Commit a05ceb1d authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #1952 from ethereum-optimism/develop

Develop -> Master PR
parents 88eb324e 8a3e400f
---
'@eth-optimism/batch-submitter': patch
---
Fix the numTxPerBatch metric
---
'@eth-optimism/message-relayer': patch
---
Removed old node.js service running script
---
'@eth-optimism/l2geth-exporter': patch
---
Initial build
---
'@eth-optimism/batch-submitter-service': patch
---
Fix metrics server
version: 2.1 version: 2.1
orbs:
gcp-gke: circleci/gcp-gke@1.3.0
commands: commands:
build-dockerfile: build-dockerfile:
parameters: parameters:
...@@ -39,6 +41,13 @@ jobs: ...@@ -39,6 +41,13 @@ jobs:
image-name: batch-submitter image-name: batch-submitter
target: batch-submitter target: batch-submitter
dockerfile: ./ops/docker/Dockerfile.packages dockerfile: ./ops/docker/Dockerfile.packages
build-go-batch-submitter:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: go-batch-submitter
dockerfile: ./ops/docker/Dockerfile.batch-submitter-service
build-deployer: build-deployer:
docker: docker:
- image: cimg/base:2021.04 - image: cimg/base:2021.04
...@@ -61,6 +70,37 @@ jobs: ...@@ -61,6 +70,37 @@ jobs:
- build-dockerfile: - build-dockerfile:
image-name: gas-oracle image-name: gas-oracle
dockerfile: ./ops/docker/Dockerfile.gas-oracle dockerfile: ./ops/docker/Dockerfile.gas-oracle
build-integration-tests:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: integration-tests
target: integration-tests
dockerfile: ./ops/docker/Dockerfile.packages
deploy-nightly:
docker:
- image: cimg/base:2021.04
steps:
- gcp-gke/install
- gcp-gke/update-kubeconfig-with-credentials:
cluster: $STACKMAN_CLUSTER
gcloud-service-key: STACKMAN_SERVICE_KEY
google-compute-region: STACKMAN_COMPUTE_REGION
google-compute-zone: STACKMAN_COMPUTE_ZONE
google-project-id: STACKMAN_PROJECT_ID
install-kubectl: yes
perform-login: yes
- run:
name: Deploy
command: |
echo "Current nightly pods:"
kubectl get pods --namespace nightly
echo "Redeploying pods:"
kubectl rollout restart statefulset nightly-sequencer --namespace nightly
kubectl rollout restart statefulset nightly-go-batch-submitter --namespace nightly
kubectl rollout restart statefulset nightly-dtl --namespace nightly
kubectl rollout restart deployment nightly-gas-oracle --namespace nightly
workflows: workflows:
...@@ -82,4 +122,18 @@ workflows: ...@@ -82,4 +122,18 @@ workflows:
- build-l2geth: - build-l2geth:
context: optimism context: optimism
- build-gas-oracle: - build-gas-oracle:
context: optimism context: optimism
\ No newline at end of file - build-integration-tests:
context: optimism
- build-go-batch-submitter:
context: optimism
- deploy-nightly:
context: optimism
requires:
- build-dtl
- build-batch-submitter
- build-go-batch-submitter
- build-deployer
- build-l2geth
- build-gas-oracle
- build-integration-tests
\ No newline at end of file
...@@ -28,6 +28,7 @@ jobs: ...@@ -28,6 +28,7 @@ jobs:
proxyd: ${{ steps.packages.outputs.proxyd }} proxyd: ${{ steps.packages.outputs.proxyd }}
rpc-proxy : ${{ steps.packages.outputs.rpc-proxy }} rpc-proxy : ${{ steps.packages.outputs.rpc-proxy }}
op-exporter : ${{ steps.packages.outputs.op-exporter }} op-exporter : ${{ steps.packages.outputs.op-exporter }}
l2geth-exporter : ${{ steps.packages.outputs.l2geth-exporter }}
steps: steps:
- name: Check out source code - name: Check out source code
...@@ -443,6 +444,43 @@ jobs: ...@@ -443,6 +444,43 @@ jobs:
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }} GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }} GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
l2geth-exporter:
name: Publish l2geth-exporter Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish
if: needs.canary-publish.outputs.l2geth-exporter != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Set build args
id: build_args
run: |
echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
echo ::set-output name=GITVERSION::$(jq -r .version ./go/l2geth-exporter/package.json)
echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.l2geth-exporter
push: true
tags: ethereumoptimism/l2geth-exporter:${{ needs.canary-publish.outputs.l2geth-exporter }}
build-args: |
GITDATE=${{ steps.build_args.outputs.GITDATE }}
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
rpc-proxy: rpc-proxy:
name: Publish rpc-proxy Version ${{ needs.canary-publish.outputs.canary-docker-tag }} name: Publish rpc-proxy Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish needs: canary-publish
......
...@@ -24,6 +24,7 @@ jobs: ...@@ -24,6 +24,7 @@ jobs:
rpc-proxy: ${{ steps.packages.outputs.rpc-proxy }} rpc-proxy: ${{ steps.packages.outputs.rpc-proxy }}
hardhat-node: ${{ steps.packages.outputs.hardhat-node }} hardhat-node: ${{ steps.packages.outputs.hardhat-node }}
op-exporter : ${{ steps.packages.outputs.op-exporter }} op-exporter : ${{ steps.packages.outputs.op-exporter }}
l2geth-exporter : ${{ steps.packages.outputs.l2geth-exporter }}
steps: steps:
- name: Checkout Repo - name: Checkout Repo
...@@ -196,6 +197,43 @@ jobs: ...@@ -196,6 +197,43 @@ jobs:
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }} GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }} GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
l2geth-exporter:
name: Publish l2geth-exporter Version ${{ needs.release.outputs.l2geth-exporter}}
needs: release
if: needs.release.outputs.l2geth-exporter != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Set build args
id: build_args
run: |
echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
echo ::set-output name=GITVERSION::$(jq -r .version ./go/l2geth-exporter/package.json)
echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.l2geth-exporter
push: true
tags: ethereumoptimism/l2geth-exporter:${{ needs.release.outputs.l2geth-exporter }},ethereumoptimism/l2geth-exporter:latest
build-args: |
GITDATE=${{ steps.build_args.outputs.GITDATE }}
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
op-exporter: op-exporter:
name: Publish op-exporter Version ${{ needs.release.outputs.op-exporter}} name: Publish op-exporter Version ${{ needs.release.outputs.op-exporter}}
needs: release needs: release
......
...@@ -131,6 +131,13 @@ jobs: ...@@ -131,6 +131,13 @@ jobs:
fail_ci_if_error: false fail_ci_if_error: false
verbose: true verbose: true
flags: message-relayer flags: message-relayer
- uses: codecov/codecov-action@v1
with:
files: ./packages/sdk/coverage.json
fail_ci_if_error: false
verbose: true
flags: sdk
lint: lint:
name: Linting name: Linting
runs-on: ubuntu-latest runs-on: ubuntu-latest
......
...@@ -293,7 +293,7 @@ func parseWalletPrivKeyAndContractAddr( ...@@ -293,7 +293,7 @@ func parseWalletPrivKeyAndContractAddr(
// NOTE: This method MUST be run as a goroutine. // NOTE: This method MUST be run as a goroutine.
func runMetricsServer(hostname string, port uint64) { func runMetricsServer(hostname string, port uint64) {
metricsPortStr := strconv.FormatUint(port, 10) metricsPortStr := strconv.FormatUint(port, 10)
metricsAddr := fmt.Sprintf("%s: %s", hostname, metricsPortStr) metricsAddr := fmt.Sprintf("%s:%s", hostname, metricsPortStr)
http.Handle("/metrics", promhttp.Handler()) http.Handle("/metrics", promhttp.Handler())
_ = http.ListenAndServe(metricsAddr, nil) _ = http.ListenAndServe(metricsAddr, nil)
......
SHELL := /bin/bash
VERSION := `git describe --abbrev=0`
GITCOMMIT := `git rev-parse HEAD`
BUILDDATE := `date +%Y-%m-%d`
BUILDUSER := `whoami`
LDFLAGSSTRING +=-X main.GitCommit=$(GITCOMMIT)
LDFLAGSSTRING +=-X main.GitDate=$(GITDATE)
LDFLAGSSTRING +=-X main.GitVersion=$(GITVERSION)
LDFLAGS :=-ldflags "$(LDFLAGSSTRING)"
all: build
build:
CGO_ENABLED=0 go build $(LDFLAGS)
clean:
rm l2geth-exporter
test:
go test -v ./...
lint:
golangci-lint run ./...
binding:
$(eval temp := $(shell mktemp))
cat ../../packages/contracts/deployments/mainnet/CanonicalTransactionChain.json \
| jq -r .bytecode > $(temp)
cat ../../packages/contracts/deployments/mainnet/CanonicalTransactionChain.json \
| jq .abi \
| abigen --pkg bindings \
--abi - \
--out bindings/CanonicalTransactionChain.go \
--type CanonicalTransactionChain \
--bin $(temp)
rm $(temp)
This diff is collapsed.
package main
import (
"github.com/prometheus/client_golang/prometheus"
)
//Define the metrics we wish to expose
var (
ctcTotalElements = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "l2geth_ctc_total_elements",
Help: "CTC GetTotalElements value."},
[]string{"state"},
)
ctcTotalElementsCallSuccess = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "l2geth_ctc_total_elements_call_success",
Help: "CTC GetTotalElements call success."},
)
)
func init() {
//Register metrics with prometheus
prometheus.MustRegister(ctcTotalElements)
prometheus.MustRegister(ctcTotalElementsCallSuccess)
}
module github.com/ethereum-optimism/optimism/go/l2geth-exporter
go 1.16
require (
github.com/ethereum/go-ethereum v1.10.8
github.com/prometheus/client_golang v1.11.0
)
This diff is collapsed.
package l1contracts
import (
"context"
"math/big"
"github.com/ethereum-optimism/optimism/go/l2geth-exporter/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
// CTC interacts with the OVM CTC contract
type CTC struct {
Address common.Address
Client *ethclient.Client
}
func (ctc *CTC) GetTotalElements(ctx context.Context) (*big.Int, error) {
contract, err := bindings.NewCanonicalTransactionChainCaller(ctc.Address, ctc.Client)
if err != nil {
return nil, err
}
totalElements, err := contract.GetTotalElements(&bind.CallOpts{
Context: ctx,
})
if err != nil {
return nil, err
}
return totalElements, nil
}
package main
import (
"context"
"math/big"
"net/http"
"os"
"time"
"github.com/ethereum-optimism/optimism/go/l2geth-exporter/l1contracts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
l1TimeoutSeconds = 5
)
func main() {
listenAddress := os.Getenv("LISTEN_ADDRESS")
if listenAddress == "" {
listenAddress = ":9100"
}
log.Root().SetHandler(log.CallerFileHandler(log.StdoutHandler))
l1Url := os.Getenv("L1_URL")
if l1Url == "" {
log.Error("L1_URL environmental variable is required")
os.Exit(1)
}
ctcAddress := os.Getenv("CTC_ADDRESS")
if ctcAddress == "" {
log.Error("CTC_ADDRESS environmental variable is required")
os.Exit(1)
}
client, err := ethclient.Dial(l1Url)
if err != nil {
log.Error("Problem connecting to L1: %s", err)
}
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html>
<head><title>L2geth Exporter</title></head>
<body>
<h1>L2geth Exporter</h1>
<p><a href="/metrics">Metrics</a></p>
</body>
</html>`))
})
go getCTCTotalElements(ctcAddress, client)
log.Info("Program starting", "listenAddress", listenAddress, "GETH_URL", l1Url, "CTC_ADDRESS", ctcAddress)
if err := http.ListenAndServe(listenAddress, nil); err != nil {
log.Error("Can't start http server", "error", err)
}
}
func getCTCTotalElements(address string, client *ethclient.Client) {
ctc := l1contracts.CTC{
Address: common.HexToAddress(address),
Client: client,
}
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(l1TimeoutSeconds))
totalElements, err := ctc.GetTotalElements(ctx)
if err != nil {
ctcTotalElementsCallSuccess.Set(0)
log.Error("Error calling GetTotalElements", "error", err)
cancel()
continue
}
ctcTotalElementsCallSuccess.Set(1)
totalElementsFloat, _ := new(big.Float).SetInt(totalElements).Float64()
ctcTotalElements.WithLabelValues(
"latest").Set(totalElementsFloat)
log.Info("ctc updated", "ctcTotalElements", totalElementsFloat)
cancel()
<-ticker.C
}
}
{
"name": "@eth-optimism/l2geth-exporter",
"version": "0.0.1",
"private": true,
"devDependencies": {}
}
...@@ -14,7 +14,7 @@ program ...@@ -14,7 +14,7 @@ program
.option('-r, --runs <n>', 'number of runs. cannot be use with -t/--time') .option('-r, --runs <n>', 'number of runs. cannot be use with -t/--time')
.option( .option(
'-t, --time <ms>', '-t, --time <ms>',
'how long to run in milliseconds. cannot be used with -r/--runs', 'how long to run in milliseconds. cannot be used with -r/--runs'
) )
.option('-c, --concurrency <n>', 'number of concurrent workers to spawn', '1') .option('-c, --concurrency <n>', 'number of concurrent workers to spawn', '1')
.option('--think-time <n>', 'how long to wait between each run', '0') .option('--think-time <n>', 'how long to wait between each run', '0')
......
...@@ -87,7 +87,10 @@ actor('Uniswap swapper', () => { ...@@ -87,7 +87,10 @@ actor('Uniswap swapper', () => {
let tx = await token.transfer(wallet.address, 1000000) let tx = await token.transfer(wallet.address, 1000000)
await tx.wait() await tx.wait()
const boundToken = token.connect(wallet) const boundToken = token.connect(wallet)
tx = await boundToken.approve(contracts.positionManager.address, 1000000000) tx = await boundToken.approve(
contracts.positionManager.address,
1000000000
)
await tx.wait() await tx.wait()
tx = await boundToken.approve(contracts.router.address, 1000000000) tx = await boundToken.approve(contracts.router.address, 1000000000)
await tx.wait() await tx.wait()
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
"scripts": { "scripts": {
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"build": "hardhat compile", "build": "hardhat compile",
"test:integration": "hardhat --network optimism test", "test:integration": "hardhat --network optimism test",
"test:actor": "IS_LIVE_NETWORK=true ts-node actor-tests/lib/runner.ts", "test:actor": "IS_LIVE_NETWORK=true ts-node actor-tests/lib/runner.ts",
......
FROM golang:1.16 as builder
ADD ./go/l2geth-exporter /app/
WORKDIR /app/
RUN make build
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/l2geth-exporter /usr/local/bin/
ENTRYPOINT ["l2geth-exporter"]
CMD ["--help"]
...@@ -11,7 +11,7 @@ RUN apt-get update -y && apt-get install -y git curl jq python3 ...@@ -11,7 +11,7 @@ RUN apt-get update -y && apt-get install -y git curl jq python3
# copy over the needed configs to run the dep installation # copy over the needed configs to run the dep installation
# note: this approach can be a bit unhandy to maintain, but it allows # note: this approach can be a bit unhandy to maintain, but it allows
# us to cache the installation steps # us to cache the installation steps
WORKDIR /optimism WORKDIR /opt/optimism
COPY *.json yarn.lock ./ COPY *.json yarn.lock ./
COPY packages/core-utils/package.json ./packages/core-utils/package.json COPY packages/core-utils/package.json ./packages/core-utils/package.json
COPY packages/common-ts/package.json ./packages/common-ts/package.json COPY packages/common-ts/package.json ./packages/common-ts/package.json
...@@ -33,30 +33,30 @@ RUN yarn build ...@@ -33,30 +33,30 @@ RUN yarn build
FROM base as deployer FROM base as deployer
WORKDIR /optimism/packages/contracts WORKDIR /opt/optimism/packages/contracts
COPY ./ops/scripts/deployer.sh . COPY ./ops/scripts/deployer.sh .
CMD ["yarn", "run", "deploy"] CMD ["yarn", "run", "deploy"]
FROM base as batch-submitter FROM base as batch-submitter
WORKDIR /optimism/packages/batch-submitter WORKDIR /opt/optimism/packages/batch-submitter
COPY ./ops/scripts/batches.sh . COPY ./ops/scripts/batches.sh .
CMD ["npm", "run", "start"] CMD ["npm", "run", "start"]
FROM base as data-transport-layer FROM base as data-transport-layer
WORKDIR /optimism/packages/data-transport-layer WORKDIR /opt/optimism/packages/data-transport-layer
COPY ./ops/scripts/dtl.sh . COPY ./ops/scripts/dtl.sh .
CMD ["node", "dist/src/services/run.js"] CMD ["node", "dist/src/services/run.js"]
FROM base as integration-tests FROM base as integration-tests
WORKDIR /optimism/integration-tests WORKDIR /opt/optimism/integration-tests
COPY ./ops/scripts/integration-tests.sh ./ COPY ./ops/scripts/integration-tests.sh ./
CMD ["yarn", "test:integration"] CMD ["yarn", "test:integration"]
FROM base as relayer FROM base as relayer
WORKDIR /optimism/packages/message-relayer WORKDIR /opt/optimism/packages/message-relayer
COPY ./ops/scripts/relayer.sh . COPY ./ops/scripts/relayer.sh .
CMD ["npm", "run", "start"] CMD ["npm", "run", "start"]
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"specs", "specs",
"go/gas-oracle", "go/gas-oracle",
"go/batch-submitter", "go/batch-submitter",
"go/l2geth-exporter",
"go/proxyd", "go/proxyd",
"go/op-exporter", "go/op-exporter",
"ops/docker/rpc-proxy", "ops/docker/rpc-proxy",
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"test": "hardhat test --show-stack-traces", "test": "hardhat test --show-stack-traces",
"test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json" "test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json"
}, },
......
...@@ -154,7 +154,6 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -154,7 +154,6 @@ export class StateBatchSubmitter extends BatchSubmitter {
startBlock: number, startBlock: number,
endBlock: number endBlock: number
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
const batchTxBuildStart = performance.now() const batchTxBuildStart = performance.now()
const batch = await this._generateStateCommitmentBatch(startBlock, endBlock) const batch = await this._generateStateCommitmentBatch(startBlock, endBlock)
......
...@@ -232,7 +232,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -232,7 +232,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
const batchTxBuildEnd = performance.now() const batchTxBuildEnd = performance.now()
this.metrics.batchTxBuildTime.set(batchTxBuildEnd - batchTxBuildStart) this.metrics.batchTxBuildTime.set(batchTxBuildEnd - batchTxBuildStart)
this.metrics.numTxPerBatch.observe(endBlock - startBlock) this.metrics.numTxPerBatch.observe(batchParams.totalElementsToAppend)
const l1tipHeight = await this.signer.provider.getBlockNumber() const l1tipHeight = await this.signer.provider.getBlockNumber()
this.logger.debug('Submitting batch.', { this.logger.debug('Submitting batch.', {
calldata: batchParams, calldata: batchParams,
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
"all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint", "all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint",
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo", "clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
"test:slither": "slither .", "test:slither": "slither .",
"pretest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat && ln -s ../../node_modules/@openzeppelin @openzeppelin && ln -s ../../node_modules/@ens @ens && ln -s ../../node_modules/hardhat hardhat", "pretest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat && ln -s ../../node_modules/@openzeppelin @openzeppelin && ln -s ../../node_modules/@ens @ens && ln -s ../../node_modules/hardhat hardhat",
"posttest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat", "posttest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat",
"lint:ts:check": "eslint .", "lint:ts:check": "eslint . --max-warnings=0",
"lint:contracts:check": "yarn solhint -f table 'contracts/**/*.sol'", "lint:contracts:check": "yarn solhint -f table 'contracts/**/*.sol'",
"lint:check": "yarn lint:contracts:check && yarn lint:ts:check", "lint:check": "yarn lint:contracts:check && yarn lint:ts:check",
"lint:ts:fix": "eslint --fix .", "lint:ts:fix": "eslint --fix .",
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo", "clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"test": "ts-mocha test/*.spec.ts", "test": "ts-mocha test/*.spec.ts",
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
"clean:db": "rimraf ./db", "clean:db": "rimraf ./db",
"lint": "yarn run lint:fix && yarn run lint:check", "lint": "yarn run lint:fix && yarn run lint:check",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"start": "ts-node ./src/services/run.ts", "start": "ts-node ./src/services/run.ts",
"start:local": "ts-node ./src/services/run.ts | pino-pretty", "start:local": "ts-node ./src/services/run.ts | pino-pretty",
"test": "hardhat --config test/config/hardhat.config.ts test", "test": "hardhat --config test/config/hardhat.config.ts test",
......
#!/usr/bin/env node
const main = require('../dist/exec/run').default
;(async () => {
await main()
})().catch((err) => {
console.log(err)
process.exit(1)
})
...@@ -11,13 +11,13 @@ ...@@ -11,13 +11,13 @@
"withdraw": "./src/exec/withdraw.ts" "withdraw": "./src/exec/withdraw.ts"
}, },
"scripts": { "scripts": {
"start": "node ./exec/run-message-relayer.js", "start": "ts-node ./src/exec/run.ts",
"build": "tsc -p ./tsconfig.build.json", "build": "tsc -p ./tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo", "clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"test": "hardhat test --show-stack-traces", "test": "hardhat test --show-stack-traces",
"test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json" "test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json"
}, },
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mocha": "^8.4.0", "mocha": "^8.4.0",
"prettier": "^2.3.1", "prettier": "^2.3.1",
"ts-node": "^10.0.0",
"typescript": "^4.3.5" "typescript": "^4.3.5"
} }
} }
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo", "clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo",
"lint": "yarn run lint:fix && yarn run lint:check", "lint": "yarn run lint:fix && yarn run lint:check",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"test:surgery": "ts-mocha --timeout 50000000 test/*", "test:surgery": "ts-mocha --timeout 50000000 test/*",
"start": "ts-node ./scripts/surgery.ts" "start": "ts-node ./scripts/surgery.ts"
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo", "clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo",
"lint": "yarn run lint:fix && yarn run lint:check", "lint": "yarn run lint:fix && yarn run lint:check",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"test": "ts-mocha test/*.spec.ts", "test": "ts-mocha test/*.spec.ts",
......
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
The `@eth-optimism/sdk` package provides a set of tools for interacting with Optimistic Ethereum. The `@eth-optimism/sdk` package provides a set of tools for interacting with Optimistic Ethereum.
## NOTICE
WARNING: This package is currently under construction.
You can definitely try to use it, but you probably won't have a good time.
Lots of pieces are missing.
We will announce the 1.0.0 release on Discord and on Twitter once it's ready, keep an eye out!
## Installation ## Installation
``` ```
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo", "clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"test": "hardhat test", "test": "hardhat test",
......
...@@ -4,7 +4,7 @@ import { ...@@ -4,7 +4,7 @@ import {
BlockTag, BlockTag,
TransactionReceipt, TransactionReceipt,
} from '@ethersproject/abstract-provider' } from '@ethersproject/abstract-provider'
import { BigNumber } from 'ethers' import { ethers, BigNumber, Event } from 'ethers'
import { import {
ICrossChainProvider, ICrossChainProvider,
OEContracts, OEContracts,
...@@ -19,6 +19,8 @@ import { ...@@ -19,6 +19,8 @@ import {
MessageStatus, MessageStatus,
TokenBridgeMessage, TokenBridgeMessage,
MessageReceipt, MessageReceipt,
CustomBridges,
CustomBridgesLike,
} from './interfaces' } from './interfaces'
import { import {
toProvider, toProvider,
...@@ -26,6 +28,7 @@ import { ...@@ -26,6 +28,7 @@ import {
toTransactionHash, toTransactionHash,
DeepPartial, DeepPartial,
getAllOEContracts, getAllOEContracts,
getCustomBridges,
} from './utils' } from './utils'
export class CrossChainProvider implements ICrossChainProvider { export class CrossChainProvider implements ICrossChainProvider {
...@@ -33,6 +36,7 @@ export class CrossChainProvider implements ICrossChainProvider { ...@@ -33,6 +36,7 @@ export class CrossChainProvider implements ICrossChainProvider {
public l2Provider: Provider public l2Provider: Provider
public l1ChainId: number public l1ChainId: number
public contracts: OEContracts public contracts: OEContracts
public bridges: CustomBridges
/** /**
* Creates a new CrossChainProvider instance. * Creates a new CrossChainProvider instance.
...@@ -48,6 +52,7 @@ export class CrossChainProvider implements ICrossChainProvider { ...@@ -48,6 +52,7 @@ export class CrossChainProvider implements ICrossChainProvider {
l2Provider: ProviderLike l2Provider: ProviderLike
l1ChainId: NumberLike l1ChainId: NumberLike
contracts?: DeepPartial<OEContractsLike> contracts?: DeepPartial<OEContractsLike>
bridges?: Partial<CustomBridgesLike>
}) { }) {
this.l1Provider = toProvider(opts.l1Provider) this.l1Provider = toProvider(opts.l1Provider)
this.l2Provider = toProvider(opts.l2Provider) this.l2Provider = toProvider(opts.l2Provider)
...@@ -57,6 +62,11 @@ export class CrossChainProvider implements ICrossChainProvider { ...@@ -57,6 +62,11 @@ export class CrossChainProvider implements ICrossChainProvider {
l2SignerOrProvider: this.l2Provider, l2SignerOrProvider: this.l2Provider,
overrides: opts.contracts, overrides: opts.contracts,
}) })
this.bridges = getCustomBridges(this.l1ChainId, {
l1SignerOrProvider: this.l1Provider,
l2SignerOrProvider: this.l2Provider,
overrides: opts.bridges,
})
} }
public async getMessagesByTransaction( public async getMessagesByTransaction(
...@@ -115,6 +125,9 @@ export class CrossChainProvider implements ICrossChainProvider { ...@@ -115,6 +125,9 @@ export class CrossChainProvider implements ICrossChainProvider {
sender: parsed.args.sender, sender: parsed.args.sender,
message: parsed.args.message, message: parsed.args.message,
messageNonce: parsed.args.messageNonce, messageNonce: parsed.args.messageNonce,
logIndex: log.logIndex,
blockNumber: log.blockNumber,
transactionHash: log.transactionHash,
} }
}) })
} }
...@@ -132,13 +145,137 @@ export class CrossChainProvider implements ICrossChainProvider { ...@@ -132,13 +145,137 @@ export class CrossChainProvider implements ICrossChainProvider {
public async getTokenBridgeMessagesByAddress( public async getTokenBridgeMessagesByAddress(
address: AddressLike, address: AddressLike,
opts?: { opts: {
direction?: MessageDirection direction?: MessageDirection
fromBlock?: BlockTag fromBlock?: BlockTag
toBlock?: BlockTag toBlock?: BlockTag
} = {}
): Promise<TokenBridgeMessage[]> {
const parseTokenEvent = (
event: Event,
dir: MessageDirection
): TokenBridgeMessage => {
return {
direction: dir,
from: event.args._from,
to: event.args._to,
l1Token: event.args._l1Token || ethers.constants.AddressZero,
l2Token: event.args._l2Token || this.contracts.l2.OVM_ETH.address,
amount: event.args._amount,
data: event.args._data,
logIndex: event.logIndex,
blockNumber: event.blockNumber,
transactionHash: event.transactionHash,
}
}
// Make sure you provide a direction if you specify a block range. Block ranges don't make
// sense to use on both chains at the same time.
if (opts.fromBlock !== undefined || opts.toBlock !== undefined) {
if (opts.direction === undefined) {
throw new Error('direction must be specified when using a block range')
}
}
// Keep track of all of the messages triggered by the address in question.
// We'll add messages to this list as we find them, based on the direction that the user has
// requested we find messages in. If the user hasn't requested a direction, we find messages in
// both directions.
const messages: TokenBridgeMessage[] = []
// First find all messages in the L1 to L2 direction.
if (
opts.direction === undefined ||
opts.direction === MessageDirection.L1_TO_L2
) {
// Find all ETH deposit events and push them into the messages array.
const ethDepositEvents =
await this.contracts.l1.L1StandardBridge.queryFilter(
this.contracts.l1.L1StandardBridge.filters.ETHDepositInitiated(
address
),
opts.fromBlock,
opts.toBlock
)
for (const event of ethDepositEvents) {
messages.push(parseTokenEvent(event, MessageDirection.L1_TO_L2))
}
// Send an event query for every L1 bridge, this will return an array of arrays.
const erc20DepositEventSets = await Promise.all(
[
this.contracts.l1.L1StandardBridge,
...Object.values(this.bridges.l1),
].map(async (bridge) => {
return bridge.queryFilter(
bridge.filters.ERC20DepositInitiated(undefined, undefined, address),
opts.fromBlock,
opts.toBlock
)
})
)
for (const erc20DepositEvents of erc20DepositEventSets) {
for (const event of erc20DepositEvents) {
messages.push(parseTokenEvent(event, MessageDirection.L1_TO_L2))
}
}
}
// Next find all messages in the L2 to L1 direction.
if (
opts.direction === undefined ||
opts.direction === MessageDirection.L2_TO_L1
) {
// ETH withdrawals and ERC20 withdrawals are the same event on L2.
// Send an event query for every L2 bridge, this will return an array of arrays.
const withdrawalEventSets = await Promise.all(
[
this.contracts.l2.L2StandardBridge,
...Object.values(this.bridges.l2),
].map(async (bridge) => {
return bridge.queryFilter(
bridge.filters.WithdrawalInitiated(undefined, undefined, address),
opts.fromBlock,
opts.toBlock
)
})
)
for (const withdrawalEvents of withdrawalEventSets) {
for (const event of withdrawalEvents) {
messages.push(parseTokenEvent(event, MessageDirection.L2_TO_L1))
}
}
} }
return messages
}
public async getDepositsByAddress(
address: AddressLike,
opts: {
fromBlock?: BlockTag
toBlock?: BlockTag
} = {}
): Promise<TokenBridgeMessage[]> { ): Promise<TokenBridgeMessage[]> {
throw new Error('Not implemented') return this.getTokenBridgeMessagesByAddress(address, {
...opts,
direction: MessageDirection.L1_TO_L2,
})
}
public async getWithdrawalsByAddress(
address: AddressLike,
opts: {
fromBlock?: BlockTag
toBlock?: BlockTag
} = {}
): Promise<TokenBridgeMessage[]> {
return this.getTokenBridgeMessagesByAddress(address, {
...opts,
direction: MessageDirection.L2_TO_L1,
})
} }
public async getMessageStatus(message: MessageLike): Promise<MessageStatus> { public async getMessageStatus(message: MessageLike): Promise<MessageStatus> {
......
...@@ -11,6 +11,7 @@ import { ...@@ -11,6 +11,7 @@ import {
TokenBridgeMessage, TokenBridgeMessage,
OEContracts, OEContracts,
MessageReceipt, MessageReceipt,
CustomBridges,
} from './types' } from './types'
/** /**
...@@ -38,6 +39,11 @@ export interface ICrossChainProvider { ...@@ -38,6 +39,11 @@ export interface ICrossChainProvider {
*/ */
contracts: OEContracts contracts: OEContracts
/**
* List of custom bridges for the given network.
*/
bridges: CustomBridges
/** /**
* Retrieves all cross chain messages sent within a given transaction. * Retrieves all cross chain messages sent within a given transaction.
* *
...@@ -80,7 +86,7 @@ export interface ICrossChainProvider { ...@@ -80,7 +86,7 @@ export interface ICrossChainProvider {
/** /**
* Finds all cross chain messages that correspond to token deposits or withdrawals sent by a * Finds all cross chain messages that correspond to token deposits or withdrawals sent by a
* particular address. Useful for finding deposits/withdrawals because the sender of the message * particular address. Useful for finding deposits/withdrawals because the sender of the message
* will appear to be the StandardBridge contract and not the actual end user. Returns * will appear to be the StandardBridge contract and not the actual end user.
* *
* @param address Address to search for messages from. * @param address Address to search for messages from.
* @param opts Options object. * @param opts Options object.
...@@ -101,6 +107,44 @@ export interface ICrossChainProvider { ...@@ -101,6 +107,44 @@ export interface ICrossChainProvider {
} }
): Promise<TokenBridgeMessage[]> ): Promise<TokenBridgeMessage[]>
/**
* Alias for getTokenBridgeMessagesByAddress with a drection of L1_TO_L2.
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All deposit token bridge messages sent by the given address.
*/
getDepositsByAddress(
address: AddressLike,
opts?: {
fromBlock?: BlockTag
toBlock?: BlockTag
}
): Promise<TokenBridgeMessage[]>
/**
* Alias for getTokenBridgeMessagesByAddress with a drection of L2_TO_L1.
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All withdrawal token bridge messages sent by the given address.
*/
getWithdrawalsByAddress(
address: AddressLike,
opts?: {
fromBlock?: BlockTag
toBlock?: BlockTag
}
): Promise<TokenBridgeMessage[]>
/** /**
* Retrieves the status of a particular message as an enum. * Retrieves the status of a particular message as an enum.
* *
......
...@@ -67,6 +67,30 @@ export interface OEContractsLike { ...@@ -67,6 +67,30 @@ export interface OEContractsLike {
l2: OEL2ContractsLike l2: OEL2ContractsLike
} }
/**
* Represents list of custom bridges.
*/
export interface CustomBridges {
l1: {
[name: string]: Contract
}
l2: {
[name: string]: Contract
}
}
/**
* Something that looks like the list of custom bridges.
*/
export interface CustomBridgesLike {
l1: {
[K in keyof CustomBridges['l1']]: AddressLike
}
l2: {
[K in keyof CustomBridges['l2']]: AddressLike
}
}
/** /**
* Enum describing the status of a message. * Enum describing the status of a message.
*/ */
...@@ -123,11 +147,9 @@ export interface CrossChainMessageRequest { ...@@ -123,11 +147,9 @@ export interface CrossChainMessageRequest {
} }
/** /**
* Describes a message that is sent between L1 and L2. Direction determines where the message was * Core components of a cross chain message.
* sent from and where it's being sent to.
*/ */
export interface CrossChainMessage { export interface CoreCrossChainMessage {
direction: MessageDirection
sender: string sender: string
target: string target: string
message: string message: string
...@@ -135,12 +157,15 @@ export interface CrossChainMessage { ...@@ -135,12 +157,15 @@ export interface CrossChainMessage {
} }
/** /**
* Convenience type for when you don't care which direction the message is going in. * Describes a message that is sent between L1 and L2. Direction determines where the message was
* sent from and where it's being sent to.
*/ */
export type DirectionlessCrossChainMessage = Omit< export interface CrossChainMessage extends CoreCrossChainMessage {
CrossChainMessage, direction: MessageDirection
'direction' logIndex: number
> blockNumber: number
transactionHash: string
}
/** /**
* Describes a token withdrawal or deposit, along with the underlying raw cross chain message * Describes a token withdrawal or deposit, along with the underlying raw cross chain message
...@@ -153,7 +178,10 @@ export interface TokenBridgeMessage { ...@@ -153,7 +178,10 @@ export interface TokenBridgeMessage {
l1Token: string l1Token: string
l2Token: string l2Token: string
amount: BigNumber amount: BigNumber
raw: CrossChainMessage data: string
logIndex: number
blockNumber: number
transactionHash: string
} }
/** /**
......
...@@ -7,6 +7,8 @@ import { ...@@ -7,6 +7,8 @@ import {
OEContractsLike, OEContractsLike,
OEL2ContractsLike, OEL2ContractsLike,
AddressLike, AddressLike,
CustomBridges,
CustomBridgesLike,
} from '../interfaces' } from '../interfaces'
import { toAddress } from './coercion' import { toAddress } from './coercion'
import { DeepPartial } from './type-utils' import { DeepPartial } from './type-utils'
...@@ -36,6 +38,42 @@ const NAME_REMAPPING = { ...@@ -36,6 +38,42 @@ const NAME_REMAPPING = {
WETH: 'WETH9', WETH: 'WETH9',
} }
/**
* Mapping of L1 chain IDs to the list of custom bridge addresses for each chain.
*/
export const CUSTOM_BRIDGE_ADDRESSES: {
[l1ChainId: number]: CustomBridgesLike
} = {
// TODO: Maybe we can pull these automatically from the token list?
// Alternatively, check against the token list in CI.
1: {
l1: {
SNX: '0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068',
DAI: '0x10E6593CDda8c58a1d0f14C5164B376352a55f2F',
BitBTC: '0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128',
},
l2: {
SNX: '0x3f87Ff1de58128eF8FCb4c807eFD776E1aC72E51',
DAI: '0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65',
BitBTC: '0x158F513096923fF2d3aab2BcF4478536de6725e2',
},
},
42: {
l1: {
SNX: '0xD134Db47DDF5A6feB245452af17cCAf92ee53D3c',
DAI: '0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3',
BitBTC: '0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746',
USX: '0x40E862341b2416345F02c41Ac70df08525150dC7',
},
l2: {
SNX: '0x5C3f51CEd0C2F6157e2be67c029264D6C44bfe42',
DAI: '0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65',
BitBTC: '0x0CFb46528a7002a7D8877a5F7a69b9AaF1A9058e',
USX: '0xB4d37826b14Cd3CB7257A2A5094507d701fe715f',
},
},
}
/** /**
* Mapping of L1 chain IDs to the appropriate contract addresses for the OE deployments to the * Mapping of L1 chain IDs to the appropriate contract addresses for the OE deployments to the
* given network. Simplifies the process of getting the correct contract addresses for a given * given network. Simplifies the process of getting the correct contract addresses for a given
...@@ -190,3 +228,59 @@ export const getAllOEContracts = ( ...@@ -190,3 +228,59 @@ export const getAllOEContracts = (
l2: l2Contracts, l2: l2Contracts,
} }
} }
/**
* Gets a series of custom bridges for the given L1 chain ID.
*
* @param l1ChainId L1 chain ID for the L1 network where the custom bridges are deployed.
* @param opts Additional options for connecting to the custom bridges.
* @param opts.l1SignerOrProvider Signer or provider to connect to the L1 contracts.
* @param opts.l2SignerOrProvider Signer or provider to connect to the L2 contracts.
* @param opts.overrides Custom contract address overrides for L1 or L2 contracts.
* @returns An object containing ethers.Contract objects connected to the appropriate addresses on
* both L1 and L2.
*/
export const getCustomBridges = (
l1ChainId: number,
opts: {
l1SignerOrProvider?: ethers.Signer | ethers.providers.Provider
l2SignerOrProvider?: ethers.Signer | ethers.providers.Provider
overrides?: Partial<CustomBridgesLike>
} = {}
): CustomBridges => {
const addresses = CUSTOM_BRIDGE_ADDRESSES[l1ChainId] || {
l1: {},
l2: {},
}
for (const [contractName, contractAddress] of Object.entries(
opts.overrides?.l1 || {}
)) {
addresses.l1[contractName] = contractAddress
}
for (const [contractName, contractAddress] of Object.entries(
opts.overrides?.l2 || {}
)) {
addresses.l2[contractName] = contractAddress
}
const bridges = {
l1: {},
l2: {},
}
for (const [contractName, contractAddress] of Object.entries(addresses.l1)) {
bridges.l1[contractName] = new Contract(
toAddress(contractAddress),
getContractInterface('IL1ERC20Bridge'),
opts.l1SignerOrProvider
)
}
for (const [contractName, contractAddress] of Object.entries(addresses.l2)) {
bridges.l2[contractName] = new Contract(
toAddress(contractAddress),
getContractInterface('IL2ERC20Bridge'),
opts.l2SignerOrProvider
)
}
return bridges
}
import { getContractInterface } from '@eth-optimism/contracts' import { getContractInterface } from '@eth-optimism/contracts'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { DirectionlessCrossChainMessage } from '../interfaces' import { CoreCrossChainMessage } from '../interfaces'
/** /**
* Returns the canonical encoding of a cross chain message. This encoding is used in various * Returns the canonical encoding of a cross chain message. This encoding is used in various
...@@ -10,7 +10,7 @@ import { DirectionlessCrossChainMessage } from '../interfaces' ...@@ -10,7 +10,7 @@ import { DirectionlessCrossChainMessage } from '../interfaces'
* @returns Canonical encoding of the message. * @returns Canonical encoding of the message.
*/ */
export const encodeCrossChainMessage = ( export const encodeCrossChainMessage = (
message: DirectionlessCrossChainMessage message: CoreCrossChainMessage
): string => { ): string => {
return getContractInterface('L2CrossDomainMessenger').encodeFunctionData( return getContractInterface('L2CrossDomainMessenger').encodeFunctionData(
'relayMessage', 'relayMessage',
...@@ -27,7 +27,7 @@ export const encodeCrossChainMessage = ( ...@@ -27,7 +27,7 @@ export const encodeCrossChainMessage = (
* @returns Canonical hash of the message. * @returns Canonical hash of the message.
*/ */
export const hashCrossChainMessage = ( export const hashCrossChainMessage = (
message: DirectionlessCrossChainMessage message: CoreCrossChainMessage
): string => { ): string => {
return ethers.utils.solidityKeccak256( return ethers.utils.solidityKeccak256(
['bytes'], ['bytes'],
......
pragma solidity ^0.8.9;
import { MockMessenger } from "./MockMessenger.sol";
contract MockBridge {
event ERC20DepositInitiated(
address indexed _l1Token,
address indexed _l2Token,
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);
event ERC20WithdrawalFinalized(
address indexed _l1Token,
address indexed _l2Token,
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);
event WithdrawalInitiated(
address indexed _l1Token,
address indexed _l2Token,
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);
event DepositFinalized(
address indexed _l1Token,
address indexed _l2Token,
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);
event DepositFailed(
address indexed _l1Token,
address indexed _l2Token,
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);
struct TokenEventStruct {
address l1Token;
address l2Token;
address from;
address to;
uint256 amount;
bytes data;
}
MockMessenger public messenger;
constructor(MockMessenger _messenger) {
messenger = _messenger;
}
function emitERC20DepositInitiated(
TokenEventStruct memory _params
) public {
emit ERC20DepositInitiated(_params.l1Token, _params.l2Token, _params.from, _params.to, _params.amount, _params.data);
messenger.triggerSentMessageEvent(
MockMessenger.SentMessageEventParams(
address(0),
address(0),
hex"1234",
1234,
12345678
)
);
}
function emitERC20WithdrawalFinalized(
TokenEventStruct memory _params
) public {
emit ERC20WithdrawalFinalized(_params.l1Token, _params.l2Token, _params.from, _params.to, _params.amount, _params.data);
}
function emitWithdrawalInitiated(
TokenEventStruct memory _params
) public {
emit WithdrawalInitiated(_params.l1Token, _params.l2Token, _params.from, _params.to, _params.amount, _params.data);
messenger.triggerSentMessageEvent(
MockMessenger.SentMessageEventParams(
address(0),
address(0),
hex"1234",
1234,
12345678
)
);
}
function emitDepositFinalized(
TokenEventStruct memory _params
) public {
emit DepositFinalized(_params.l1Token, _params.l2Token, _params.from, _params.to, _params.amount, _params.data);
}
function emitDepositFailed(
TokenEventStruct memory _params
) public {
emit DepositFailed(_params.l1Token, _params.l2Token, _params.from, _params.to, _params.amount, _params.data);
}
}
...@@ -28,17 +28,23 @@ contract MockMessenger is ICrossDomainMessenger { ...@@ -28,17 +28,23 @@ contract MockMessenger is ICrossDomainMessenger {
return; return;
} }
function triggerSentMessageEvent(
SentMessageEventParams memory _params
) public {
emit SentMessage(
_params.target,
_params.sender,
_params.message,
_params.messageNonce,
_params.gasLimit
);
}
function triggerSentMessageEvents( function triggerSentMessageEvents(
SentMessageEventParams[] memory _params SentMessageEventParams[] memory _params
) public { ) public {
for (uint256 i = 0; i < _params.length; i++) { for (uint256 i = 0; i < _params.length; i++) {
emit SentMessage( triggerSentMessageEvent(_params[i]);
_params[i].target,
_params[i].sender,
_params[i].message,
_params[i].messageNonce,
_params[i].gasLimit
);
} }
} }
......
...@@ -3,8 +3,7 @@ import { Contract, Signer } from 'ethers' ...@@ -3,8 +3,7 @@ import { Contract, Signer } from 'ethers'
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import { getContractFactory } from '@eth-optimism/contracts' import { getContractFactory } from '@eth-optimism/contracts'
import { import {
CrossChainMessage, CoreCrossChainMessage,
MessageDirection,
encodeCrossChainMessage, encodeCrossChainMessage,
hashCrossChainMessage, hashCrossChainMessage,
} from '../../src' } from '../../src'
...@@ -25,8 +24,7 @@ describe('message encoding utils', () => { ...@@ -25,8 +24,7 @@ describe('message encoding utils', () => {
}) })
it('should properly encode a message', async () => { it('should properly encode a message', async () => {
const message: CrossChainMessage = { const message: CoreCrossChainMessage = {
direction: MessageDirection.L1_TO_L2,
target: '0x' + '11'.repeat(20), target: '0x' + '11'.repeat(20),
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '1234'.repeat(32), message: '0x' + '1234'.repeat(32),
...@@ -53,8 +51,7 @@ describe('message encoding utils', () => { ...@@ -53,8 +51,7 @@ describe('message encoding utils', () => {
}) })
it('should properly hash a message', async () => { it('should properly hash a message', async () => {
const message: CrossChainMessage = { const message: CoreCrossChainMessage = {
direction: MessageDirection.L1_TO_L2,
target: '0x' + '11'.repeat(20), target: '0x' + '11'.repeat(20),
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '1234'.repeat(32), message: '0x' + '1234'.repeat(32),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment