mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-12 07:28:08 -05:00
Compare commits
40 Commits
alpha-v1.1
...
alpha-v2.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c752e3473d | ||
|
|
cb6a609366 | ||
|
|
87cc80e6e3 | ||
|
|
77f1fa7ca7 | ||
|
|
c2445176ec | ||
|
|
3a1cb6a34b | ||
|
|
0a404fe10f | ||
|
|
73b6bd176e | ||
|
|
56b489e8d4 | ||
|
|
6807c20267 | ||
|
|
7b0546e1e5 | ||
|
|
e1cabce03d | ||
|
|
e034b6e436 | ||
|
|
d2597e0926 | ||
|
|
525e4c6e1d | ||
|
|
2f2072fd4e | ||
|
|
ebe557acf2 | ||
|
|
a98892d65c | ||
|
|
4025a26875 | ||
|
|
3e64f32b85 | ||
|
|
31c6d965a7 | ||
|
|
06a1b47ffa | ||
|
|
1d2886cbb2 | ||
|
|
ba87e8ea25 | ||
|
|
0f98d0c5e5 | ||
|
|
4df23100d1 | ||
|
|
8f807c8ee0 | ||
|
|
a62ff312a6 | ||
|
|
d3c84dd013 | ||
|
|
b922f59686 | ||
|
|
ee4c00eb6b | ||
|
|
357066e9c8 | ||
|
|
e1ec4d1f05 | ||
|
|
551e2ba784 | ||
|
|
58315eadce | ||
|
|
44e27b1110 | ||
|
|
ddad2552bb | ||
|
|
f61d917b92 | ||
|
|
0eaf220382 | ||
|
|
7f6c219d56 |
2
.github/workflows/bridge.yml
vendored
2
.github/workflows/bridge.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'bridge/**'
|
||||
@@ -13,6 +14,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'bridge/**'
|
||||
|
||||
2
.github/workflows/common.yml
vendored
2
.github/workflows/common.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'common/**'
|
||||
@@ -13,6 +14,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'common/**'
|
||||
|
||||
33
.github/workflows/contracts.yaml
vendored
33
.github/workflows/contracts.yaml
vendored
@@ -2,24 +2,10 @@ name: Contracts
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- prod
|
||||
- release/*
|
||||
- staging
|
||||
- alpha
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- '.github/workflows/contracts.yaml'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- prod
|
||||
- release/*
|
||||
- staging
|
||||
- alpha
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- '.github/workflows/contracts.yaml'
|
||||
@@ -42,6 +28,9 @@ jobs:
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly
|
||||
|
||||
- name: Setup LCOV
|
||||
uses: hrishikesh-kadam/setup-lcov@v1
|
||||
|
||||
- name: Install Node.js 14
|
||||
uses: actions/setup-node@v2
|
||||
@@ -78,6 +67,22 @@ jobs:
|
||||
- name: Run foundry tests
|
||||
run: forge test -vvv
|
||||
|
||||
- name: Run foundry coverage
|
||||
run : forge coverage --report lcov
|
||||
|
||||
- name : Prune coverage
|
||||
run : lcov --remove ./lcov.info -o ./lcov.info.pruned 'src/mocks/*' 'src/test/*' 'scripts/*' 'node_modules/*' 'lib/*'
|
||||
|
||||
- name: Report code coverage
|
||||
uses: zgosalvez/github-actions-report-lcov@v3
|
||||
with:
|
||||
coverage-files: contracts/lcov.info.pruned
|
||||
minimum-coverage: 0
|
||||
artifact-name: code-coverage-report
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
working-directory: contracts
|
||||
update-comment: true
|
||||
|
||||
hardhat:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
2
.github/workflows/coordinator.yml
vendored
2
.github/workflows/coordinator.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'coordinator/**'
|
||||
@@ -13,6 +14,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'coordinator/**'
|
||||
|
||||
2
.github/workflows/database.yml
vendored
2
.github/workflows/database.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'database/**'
|
||||
@@ -13,6 +14,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'database/**'
|
||||
|
||||
2
.github/workflows/roller.yml
vendored
2
.github/workflows/roller.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'roller/**'
|
||||
@@ -13,6 +14,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
- develop
|
||||
- alpha
|
||||
paths:
|
||||
- 'roller/**'
|
||||
|
||||
16
Jenkinsfile
vendored
16
Jenkinsfile
vendored
@@ -63,42 +63,42 @@ pipeline {
|
||||
parallel{
|
||||
stage('Test bridge package') {
|
||||
steps {
|
||||
sh 'go test -v -race -coverprofile=coverage.bridge.txt -covermode=atomic -p 1 scroll-tech/bridge/...'
|
||||
sh 'go test -v -coverprofile=coverage.bridge.txt -covermode=atomic -p 1 scroll-tech/bridge/...'
|
||||
}
|
||||
}
|
||||
stage('Test common package') {
|
||||
steps {
|
||||
sh 'go test -v -race -coverprofile=coverage.common.txt -covermode=atomic -p 1 scroll-tech/common/...'
|
||||
sh 'go test -v -coverprofile=coverage.common.txt -covermode=atomic -p 1 scroll-tech/common/...'
|
||||
}
|
||||
}
|
||||
stage('Test coordinator package') {
|
||||
steps {
|
||||
sh 'go test -v -race -coverprofile=coverage.coordinator.txt -covermode=atomic -p 1 scroll-tech/coordinator/...'
|
||||
sh 'go test -v -coverprofile=coverage.coordinator.txt -covermode=atomic -p 1 scroll-tech/coordinator/...'
|
||||
}
|
||||
}
|
||||
stage('Test database package') {
|
||||
steps {
|
||||
sh 'go test -v -race -coverprofile=coverage.db.txt -covermode=atomic -p 1 scroll-tech/database/...'
|
||||
sh 'go test -v -coverprofile=coverage.db.txt -covermode=atomic -p 1 scroll-tech/database/...'
|
||||
}
|
||||
}
|
||||
stage('Integration test') {
|
||||
steps {
|
||||
sh 'go test -v -race -tags="mock_prover mock_verifier" -coverprofile=coverage.integration.txt -covermode=atomic -p 1 scroll-tech/integration-test/...'
|
||||
sh 'go test -v -tags="mock_prover mock_verifier" -coverprofile=coverage.integration.txt -covermode=atomic -p 1 scroll-tech/integration-test/...'
|
||||
}
|
||||
}
|
||||
stage('Race test bridge package') {
|
||||
steps {
|
||||
sh "cd bridge && go test -v -race -coverprofile=coverage.txt -covermode=atomic \$(go list ./... | grep -v 'database\\|common\\|l1\\|l2\\|coordinator')"
|
||||
sh 'go test -v -race -coverprofile=coverage.txt -covermode=atomic scroll-tech/bridge/...'
|
||||
}
|
||||
}
|
||||
stage('Race test coordinator package') {
|
||||
steps {
|
||||
sh "cd coordinator && go test -v -race -coverprofile=coverage.txt -covermode=atomic \$(go list ./... | grep -v 'database\\|common\\|l1\\|l2\\|coordinator')"
|
||||
sh 'go test -v -race -coverprofile=coverage.txt -covermode=atomic scroll-tech/coordinator/...'
|
||||
}
|
||||
}
|
||||
stage('Race test database package') {
|
||||
steps {
|
||||
sh "cd database && go test -v -race -coverprofile=coverage.txt -covermode=atomic \$(go list ./... | grep -v 'database\\|common\\|l1\\|l2\\|coordinator')"
|
||||
sh 'go test -v -race -coverprofile=coverage.txt -covermode=atomic scroll-tech/database/...'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
Makefile
10
Makefile
@@ -16,11 +16,11 @@ lint: ## The code's format and security checks.
|
||||
|
||||
update: ## update dependencies
|
||||
go work sync
|
||||
cd $(PWD)/bridge/ && go get -u github.com/scroll-tech/go-ethereum@staging && go mod tidy
|
||||
cd $(PWD)/common/ && go get -u github.com/scroll-tech/go-ethereum@staging && go mod tidy
|
||||
cd $(PWD)/coordinator/ && go get -u github.com/scroll-tech/go-ethereum@staging && go mod tidy
|
||||
cd $(PWD)/database/ && go get -u github.com/scroll-tech/go-ethereum@staging && go mod tidy
|
||||
cd $(PWD)/roller/ && go get -u github.com/scroll-tech/go-ethereum@staging && go mod tidy
|
||||
cd $(PWD)/bridge/ && go get -u github.com/scroll-tech/go-ethereum@scroll && go mod tidy
|
||||
cd $(PWD)/common/ && go get -u github.com/scroll-tech/go-ethereum@scroll && go mod tidy
|
||||
cd $(PWD)/coordinator/ && go get -u github.com/scroll-tech/go-ethereum@scroll && go mod tidy
|
||||
cd $(PWD)/database/ && go get -u github.com/scroll-tech/go-ethereum@scroll && go mod tidy
|
||||
cd $(PWD)/roller/ && go get -u github.com/scroll-tech/go-ethereum@scroll && go mod tidy
|
||||
goimports -local $(PWD)/bridge/ -w .
|
||||
goimports -local $(PWD)/common/ -w .
|
||||
goimports -local $(PWD)/coordinator/ -w .
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
)
|
||||
|
||||
func TestRunBridge(t *testing.T) {
|
||||
bridge := cmd.NewCmd(t, "bridge-test", "--version")
|
||||
bridge := cmd.NewCmd("bridge-test", "--version")
|
||||
defer bridge.WaitExit()
|
||||
|
||||
// wait result
|
||||
bridge.ExpectWithTimeout(true, time.Second*3, fmt.Sprintf("bridge version %s", version.Version))
|
||||
bridge.ExpectWithTimeout(t, true, time.Second*3, fmt.Sprintf("bridge version %s", version.Version))
|
||||
bridge.RunApp(nil)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"sender_config": {
|
||||
"endpoint": "/var/lib/jenkins/workspace/SequencerPipeline/MyPrivateNetwork/geth.ipc",
|
||||
"check_pending_time": 2,
|
||||
"check_balance_time": 100,
|
||||
"escalate_blocks": 100,
|
||||
"confirmations": "0x1",
|
||||
"escalate_multiple_num": 11,
|
||||
@@ -45,6 +46,7 @@
|
||||
"sender_config": {
|
||||
"endpoint": "https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161",
|
||||
"check_pending_time": 10,
|
||||
"check_balance_time": 100,
|
||||
"escalate_blocks": 100,
|
||||
"confirmations": "0x6",
|
||||
"escalate_multiple_num": 11,
|
||||
|
||||
@@ -31,6 +31,8 @@ type SenderConfig struct {
|
||||
TxType string `json:"tx_type"`
|
||||
// The min balance set for check and set balance for sender's accounts.
|
||||
MinBalance *big.Int `json:"min_balance,omitempty"`
|
||||
// The interval (in seconds) to check balance and top up sender's accounts
|
||||
CheckBalanceTime uint64 `json:"check_balance_time"`
|
||||
}
|
||||
|
||||
// RelayerConfig loads relayer configuration items.
|
||||
@@ -49,6 +51,8 @@ type RelayerConfig struct {
|
||||
GasOracleConfig *GasOracleConfig `json:"gas_oracle_config"`
|
||||
// The interval in which we send finalize batch transactions.
|
||||
FinalizeBatchIntervalSec uint64 `json:"finalize_batch_interval_sec"`
|
||||
// MessageRelayMinGasLimit to avoid OutOfGas error
|
||||
MessageRelayMinGasLimit uint64 `json:"message_relay_min_gas_limit,omitempty"`
|
||||
// The private key of the relayer
|
||||
MessageSenderPrivateKeys []*ecdsa.PrivateKey `json:"-"`
|
||||
GasOracleSenderPrivateKeys []*ecdsa.PrivateKey `json:"-"`
|
||||
|
||||
@@ -4,8 +4,8 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230220082843-ec9254b0b1c6
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230321020420-127af384ed04
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa
|
||||
golang.org/x/sync v0.1.0
|
||||
modernc.org/mathutil v1.4.1
|
||||
@@ -16,26 +16,27 @@ require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||
github.com/ethereum/go-ethereum v1.11.1 // indirect
|
||||
github.com/ethereum/go-ethereum v1.11.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/holiman/uint256 v1.2.0 // indirect
|
||||
github.com/iden3/go-iden3-crypto v0.0.13 // indirect
|
||||
github.com/iden3/go-iden3-crypto v0.0.14 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/scroll-tech/zktrie v0.5.0 // indirect
|
||||
github.com/scroll-tech/zktrie v0.5.2 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.6.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
561
bridge/go.sum
561
bridge/go.sum
@@ -1,63 +1,5 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
|
||||
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
|
||||
github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o=
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM=
|
||||
github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
@@ -67,598 +9,127 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
||||
github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=
|
||||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI=
|
||||
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
||||
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
|
||||
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
|
||||
github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=
|
||||
github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
|
||||
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ethereum/go-ethereum v1.10.13/go.mod h1:W3yfrFyL9C1pHcwY5hmRHVDaorTiQxhYBkKyu5mEDHw=
|
||||
github.com/ethereum/go-ethereum v1.11.1 h1:EMymmWFzpS7G9l9NvVN8G73cgdUIqDPNRf2YTSGBXlk=
|
||||
github.com/ethereum/go-ethereum v1.11.1/go.mod h1:DuefStAgaxoaYGLR0FueVcVbehmn5n9QUcVrMCuOvuc=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/ethereum/go-ethereum v1.11.4 h1:KG81SnUHXWk8LJB3mBcHg/E2yLvXoiPmRMCIRxgx3cE=
|
||||
github.com/ethereum/go-ethereum v1.11.4/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo=
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
|
||||
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
|
||||
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
||||
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
|
||||
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
|
||||
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/iden3/go-iden3-crypto v0.0.12/go.mod h1:swXIv0HFbJKobbQBtsB50G7IHr6PbTowutSew/iBEoo=
|
||||
github.com/iden3/go-iden3-crypto v0.0.13 h1:ixWRiaqDULNyIDdOWz2QQJG5t4PpNHkQk2P6GV94cok=
|
||||
github.com/iden3/go-iden3-crypto v0.0.13/go.mod h1:swXIv0HFbJKobbQBtsB50G7IHr6PbTowutSew/iBEoo=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=
|
||||
github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8=
|
||||
github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk=
|
||||
github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE=
|
||||
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
|
||||
github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8=
|
||||
github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=
|
||||
github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=
|
||||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/iden3/go-iden3-crypto v0.0.14 h1:HQnFchY735JRNQxof6n/Vbyon4owj4+Ku+LNAamWV6c=
|
||||
github.com/iden3/go-iden3-crypto v0.0.14/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
||||
github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
||||
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
|
||||
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
|
||||
github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
|
||||
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
||||
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
||||
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
|
||||
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230220082843-ec9254b0b1c6 h1:2kXWJR+mOj09HBh5sUTb4L/OURPSXoQd1NC/10v7otM=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230220082843-ec9254b0b1c6/go.mod h1:eW+eyNdMoO0MyuczCc9xWSnW8dPJ0kOy5xsxgOKYEaA=
|
||||
github.com/scroll-tech/zktrie v0.5.0 h1:dABDR6lMZq6Hs+fWQSiHbX8s3AOX6hY+5nkhSYm5rmU=
|
||||
github.com/scroll-tech/zktrie v0.5.0/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230321020420-127af384ed04 h1:PpI31kaBVm6+7sZtyK03Ex0QIg3P821Ktae0FHFh7IM=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230321020420-127af384ed04/go.mod h1:jH8c08L9K8Hieaf0r/ur2P/cpesn4dFhmLm2Mmoi8kI=
|
||||
github.com/scroll-tech/zktrie v0.5.2 h1:U34jPXMLGOlRHfdvYp5VVgOcC0RuPeJmcS3bWotCWiY=
|
||||
github.com/scroll-tech/zktrie v0.5.2/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
||||
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
||||
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
|
||||
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q=
|
||||
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
||||
gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
|
||||
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
|
||||
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
@@ -15,42 +15,27 @@ var (
|
||||
cfg *config.Config
|
||||
|
||||
// docker consider handler.
|
||||
l1gethImg docker.ImgInstance
|
||||
l2gethImg docker.ImgInstance
|
||||
dbImg docker.ImgInstance
|
||||
base *docker.App
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
base = docker.NewDockerApp()
|
||||
|
||||
m.Run()
|
||||
|
||||
base.Free()
|
||||
}
|
||||
|
||||
func setupEnv(t *testing.T) {
|
||||
// Load config.
|
||||
var err error
|
||||
cfg, err = config.NewConfig("../config.json")
|
||||
assert.NoError(t, err)
|
||||
base.RunImages(t)
|
||||
|
||||
// Create l1geth container.
|
||||
l1gethImg = docker.NewTestL1Docker(t)
|
||||
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = l1gethImg.Endpoint()
|
||||
cfg.L1Config.Endpoint = l1gethImg.Endpoint()
|
||||
|
||||
// Create l2geth container.
|
||||
l2gethImg = docker.NewTestL2Docker(t)
|
||||
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
|
||||
cfg.L2Config.Endpoint = l2gethImg.Endpoint()
|
||||
|
||||
// Create db container.
|
||||
dbImg = docker.NewTestDBDocker(t, cfg.DBConfig.DriverName)
|
||||
cfg.DBConfig.DSN = dbImg.Endpoint()
|
||||
}
|
||||
|
||||
func free(t *testing.T) {
|
||||
if dbImg != nil {
|
||||
assert.NoError(t, dbImg.Stop())
|
||||
}
|
||||
if l1gethImg != nil {
|
||||
assert.NoError(t, l1gethImg.Stop())
|
||||
}
|
||||
if l2gethImg != nil {
|
||||
assert.NoError(t, l2gethImg.Stop())
|
||||
}
|
||||
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
|
||||
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
|
||||
cfg.DBConfig.DSN = base.DBEndpoint()
|
||||
}
|
||||
|
||||
func TestL1(t *testing.T) {
|
||||
@@ -58,8 +43,4 @@ func TestL1(t *testing.T) {
|
||||
|
||||
t.Run("testCreateNewL1Relayer", testCreateNewL1Relayer)
|
||||
t.Run("testStartWatcher", testStartWatcher)
|
||||
|
||||
t.Cleanup(func() {
|
||||
free(t)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,20 +12,31 @@ import (
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
geth_metrics "github.com/scroll-tech/go-ethereum/metrics"
|
||||
|
||||
"scroll-tech/common/types"
|
||||
"scroll-tech/common/utils"
|
||||
|
||||
"scroll-tech/database"
|
||||
|
||||
"scroll-tech/common/metrics"
|
||||
|
||||
bridge_abi "scroll-tech/bridge/abi"
|
||||
"scroll-tech/bridge/config"
|
||||
"scroll-tech/bridge/sender"
|
||||
)
|
||||
|
||||
var (
|
||||
bridgeL1MsgsRelayedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l1/msgs/relayed/total", metrics.ScrollRegistry)
|
||||
bridgeL1MsgsRelayedConfirmedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l1/msgs/relayed/confirmed/total", metrics.ScrollRegistry)
|
||||
)
|
||||
|
||||
const (
|
||||
gasPriceDiffPrecision = 1000000
|
||||
|
||||
defaultGasPriceDiff = 50000 // 5%
|
||||
|
||||
defaultMessageRelayMinGasLimit = 130000 // should be enough for both ERC20 and ETH relay
|
||||
)
|
||||
|
||||
// Layer1Relayer is responsible for
|
||||
@@ -49,6 +60,8 @@ type Layer1Relayer struct {
|
||||
gasOracleCh <-chan *sender.Confirmation
|
||||
l1GasOracleABI *abi.ABI
|
||||
|
||||
minGasLimitForMessageRelay uint64
|
||||
|
||||
lastGasPrice uint64
|
||||
minGasPrice uint64
|
||||
gasPriceDiff uint64
|
||||
@@ -83,6 +96,11 @@ func NewLayer1Relayer(ctx context.Context, db database.OrmFactory, cfg *config.R
|
||||
gasPriceDiff = defaultGasPriceDiff
|
||||
}
|
||||
|
||||
minGasLimitForMessageRelay := uint64(defaultMessageRelayMinGasLimit)
|
||||
if cfg.MessageRelayMinGasLimit != 0 {
|
||||
minGasLimitForMessageRelay = cfg.MessageRelayMinGasLimit
|
||||
}
|
||||
|
||||
return &Layer1Relayer{
|
||||
ctx: ctx,
|
||||
db: db,
|
||||
@@ -95,6 +113,8 @@ func NewLayer1Relayer(ctx context.Context, db database.OrmFactory, cfg *config.R
|
||||
gasOracleCh: gasOracleSender.ConfirmChan(),
|
||||
l1GasOracleABI: bridge_abi.L1GasPriceOracleABI,
|
||||
|
||||
minGasLimitForMessageRelay: minGasLimitForMessageRelay,
|
||||
|
||||
minGasPrice: minGasPrice,
|
||||
gasPriceDiff: gasPriceDiff,
|
||||
|
||||
@@ -129,7 +149,7 @@ func (r *Layer1Relayer) ProcessSavedEvents() {
|
||||
func (r *Layer1Relayer) processSavedEvent(msg *types.L1Message) error {
|
||||
calldata := common.Hex2Bytes(msg.Calldata)
|
||||
|
||||
hash, err := r.messageSender.SendTransaction(msg.MsgHash, &r.cfg.MessengerContractAddress, big.NewInt(0), calldata)
|
||||
hash, err := r.messageSender.SendTransaction(msg.MsgHash, &r.cfg.MessengerContractAddress, big.NewInt(0), calldata, r.minGasLimitForMessageRelay)
|
||||
if err != nil && err.Error() == "execution reverted: Message expired" {
|
||||
return r.db.UpdateLayer1Status(r.ctx, msg.MsgHash, types.MsgExpired)
|
||||
}
|
||||
@@ -139,6 +159,7 @@ func (r *Layer1Relayer) processSavedEvent(msg *types.L1Message) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bridgeL1MsgsRelayedTotalCounter.Inc(1)
|
||||
log.Info("relayMessage to layer2", "msg hash", msg.MsgHash, "tx hash", hash)
|
||||
|
||||
err = r.db.UpdateLayer1StatusAndLayer2Hash(r.ctx, msg.MsgHash, types.MsgSubmitted, hash.String())
|
||||
@@ -180,7 +201,7 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() {
|
||||
return
|
||||
}
|
||||
|
||||
hash, err := r.gasOracleSender.SendTransaction(block.Hash, &r.cfg.GasPriceOracleContractAddress, big.NewInt(0), data)
|
||||
hash, err := r.gasOracleSender.SendTransaction(block.Hash, &r.cfg.GasPriceOracleContractAddress, big.NewInt(0), data, 0)
|
||||
if err != nil {
|
||||
if !errors.Is(err, sender.ErrNoAvailableAccount) {
|
||||
log.Error("Failed to send setL1BaseFee tx to layer2 ", "block.Hash", block.Hash, "block.Height", block.Number, "err", err)
|
||||
@@ -201,24 +222,11 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() {
|
||||
|
||||
// Start the relayer process
|
||||
func (r *Layer1Relayer) Start() {
|
||||
loop := func(ctx context.Context, f func()) {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
f()
|
||||
}
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
ctx, cancel := context.WithCancel(r.ctx)
|
||||
|
||||
go loop(ctx, r.ProcessSavedEvents)
|
||||
go loop(ctx, r.ProcessGasPriceOracle)
|
||||
go utils.Loop(ctx, 2*time.Second, r.ProcessSavedEvents)
|
||||
go utils.Loop(ctx, 2*time.Second, r.ProcessGasPriceOracle)
|
||||
|
||||
go func(ctx context.Context) {
|
||||
for {
|
||||
@@ -226,6 +234,7 @@ func (r *Layer1Relayer) Start() {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case cfm := <-r.messageCh:
|
||||
bridgeL1MsgsRelayedConfirmedTotalCounter.Inc(1)
|
||||
if !cfm.IsSuccessful {
|
||||
log.Warn("transaction confirmed but failed in layer2", "confirmation", cfm)
|
||||
} else {
|
||||
|
||||
@@ -12,19 +12,25 @@ import (
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/scroll-tech/go-ethereum/metrics"
|
||||
geth_metrics "github.com/scroll-tech/go-ethereum/metrics"
|
||||
"github.com/scroll-tech/go-ethereum/rpc"
|
||||
|
||||
"scroll-tech/common/metrics"
|
||||
"scroll-tech/common/types"
|
||||
|
||||
"scroll-tech/database"
|
||||
|
||||
cutil "scroll-tech/common/utils"
|
||||
|
||||
bridge_abi "scroll-tech/bridge/abi"
|
||||
"scroll-tech/bridge/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
bridgeL1MsgSyncHeightGauge = metrics.NewRegisteredGauge("bridge/l1/msg/sync/height", nil)
|
||||
bridgeL1MsgsSyncHeightGauge = geth_metrics.NewRegisteredGauge("bridge/l1/msgs/sync/height", metrics.ScrollRegistry)
|
||||
|
||||
bridgeL1MsgsSentEventsTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l1/msgs/sent/events/total", metrics.ScrollRegistry)
|
||||
bridgeL1MsgsRelayedEventsTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l1/msgs/relayed/events/total", metrics.ScrollRegistry)
|
||||
bridgeL1MsgsRollupEventsTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l1/msgs/rollup/events/total", metrics.ScrollRegistry)
|
||||
)
|
||||
|
||||
type relayedMessage struct {
|
||||
@@ -114,51 +120,27 @@ func (w *Watcher) Start() {
|
||||
go func() {
|
||||
ctx, cancel := context.WithCancel(w.ctx)
|
||||
|
||||
go func(ctx context.Context) {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
number, err := utils.GetLatestConfirmedBlockNumber(w.ctx, w.client, w.confirmations)
|
||||
if err != nil {
|
||||
log.Error("failed to get block number", "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := w.FetchBlockHeader(number); err != nil {
|
||||
log.Error("Failed to fetch L1 block header", "lastest", number, "err", err)
|
||||
}
|
||||
go cutil.LoopWithContext(ctx, 2*time.Second, func(subCtx context.Context) {
|
||||
number, err := utils.GetLatestConfirmedBlockNumber(subCtx, w.client, w.confirmations)
|
||||
if err != nil {
|
||||
log.Error("failed to get block number", "err", err)
|
||||
} else {
|
||||
if err := w.FetchBlockHeader(number); err != nil {
|
||||
log.Error("Failed to fetch L1 block header", "lastest", number, "err", err)
|
||||
}
|
||||
}
|
||||
}(ctx)
|
||||
})
|
||||
|
||||
go func(ctx context.Context) {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
number, err := utils.GetLatestConfirmedBlockNumber(w.ctx, w.client, w.confirmations)
|
||||
if err != nil {
|
||||
log.Error("failed to get block number", "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := w.FetchContractEvent(number); err != nil {
|
||||
log.Error("Failed to fetch bridge contract", "err", err)
|
||||
}
|
||||
go cutil.LoopWithContext(ctx, 2*time.Second, func(subCtx context.Context) {
|
||||
number, err := utils.GetLatestConfirmedBlockNumber(subCtx, w.client, w.confirmations)
|
||||
if err != nil {
|
||||
log.Error("failed to get block number", "err", err)
|
||||
} else {
|
||||
if err := w.FetchContractEvent(number); err != nil {
|
||||
log.Error("Failed to fetch bridge contract", "err", err)
|
||||
}
|
||||
}
|
||||
}(ctx)
|
||||
})
|
||||
|
||||
<-w.stopCh
|
||||
cancel()
|
||||
@@ -259,7 +241,7 @@ func (w *Watcher) FetchContractEvent(blockHeight uint64) error {
|
||||
}
|
||||
if len(logs) == 0 {
|
||||
w.processedMsgHeight = uint64(to)
|
||||
bridgeL1MsgSyncHeightGauge.Update(to)
|
||||
bridgeL1MsgsSyncHeightGauge.Update(to)
|
||||
continue
|
||||
}
|
||||
log.Info("Received new L1 events", "fromBlock", from, "toBlock", to, "cnt", len(logs))
|
||||
@@ -269,7 +251,13 @@ func (w *Watcher) FetchContractEvent(blockHeight uint64) error {
|
||||
log.Error("Failed to parse emitted events log", "err", err)
|
||||
return err
|
||||
}
|
||||
log.Info("L1 events types", "SentMessageCount", len(sentMessageEvents), "RelayedMessageCount", len(relayedMessageEvents), "RollupEventCount", len(rollupEvents))
|
||||
sentMessageCount := int64(len(sentMessageEvents))
|
||||
relayedMessageCount := int64(len(relayedMessageEvents))
|
||||
rollupEventCount := int64(len(rollupEvents))
|
||||
bridgeL1MsgsSentEventsTotalCounter.Inc(sentMessageCount)
|
||||
bridgeL1MsgsRelayedEventsTotalCounter.Inc(relayedMessageCount)
|
||||
bridgeL1MsgsRollupEventsTotalCounter.Inc(rollupEventCount)
|
||||
log.Info("L1 events types", "SentMessageCount", sentMessageCount, "RelayedMessageCount", relayedMessageCount, "RollupEventCount", rollupEventCount)
|
||||
|
||||
// use rollup event to update rollup results db status
|
||||
var batchHashes []string
|
||||
@@ -323,7 +311,7 @@ func (w *Watcher) FetchContractEvent(blockHeight uint64) error {
|
||||
}
|
||||
|
||||
w.processedMsgHeight = uint64(to)
|
||||
bridgeL1MsgSyncHeightGauge.Update(to)
|
||||
bridgeL1MsgsSyncHeightGauge.Update(to)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -18,7 +18,7 @@ func testStartWatcher(t *testing.T) {
|
||||
assert.NoError(t, migrate.ResetDB(db.GetDB().DB))
|
||||
defer db.Close()
|
||||
|
||||
client, err := ethclient.Dial(l1gethImg.Endpoint())
|
||||
client, err := ethclient.Dial(base.L1GethEndpoint())
|
||||
assert.NoError(t, err)
|
||||
|
||||
l1Cfg := cfg.L1Config
|
||||
|
||||
@@ -10,8 +10,11 @@ import (
|
||||
|
||||
geth_types "github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
geth_metrics "github.com/scroll-tech/go-ethereum/metrics"
|
||||
|
||||
"scroll-tech/common/metrics"
|
||||
"scroll-tech/common/types"
|
||||
"scroll-tech/common/utils"
|
||||
|
||||
"scroll-tech/database"
|
||||
|
||||
@@ -19,6 +22,16 @@ import (
|
||||
"scroll-tech/bridge/config"
|
||||
)
|
||||
|
||||
var (
|
||||
bridgeL2BatchesGasOverThresholdTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/batches/gas/over/threshold/total", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesTxsOverThresholdTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/batches/txs/over/threshold/total", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesCommitTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/batches/commit/total", metrics.ScrollRegistry)
|
||||
|
||||
bridgeL2BatchesCreatedRateMeter = geth_metrics.NewRegisteredMeter("bridge/l2/batches/blocks/created/rate", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesTxsCreatedRateMeter = geth_metrics.NewRegisteredMeter("bridge/l2/batches/txs/created/rate", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesGasCreatedRateMeter = geth_metrics.NewRegisteredMeter("bridge/l2/batches/gas/created/rate", metrics.ScrollRegistry)
|
||||
)
|
||||
|
||||
// AddBatchInfoToDB inserts the batch information to the BlockBatch table and updates the batch_hash
|
||||
// in all blocks included in the batch.
|
||||
func AddBatchInfoToDB(db database.OrmFactory, batchData *types.BatchData) error {
|
||||
@@ -114,22 +127,10 @@ func (p *BatchProposer) Start() {
|
||||
|
||||
ctx, cancel := context.WithCancel(p.ctx)
|
||||
|
||||
// batch proposer loop
|
||||
go func(ctx context.Context) {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
p.tryProposeBatch()
|
||||
p.tryCommitBatches()
|
||||
}
|
||||
}
|
||||
}(ctx)
|
||||
go utils.Loop(ctx, 2*time.Second, func() {
|
||||
p.tryProposeBatch()
|
||||
p.tryCommitBatches()
|
||||
})
|
||||
|
||||
<-p.stopCh
|
||||
cancel()
|
||||
@@ -270,6 +271,7 @@ func (p *BatchProposer) tryCommitBatches() {
|
||||
log.Error("SendCommitTx failed", "error", err)
|
||||
} else {
|
||||
// pop the processed batches from the buffer
|
||||
bridgeL2BatchesCommitTotalCounter.Inc(1)
|
||||
p.batchDataBuffer = p.batchDataBuffer[index:]
|
||||
}
|
||||
}
|
||||
@@ -280,17 +282,27 @@ func (p *BatchProposer) proposeBatch(blocks []*types.BlockInfo) {
|
||||
}
|
||||
|
||||
if blocks[0].GasUsed > p.batchGasThreshold {
|
||||
bridgeL2BatchesGasOverThresholdTotalCounter.Inc(1)
|
||||
log.Warn("gas overflow even for only 1 block", "height", blocks[0].Number, "gas", blocks[0].GasUsed)
|
||||
if err := p.createBatchForBlocks(blocks[:1]); err != nil {
|
||||
log.Error("failed to create batch", "number", blocks[0].Number, "err", err)
|
||||
} else {
|
||||
bridgeL2BatchesTxsCreatedRateMeter.Mark(int64(blocks[0].TxNum))
|
||||
bridgeL2BatchesGasCreatedRateMeter.Mark(int64(blocks[0].GasUsed))
|
||||
bridgeL2BatchesCreatedRateMeter.Mark(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if blocks[0].TxNum > p.batchTxNumThreshold {
|
||||
bridgeL2BatchesTxsOverThresholdTotalCounter.Inc(1)
|
||||
log.Warn("too many txs even for only 1 block", "height", blocks[0].Number, "tx_num", blocks[0].TxNum)
|
||||
if err := p.createBatchForBlocks(blocks[:1]); err != nil {
|
||||
log.Error("failed to create batch", "number", blocks[0].Number, "err", err)
|
||||
} else {
|
||||
bridgeL2BatchesTxsCreatedRateMeter.Mark(int64(blocks[0].TxNum))
|
||||
bridgeL2BatchesGasCreatedRateMeter.Mark(int64(blocks[0].GasUsed))
|
||||
bridgeL2BatchesCreatedRateMeter.Mark(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -317,6 +329,10 @@ func (p *BatchProposer) proposeBatch(blocks []*types.BlockInfo) {
|
||||
|
||||
if err := p.createBatchForBlocks(blocks); err != nil {
|
||||
log.Error("failed to create batch", "from", blocks[0].Number, "to", blocks[len(blocks)-1].Number, "err", err)
|
||||
} else {
|
||||
bridgeL2BatchesTxsCreatedRateMeter.Mark(int64(txNum))
|
||||
bridgeL2BatchesGasCreatedRateMeter.Mark(int64(gasUsed))
|
||||
bridgeL2BatchesCreatedRateMeter.Mark(int64(len(blocks)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,7 @@ var (
|
||||
// config
|
||||
cfg *config.Config
|
||||
|
||||
// docker consider handler.
|
||||
l1gethImg docker.ImgInstance
|
||||
l2gethImg docker.ImgInstance
|
||||
dbImg docker.ImgInstance
|
||||
base *docker.App
|
||||
|
||||
// l2geth client
|
||||
l2Cli *ethclient.Client
|
||||
@@ -42,22 +39,14 @@ func setupEnv(t *testing.T) (err error) {
|
||||
cfg, err = config.NewConfig("../config.json")
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Create l1geth container.
|
||||
l1gethImg = docker.NewTestL1Docker(t)
|
||||
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = l1gethImg.Endpoint()
|
||||
cfg.L1Config.Endpoint = l1gethImg.Endpoint()
|
||||
base.RunImages(t)
|
||||
|
||||
// Create l2geth container.
|
||||
l2gethImg = docker.NewTestL2Docker(t)
|
||||
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
|
||||
cfg.L2Config.Endpoint = l2gethImg.Endpoint()
|
||||
|
||||
// Create db container.
|
||||
dbImg = docker.NewTestDBDocker(t, cfg.DBConfig.DriverName)
|
||||
cfg.DBConfig.DSN = dbImg.Endpoint()
|
||||
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
|
||||
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
|
||||
cfg.DBConfig.DSN = base.DBEndpoint()
|
||||
|
||||
// Create l2geth client.
|
||||
l2Cli, err = ethclient.Dial(cfg.L2Config.Endpoint)
|
||||
l2Cli, err = base.L2Client()
|
||||
assert.NoError(t, err)
|
||||
|
||||
templateBlockTrace1, err := os.ReadFile("../../common/testdata/blockTrace_02.json")
|
||||
@@ -97,16 +86,12 @@ func setupEnv(t *testing.T) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func free(t *testing.T) {
|
||||
if dbImg != nil {
|
||||
assert.NoError(t, dbImg.Stop())
|
||||
}
|
||||
if l1gethImg != nil {
|
||||
assert.NoError(t, l1gethImg.Stop())
|
||||
}
|
||||
if l2gethImg != nil {
|
||||
assert.NoError(t, l2gethImg.Stop())
|
||||
}
|
||||
func TestMain(m *testing.M) {
|
||||
base = docker.NewDockerApp()
|
||||
|
||||
m.Run()
|
||||
|
||||
base.Free()
|
||||
}
|
||||
|
||||
func TestFunction(t *testing.T) {
|
||||
@@ -129,7 +114,4 @@ func TestFunction(t *testing.T) {
|
||||
t.Run("TestBatchProposerProposeBatch", testBatchProposerProposeBatch)
|
||||
t.Run("TestBatchProposerGracefulRestart", testBatchProposerGracefulRestart)
|
||||
|
||||
t.Cleanup(func() {
|
||||
free(t)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -9,30 +9,43 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
// not sure if this will make problems when relay with l1geth
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/accounts/abi"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
geth_metrics "github.com/scroll-tech/go-ethereum/metrics"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"modernc.org/mathutil"
|
||||
|
||||
"scroll-tech/common/metrics"
|
||||
"scroll-tech/common/types"
|
||||
|
||||
"scroll-tech/database"
|
||||
|
||||
cutil "scroll-tech/common/utils"
|
||||
|
||||
bridge_abi "scroll-tech/bridge/abi"
|
||||
"scroll-tech/bridge/config"
|
||||
"scroll-tech/bridge/sender"
|
||||
"scroll-tech/bridge/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
bridgeL2MsgsRelayedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/msgs/relayed/total", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesFinalizedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/batches/finalized/total", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesCommittedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/batches/committed/total", metrics.ScrollRegistry)
|
||||
bridgeL2MsgsRelayedConfirmedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/msgs/relayed/confirmed/total", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesFinalizedConfirmedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/batches/finalized/confirmed/total", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesCommittedConfirmedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/batches/committed/confirmed/total", metrics.ScrollRegistry)
|
||||
bridgeL2BatchesSkippedTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/batches/skipped/total", metrics.ScrollRegistry)
|
||||
)
|
||||
|
||||
const (
|
||||
gasPriceDiffPrecision = 1000000
|
||||
|
||||
defaultGasPriceDiff = 50000 // 5%
|
||||
|
||||
defaultMessageRelayMinGasLimit = 200000 // should be enough for both ERC20 and ETH relay
|
||||
)
|
||||
|
||||
// Layer2Relayer is responsible for
|
||||
@@ -61,6 +74,8 @@ type Layer2Relayer struct {
|
||||
gasOracleCh <-chan *sender.Confirmation
|
||||
l2GasOracleABI *abi.ABI
|
||||
|
||||
minGasLimitForMessageRelay uint64
|
||||
|
||||
lastGasPrice uint64
|
||||
minGasPrice uint64
|
||||
gasPriceDiff uint64
|
||||
@@ -111,6 +126,11 @@ func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db databa
|
||||
gasPriceDiff = defaultGasPriceDiff
|
||||
}
|
||||
|
||||
minGasLimitForMessageRelay := uint64(defaultMessageRelayMinGasLimit)
|
||||
if cfg.MessageRelayMinGasLimit != 0 {
|
||||
minGasLimitForMessageRelay = cfg.MessageRelayMinGasLimit
|
||||
}
|
||||
|
||||
return &Layer2Relayer{
|
||||
ctx: ctx,
|
||||
db: db,
|
||||
@@ -129,6 +149,8 @@ func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db databa
|
||||
gasOracleCh: gasOracleSender.ConfirmChan(),
|
||||
l2GasOracleABI: bridge_abi.L2GasPriceOracleABI,
|
||||
|
||||
minGasLimitForMessageRelay: minGasLimitForMessageRelay,
|
||||
|
||||
minGasPrice: minGasPrice,
|
||||
gasPriceDiff: gasPriceDiff,
|
||||
|
||||
@@ -221,7 +243,7 @@ func (r *Layer2Relayer) processSavedEvent(msg *types.L2Message) error {
|
||||
return err
|
||||
}
|
||||
|
||||
hash, err := r.messageSender.SendTransaction(msg.MsgHash, &r.cfg.MessengerContractAddress, big.NewInt(0), data)
|
||||
hash, err := r.messageSender.SendTransaction(msg.MsgHash, &r.cfg.MessengerContractAddress, big.NewInt(0), data, r.minGasLimitForMessageRelay)
|
||||
if err != nil && err.Error() == "execution reverted: Message expired" {
|
||||
return r.db.UpdateLayer2Status(r.ctx, msg.MsgHash, types.MsgExpired)
|
||||
}
|
||||
@@ -234,6 +256,7 @@ func (r *Layer2Relayer) processSavedEvent(msg *types.L2Message) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
bridgeL2MsgsRelayedTotalCounter.Inc(1)
|
||||
log.Info("relayMessageWithProof to layer1", "msgHash", msg.MsgHash, "txhash", hash.String())
|
||||
|
||||
// save status in db
|
||||
@@ -272,7 +295,7 @@ func (r *Layer2Relayer) ProcessGasPriceOracle() {
|
||||
return
|
||||
}
|
||||
|
||||
hash, err := r.gasOracleSender.SendTransaction(batch.Hash, &r.cfg.GasPriceOracleContractAddress, big.NewInt(0), data)
|
||||
hash, err := r.gasOracleSender.SendTransaction(batch.Hash, &r.cfg.GasPriceOracleContractAddress, big.NewInt(0), data, 0)
|
||||
if err != nil {
|
||||
if !errors.Is(err, sender.ErrNoAvailableAccount) {
|
||||
log.Error("Failed to send setL2BaseFee tx to layer2 ", "batch.Hash", batch.Hash, "err", err)
|
||||
@@ -318,13 +341,14 @@ func (r *Layer2Relayer) SendCommitTx(batchData []*types.BatchData) error {
|
||||
bytes = append(bytes, batch.Hash().Bytes()...)
|
||||
}
|
||||
txID := crypto.Keccak256Hash(bytes).String()
|
||||
txHash, err := r.rollupSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), calldata)
|
||||
txHash, err := r.rollupSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), calldata, 0)
|
||||
if err != nil {
|
||||
if !errors.Is(err, sender.ErrNoAvailableAccount) {
|
||||
log.Error("Failed to send commitBatches tx to layer1 ", "err", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
bridgeL2BatchesCommittedTotalCounter.Inc(int64(len(commitBatches)))
|
||||
log.Info("Sent the commitBatches tx to layer1",
|
||||
"tx_hash", txHash.Hex(),
|
||||
"start_batch_index", commitBatches[0].BatchIndex,
|
||||
@@ -350,6 +374,7 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
|
||||
log.Error("UpdateSkippedBatches failed", "err", err)
|
||||
// continue anyway
|
||||
} else if count > 0 {
|
||||
bridgeL2BatchesSkippedTotalCounter.Inc(count)
|
||||
log.Info("Skipping batches", "count", count)
|
||||
}
|
||||
|
||||
@@ -465,7 +490,7 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
|
||||
|
||||
txID := hash + "-finalize"
|
||||
// add suffix `-finalize` to avoid duplication with commit tx in unit tests
|
||||
txHash, err := r.rollupSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), data)
|
||||
txHash, err := r.rollupSender.SendTransaction(txID, &r.cfg.RollupContractAddress, big.NewInt(0), data, 0)
|
||||
finalizeTxHash := &txHash
|
||||
if err != nil {
|
||||
if !errors.Is(err, sender.ErrNoAvailableAccount) {
|
||||
@@ -473,6 +498,7 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
|
||||
}
|
||||
return
|
||||
}
|
||||
bridgeL2BatchesFinalizedTotalCounter.Inc(1)
|
||||
log.Info("finalizeBatchWithProof in layer1", "batch_hash", hash, "tx_hash", hash)
|
||||
|
||||
// record and sync with db, @todo handle db error
|
||||
@@ -492,26 +518,11 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
|
||||
|
||||
// Start the relayer process
|
||||
func (r *Layer2Relayer) Start() {
|
||||
loop := func(ctx context.Context, f func()) {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
f()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
ctx, cancel := context.WithCancel(r.ctx)
|
||||
|
||||
go loop(ctx, r.ProcessSavedEvents)
|
||||
go loop(ctx, r.ProcessCommittedBatches)
|
||||
go loop(ctx, r.ProcessGasPriceOracle)
|
||||
go cutil.Loop(ctx, time.Second, r.ProcessSavedEvents)
|
||||
go cutil.Loop(ctx, time.Second, r.ProcessCommittedBatches)
|
||||
go cutil.Loop(ctx, time.Second, r.ProcessGasPriceOracle)
|
||||
|
||||
go func(ctx context.Context) {
|
||||
for {
|
||||
@@ -567,19 +578,22 @@ func (r *Layer2Relayer) handleConfirmation(confirmation *sender.Confirmation) {
|
||||
if err != nil {
|
||||
log.Warn("UpdateLayer2StatusAndLayer1Hash failed", "msgHash", msgHash.(string), "err", err)
|
||||
}
|
||||
bridgeL2MsgsRelayedConfirmedTotalCounter.Inc(1)
|
||||
r.processingMessage.Delete(confirmation.ID)
|
||||
}
|
||||
|
||||
// check whether it is CommitBatches transaction
|
||||
if batchBatches, ok := r.processingBatchesCommitment.Load(confirmation.ID); ok {
|
||||
transactionType = "BatchesCommitment"
|
||||
for _, batchHash := range batchBatches.([]string) {
|
||||
batchHashes := batchBatches.([]string)
|
||||
for _, batchHash := range batchHashes {
|
||||
// @todo handle db error
|
||||
err := r.db.UpdateCommitTxHashAndRollupStatus(r.ctx, batchHash, confirmation.TxHash.String(), types.RollupCommitted)
|
||||
if err != nil {
|
||||
log.Warn("UpdateCommitTxHashAndRollupStatus failed", "batch_hash", batchHash, "err", err)
|
||||
}
|
||||
}
|
||||
bridgeL2BatchesCommittedConfirmedTotalCounter.Inc(int64(len(batchHashes)))
|
||||
r.processingBatchesCommitment.Delete(confirmation.ID)
|
||||
}
|
||||
|
||||
@@ -591,6 +605,7 @@ func (r *Layer2Relayer) handleConfirmation(confirmation *sender.Confirmation) {
|
||||
if err != nil {
|
||||
log.Warn("UpdateFinalizeTxHashAndRollupStatus failed", "batch_hash", batchHash.(string), "err", err)
|
||||
}
|
||||
bridgeL2BatchesFinalizedConfirmedTotalCounter.Inc(1)
|
||||
r.processingFinalization.Delete(confirmation.ID)
|
||||
}
|
||||
log.Info("transaction confirmed in layer1", "type", transactionType, "confirmation", confirmation)
|
||||
|
||||
@@ -73,8 +73,7 @@ func testL2RelayerProcessSaveEvents(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
err = db.InsertL2BlockTraces(traces)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.InsertL2BlockTraces(traces))
|
||||
|
||||
dbTx, err := db.Beginx()
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -15,20 +15,27 @@ import (
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/event"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/scroll-tech/go-ethereum/metrics"
|
||||
geth_metrics "github.com/scroll-tech/go-ethereum/metrics"
|
||||
"github.com/scroll-tech/go-ethereum/rpc"
|
||||
|
||||
"scroll-tech/common/metrics"
|
||||
"scroll-tech/common/types"
|
||||
cutil "scroll-tech/common/utils"
|
||||
"scroll-tech/database"
|
||||
|
||||
bridge_abi "scroll-tech/bridge/abi"
|
||||
"scroll-tech/bridge/utils"
|
||||
|
||||
"scroll-tech/common/types"
|
||||
|
||||
"scroll-tech/database"
|
||||
)
|
||||
|
||||
// Metrics
|
||||
var (
|
||||
bridgeL2MsgSyncHeightGauge = metrics.NewRegisteredGauge("bridge/l2/msg/sync/height", nil)
|
||||
bridgeL2MsgsSyncHeightGauge = geth_metrics.NewRegisteredGauge("bridge/l2/msgs/sync/height", metrics.ScrollRegistry)
|
||||
bridgeL2TracesFetchedHeightGauge = geth_metrics.NewRegisteredGauge("bridge/l2/traces/fetched/height", metrics.ScrollRegistry)
|
||||
bridgeL2TracesFetchedGapGauge = geth_metrics.NewRegisteredGauge("bridge/l2/traces/fetched/gap", metrics.ScrollRegistry)
|
||||
|
||||
bridgeL2MsgsSentEventsTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/msgs/sent/events/total", metrics.ScrollRegistry)
|
||||
bridgeL2MsgsAppendEventsTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/msgs/append/events/total", metrics.ScrollRegistry)
|
||||
bridgeL2MsgsRelayedEventsTotalCounter = geth_metrics.NewRegisteredCounter("bridge/l2/msgs/relayed/events/total", metrics.ScrollRegistry)
|
||||
)
|
||||
|
||||
type relayedMessage struct {
|
||||
@@ -148,50 +155,23 @@ func (w *WatcherClient) Start() {
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(w.ctx)
|
||||
|
||||
// trace fetcher loop
|
||||
go func(ctx context.Context) {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
number, err := utils.GetLatestConfirmedBlockNumber(ctx, w.Client, w.confirmations)
|
||||
if err != nil {
|
||||
log.Error("failed to get block number", "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
w.tryFetchRunningMissingBlocks(ctx, number)
|
||||
}
|
||||
go cutil.LoopWithContext(ctx, 2*time.Second, func(subCtx context.Context) {
|
||||
number, err := utils.GetLatestConfirmedBlockNumber(subCtx, w.Client, w.confirmations)
|
||||
if err != nil {
|
||||
log.Error("failed to get block number", "err", err)
|
||||
} else {
|
||||
w.tryFetchRunningMissingBlocks(ctx, number)
|
||||
}
|
||||
}(ctx)
|
||||
})
|
||||
|
||||
// event fetcher loop
|
||||
go func(ctx context.Context) {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
number, err := utils.GetLatestConfirmedBlockNumber(ctx, w.Client, w.confirmations)
|
||||
if err != nil {
|
||||
log.Error("failed to get block number", "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
w.FetchContractEvent(number)
|
||||
}
|
||||
go cutil.LoopWithContext(ctx, 2*time.Second, func(subCtx context.Context) {
|
||||
number, err := utils.GetLatestConfirmedBlockNumber(subCtx, w.Client, w.confirmations)
|
||||
if err != nil {
|
||||
log.Error("failed to get block number", "err", err)
|
||||
} else {
|
||||
w.FetchContractEvent(number)
|
||||
}
|
||||
}(ctx)
|
||||
})
|
||||
|
||||
<-w.stopCh
|
||||
cancel()
|
||||
@@ -234,12 +214,13 @@ func (w *WatcherClient) tryFetchRunningMissingBlocks(ctx context.Context, blockH
|
||||
log.Error("fail to getAndStoreBlockTraces", "from", from, "to", to, "err", err)
|
||||
return
|
||||
}
|
||||
bridgeL2TracesFetchedHeightGauge.Update(int64(to))
|
||||
bridgeL2TracesFetchedGapGauge.Update(int64(blockHeight - to))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WatcherClient) getAndStoreBlockTraces(ctx context.Context, from, to uint64) error {
|
||||
var traces []*geth_types.BlockTrace
|
||||
|
||||
for number := from; number <= to; number++ {
|
||||
log.Debug("retrieving block trace", "height", number)
|
||||
trace, err2 := w.GetBlockTraceByNumber(ctx, big.NewInt(int64(number)))
|
||||
@@ -247,9 +228,7 @@ func (w *WatcherClient) getAndStoreBlockTraces(ctx context.Context, from, to uin
|
||||
return fmt.Errorf("failed to GetBlockResultByHash: %v. number: %v", err2, number)
|
||||
}
|
||||
log.Info("retrieved block trace", "height", trace.Header.Number, "hash", trace.Header.Hash().String())
|
||||
|
||||
traces = append(traces, trace)
|
||||
|
||||
}
|
||||
if len(traces) > 0 {
|
||||
if err := w.orm.InsertL2BlockTraces(traces); err != nil {
|
||||
@@ -301,7 +280,7 @@ func (w *WatcherClient) FetchContractEvent(blockHeight uint64) {
|
||||
}
|
||||
if len(logs) == 0 {
|
||||
w.processedMsgHeight = uint64(to)
|
||||
bridgeL2MsgSyncHeightGauge.Update(to)
|
||||
bridgeL2MsgsSyncHeightGauge.Update(to)
|
||||
continue
|
||||
}
|
||||
log.Info("received new L2 messages", "fromBlock", from, "toBlock", to, "cnt", len(logs))
|
||||
@@ -312,6 +291,12 @@ func (w *WatcherClient) FetchContractEvent(blockHeight uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
sentMessageCount := int64(len(sentMessageEvents))
|
||||
relayedMessageCount := int64(len(relayedMessageEvents))
|
||||
bridgeL2MsgsSentEventsTotalCounter.Inc(sentMessageCount)
|
||||
bridgeL2MsgsRelayedEventsTotalCounter.Inc(relayedMessageCount)
|
||||
log.Info("L2 events types", "SentMessageCount", sentMessageCount, "RelayedMessageCount", relayedMessageCount)
|
||||
|
||||
// Update relayed message first to make sure we don't forget to update submited message.
|
||||
// Since, we always start sync from the latest unprocessed message.
|
||||
for _, msg := range relayedMessageEvents {
|
||||
@@ -333,7 +318,7 @@ func (w *WatcherClient) FetchContractEvent(blockHeight uint64) {
|
||||
}
|
||||
|
||||
w.processedMsgHeight = uint64(to)
|
||||
bridgeL2MsgSyncHeightGauge.Update(to)
|
||||
bridgeL2MsgsSyncHeightGauge.Update(to)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,6 +407,7 @@ func (w *WatcherClient) parseBridgeEventLogs(logs []geth_types.Log) ([]*types.L2
|
||||
|
||||
lastAppendMsgHash = event.MessageHash
|
||||
lastAppendMsgNonce = event.Index.Uint64()
|
||||
bridgeL2MsgsAppendEventsTotalCounter.Inc(1)
|
||||
default:
|
||||
log.Error("Unknown event", "topic", vLog.Topics[0], "txHash", vLog.TxHash)
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func testCreateNewWatcherAndStop(t *testing.T) {
|
||||
numTransactions := 3
|
||||
toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
|
||||
for i := 0; i < numTransactions; i++ {
|
||||
_, err = newSender.SendTransaction(strconv.Itoa(1000+i), &toAddress, big.NewInt(1000000000), nil)
|
||||
_, err = newSender.SendTransaction(strconv.Itoa(1000+i), &toAddress, big.NewInt(1000000000), nil, 0)
|
||||
assert.NoError(t, err)
|
||||
<-newSender.ConfirmChan()
|
||||
}
|
||||
|
||||
73
bridge/sender/estimategas.go
Normal file
73
bridge/sender/estimategas.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum"
|
||||
"github.com/scroll-tech/go-ethereum/accounts/abi/bind"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
)
|
||||
|
||||
func (s *Sender) estimateLegacyGas(auth *bind.TransactOpts, contract *common.Address, value *big.Int, input []byte, minGasLimit uint64) (*FeeData, error) {
|
||||
gasPrice, err := s.client.SuggestGasPrice(s.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gasLimit, err := s.estimateGasLimit(auth, contract, input, gasPrice, nil, nil, value, minGasLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FeeData{
|
||||
gasPrice: gasPrice,
|
||||
gasLimit: gasLimit,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Sender) estimateDynamicGas(auth *bind.TransactOpts, contract *common.Address, value *big.Int, input []byte, minGasLimit uint64) (*FeeData, error) {
|
||||
gasTipCap, err := s.client.SuggestGasTipCap(s.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseFee := big.NewInt(0)
|
||||
if feeGas := atomic.LoadUint64(&s.baseFeePerGas); feeGas != 0 {
|
||||
baseFee.SetUint64(feeGas)
|
||||
}
|
||||
gasFeeCap := new(big.Int).Add(
|
||||
gasTipCap,
|
||||
new(big.Int).Mul(baseFee, big.NewInt(2)),
|
||||
)
|
||||
gasLimit, err := s.estimateGasLimit(auth, contract, input, nil, gasTipCap, gasFeeCap, value, minGasLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FeeData{
|
||||
gasLimit: gasLimit,
|
||||
gasTipCap: gasTipCap,
|
||||
gasFeeCap: gasFeeCap,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Sender) estimateGasLimit(opts *bind.TransactOpts, contract *common.Address, input []byte, gasPrice, gasTipCap, gasFeeCap, value *big.Int, minGasLimit uint64) (uint64, error) {
|
||||
msg := ethereum.CallMsg{
|
||||
From: opts.From,
|
||||
To: contract,
|
||||
GasPrice: gasPrice,
|
||||
GasTipCap: gasTipCap,
|
||||
GasFeeCap: gasFeeCap,
|
||||
Value: value,
|
||||
Data: input,
|
||||
}
|
||||
gasLimit, err := s.client.EstimateGas(s.ctx, msg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if minGasLimit > gasLimit {
|
||||
gasLimit = minGasLimit
|
||||
}
|
||||
|
||||
gasLimit = gasLimit * 15 / 10 // 50% extra gas to void out of gas error
|
||||
|
||||
return gasLimit, nil
|
||||
}
|
||||
@@ -12,10 +12,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
geth "github.com/scroll-tech/go-ethereum"
|
||||
"github.com/scroll-tech/go-ethereum/accounts/abi/bind"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/common/math"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
@@ -152,42 +150,15 @@ func (s *Sender) NumberOfAccounts() int {
|
||||
return len(s.auths.accounts)
|
||||
}
|
||||
|
||||
func (s *Sender) getFeeData(auth *bind.TransactOpts, target *common.Address, value *big.Int, data []byte) (*FeeData, error) {
|
||||
// estimate gas limit
|
||||
gasLimit, err := s.client.EstimateGas(s.ctx, geth.CallMsg{From: auth.From, To: target, Value: value, Data: data})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *Sender) getFeeData(auth *bind.TransactOpts, target *common.Address, value *big.Int, data []byte, minGasLimit uint64) (*FeeData, error) {
|
||||
if s.config.TxType == DynamicFeeTxType {
|
||||
return s.estimateDynamicGas(auth, target, value, data, minGasLimit)
|
||||
}
|
||||
gasLimit = gasLimit * 15 / 10 // 50% extra gas to void out of gas error
|
||||
// @todo change it when Scroll enable EIP1559
|
||||
if s.config.TxType != DynamicFeeTxType {
|
||||
// estimate gas price
|
||||
var gasPrice *big.Int
|
||||
gasPrice, err = s.client.SuggestGasPrice(s.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FeeData{
|
||||
gasPrice: gasPrice,
|
||||
gasLimit: gasLimit,
|
||||
}, nil
|
||||
}
|
||||
gasTipCap, err := s.client.SuggestGasTipCap(s.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Make sure feeCap is bigger than txpool's gas price. 1000000000 is l2geth's default pool.gas value.
|
||||
baseFee := atomic.LoadUint64(&s.baseFeePerGas)
|
||||
maxFeePerGas := math.BigMax(big.NewInt(int64(baseFee)), big.NewInt(1000000000))
|
||||
return &FeeData{
|
||||
gasFeeCap: math.BigMax(maxFeePerGas, gasTipCap),
|
||||
gasTipCap: math.BigMin(maxFeePerGas, gasTipCap),
|
||||
gasLimit: gasLimit,
|
||||
}, nil
|
||||
return s.estimateLegacyGas(auth, target, value, data, minGasLimit)
|
||||
}
|
||||
|
||||
// SendTransaction send a signed L2tL1 transaction.
|
||||
func (s *Sender) SendTransaction(ID string, target *common.Address, value *big.Int, data []byte) (hash common.Hash, err error) {
|
||||
func (s *Sender) SendTransaction(ID string, target *common.Address, value *big.Int, data []byte, minGasLimit uint64) (hash common.Hash, err error) {
|
||||
// We occupy the ID, in case some other threads call with the same ID in the same time
|
||||
if _, loaded := s.pendingTxs.LoadOrStore(ID, nil); loaded {
|
||||
return common.Hash{}, fmt.Errorf("has the repeat tx ID, ID: %s", ID)
|
||||
@@ -211,7 +182,7 @@ func (s *Sender) SendTransaction(ID string, target *common.Address, value *big.I
|
||||
tx *types.Transaction
|
||||
)
|
||||
// estimate gas fee
|
||||
if feeData, err = s.getFeeData(auth, target, value, data); err != nil {
|
||||
if feeData, err = s.getFeeData(auth, target, value, data, minGasLimit); err != nil {
|
||||
return
|
||||
}
|
||||
if tx, err = s.createAndSendTx(auth, feeData, target, value, data, nil); err == nil {
|
||||
@@ -436,7 +407,7 @@ func (s *Sender) loop(ctx context.Context) {
|
||||
checkTick := time.NewTicker(time.Duration(s.config.CheckPendingTime) * time.Second)
|
||||
defer checkTick.Stop()
|
||||
|
||||
checkBalanceTicker := time.NewTicker(time.Minute * 10)
|
||||
checkBalanceTicker := time.NewTicker(time.Duration(s.config.CheckBalanceTime) * time.Second)
|
||||
defer checkBalanceTicker.Stop()
|
||||
|
||||
for {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
cmap "github.com/orcaman/concurrent-map"
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/scroll-tech/go-ethereum/rpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@@ -28,35 +29,64 @@ const TXBatch = 50
|
||||
var (
|
||||
privateKeys []*ecdsa.PrivateKey
|
||||
cfg *config.Config
|
||||
l2gethImg docker.ImgInstance
|
||||
base *docker.App
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
base = docker.NewDockerApp()
|
||||
|
||||
m.Run()
|
||||
|
||||
base.Free()
|
||||
}
|
||||
|
||||
func setupEnv(t *testing.T) {
|
||||
var err error
|
||||
cfg, err = config.NewConfig("../config.json")
|
||||
assert.NoError(t, err)
|
||||
|
||||
base.RunImages(t)
|
||||
priv, err := crypto.HexToECDSA("1212121212121212121212121212121212121212121212121212121212121212")
|
||||
assert.NoError(t, err)
|
||||
// Load default private key.
|
||||
privateKeys = []*ecdsa.PrivateKey{priv}
|
||||
|
||||
l2gethImg = docker.NewTestL2Docker(t)
|
||||
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
|
||||
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
|
||||
}
|
||||
|
||||
func TestSender(t *testing.T) {
|
||||
// Setup
|
||||
setupEnv(t)
|
||||
|
||||
t.Run("test min gas limit", func(t *testing.T) { testMinGasLimit(t) })
|
||||
|
||||
t.Run("test 1 account sender", func(t *testing.T) { testBatchSender(t, 1) })
|
||||
t.Run("test 3 account sender", func(t *testing.T) { testBatchSender(t, 3) })
|
||||
t.Run("test 8 account sender", func(t *testing.T) { testBatchSender(t, 8) })
|
||||
}
|
||||
|
||||
// Teardown
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, l2gethImg.Stop())
|
||||
})
|
||||
func testMinGasLimit(t *testing.T) {
|
||||
senderCfg := cfg.L1Config.RelayerConfig.SenderConfig
|
||||
senderCfg.Confirmations = rpc.LatestBlockNumber
|
||||
newSender, err := sender.NewSender(context.Background(), senderCfg, privateKeys)
|
||||
assert.NoError(t, err)
|
||||
defer newSender.Stop()
|
||||
|
||||
client, err := ethclient.Dial(senderCfg.Endpoint)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// MinGasLimit = 0
|
||||
txHash0, err := newSender.SendTransaction("0", &common.Address{}, big.NewInt(1), nil, 0)
|
||||
assert.NoError(t, err)
|
||||
tx0, _, err := client.TransactionByHash(context.Background(), txHash0)
|
||||
assert.NoError(t, err)
|
||||
assert.Greater(t, tx0.Gas(), uint64(0))
|
||||
|
||||
// MinGasLimit = 100000
|
||||
txHash1, err := newSender.SendTransaction("1", &common.Address{}, big.NewInt(1), nil, 100000)
|
||||
assert.NoError(t, err)
|
||||
tx1, _, err := client.TransactionByHash(context.Background(), txHash1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tx1.Gas(), uint64(150000))
|
||||
}
|
||||
|
||||
func testBatchSender(t *testing.T, batchSize int) {
|
||||
@@ -88,7 +118,7 @@ func testBatchSender(t *testing.T, batchSize int) {
|
||||
for i := 0; i < TXBatch; i++ {
|
||||
toAddr := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
|
||||
id := strconv.Itoa(i + index*1000)
|
||||
_, err := newSender.SendTransaction(id, &toAddr, big.NewInt(1), nil)
|
||||
_, err := newSender.SendTransaction(id, &toAddr, big.NewInt(1), nil, 0)
|
||||
if errors.Is(err, sender.ErrNoAvailableAccount) {
|
||||
<-time.After(time.Second)
|
||||
continue
|
||||
|
||||
@@ -26,11 +26,7 @@ var (
|
||||
|
||||
// private key
|
||||
privateKey *ecdsa.PrivateKey
|
||||
|
||||
// docker consider handler.
|
||||
l1gethImg docker.ImgInstance
|
||||
l2gethImg docker.ImgInstance
|
||||
dbImg docker.ImgInstance
|
||||
base *docker.App
|
||||
|
||||
// clients
|
||||
l1Client *ethclient.Client
|
||||
@@ -53,6 +49,14 @@ var (
|
||||
l2MessengerAddress common.Address
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
base = docker.NewDockerApp()
|
||||
|
||||
m.Run()
|
||||
|
||||
base.Free()
|
||||
}
|
||||
|
||||
func setupEnv(t *testing.T) {
|
||||
var err error
|
||||
privateKey, err = crypto.ToECDSA(common.FromHex("1212121212121212121212121212121212121212121212121212121212121212"))
|
||||
@@ -75,20 +79,18 @@ func setupEnv(t *testing.T) {
|
||||
cfg.L2Config.RelayerConfig.MessageSenderPrivateKeys = []*ecdsa.PrivateKey{messagePrivateKey}
|
||||
cfg.L2Config.RelayerConfig.RollupSenderPrivateKeys = []*ecdsa.PrivateKey{rollupPrivateKey}
|
||||
cfg.L2Config.RelayerConfig.GasOracleSenderPrivateKeys = []*ecdsa.PrivateKey{gasOraclePrivateKey}
|
||||
base.RunImages(t)
|
||||
|
||||
// Create l1geth container.
|
||||
l1gethImg = docker.NewTestL1Docker(t)
|
||||
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = l1gethImg.Endpoint()
|
||||
cfg.L1Config.Endpoint = l1gethImg.Endpoint()
|
||||
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
|
||||
cfg.L1Config.Endpoint = base.L1GethEndpoint()
|
||||
|
||||
// Create l2geth container.
|
||||
l2gethImg = docker.NewTestL2Docker(t)
|
||||
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
|
||||
cfg.L2Config.Endpoint = l2gethImg.Endpoint()
|
||||
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
|
||||
cfg.L2Config.Endpoint = base.L2GethEndpoint()
|
||||
|
||||
// Create db container.
|
||||
dbImg = docker.NewTestDBDocker(t, cfg.DBConfig.DriverName)
|
||||
cfg.DBConfig.DSN = dbImg.Endpoint()
|
||||
cfg.DBConfig.DSN = base.DBEndpoint()
|
||||
|
||||
// Create l1geth and l2geth client.
|
||||
l1Client, err = ethclient.Dial(cfg.L1Config.Endpoint)
|
||||
@@ -144,18 +146,6 @@ func transferEther(t *testing.T, auth *bind.TransactOpts, client *ethclient.Clie
|
||||
}
|
||||
}
|
||||
|
||||
func free(t *testing.T) {
|
||||
if dbImg != nil {
|
||||
assert.NoError(t, dbImg.Stop())
|
||||
}
|
||||
if l1gethImg != nil {
|
||||
assert.NoError(t, l1gethImg.Stop())
|
||||
}
|
||||
if l2gethImg != nil {
|
||||
assert.NoError(t, l2gethImg.Stop())
|
||||
}
|
||||
}
|
||||
|
||||
func prepareContracts(t *testing.T) {
|
||||
var err error
|
||||
var tx *types.Transaction
|
||||
@@ -217,7 +207,4 @@ func TestFunction(t *testing.T) {
|
||||
t.Run("TestImportL1GasPrice", testImportL1GasPrice)
|
||||
t.Run("TestImportL2GasPrice", testImportL2GasPrice)
|
||||
|
||||
t.Cleanup(func() {
|
||||
free(t)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -97,8 +97,7 @@ func testImportL2GasPrice(t *testing.T) {
|
||||
StorageTrace: &geth_types.StorageTrace{},
|
||||
},
|
||||
}
|
||||
err = db.InsertL2BlockTraces(traces)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.InsertL2BlockTraces(traces))
|
||||
|
||||
parentBatch := &types.BlockBatch{
|
||||
Index: 0,
|
||||
|
||||
@@ -76,8 +76,7 @@ func testRelayL2MessageSucceed(t *testing.T) {
|
||||
StorageTrace: &geth_types.StorageTrace{},
|
||||
},
|
||||
}
|
||||
err = db.InsertL2BlockTraces(traces)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.InsertL2BlockTraces(traces))
|
||||
|
||||
parentBatch := &types.BlockBatch{
|
||||
Index: 0,
|
||||
|
||||
@@ -54,8 +54,7 @@ func testCommitBatchAndFinalizeBatch(t *testing.T) {
|
||||
})
|
||||
parentHash = header.Hash()
|
||||
}
|
||||
err = db.InsertL2BlockTraces(traces)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.InsertL2BlockTraces(traces))
|
||||
|
||||
parentBatch := &types.BlockBatch{
|
||||
Index: 0,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
cmap "github.com/orcaman/concurrent-map"
|
||||
)
|
||||
@@ -23,8 +23,6 @@ type checkFunc func(buf string)
|
||||
|
||||
// Cmd struct
|
||||
type Cmd struct {
|
||||
*testing.T
|
||||
|
||||
name string
|
||||
args []string
|
||||
|
||||
@@ -38,9 +36,8 @@ type Cmd struct {
|
||||
}
|
||||
|
||||
// NewCmd create Cmd instance.
|
||||
func NewCmd(t *testing.T, name string, args ...string) *Cmd {
|
||||
func NewCmd(name string, args ...string) *Cmd {
|
||||
return &Cmd{
|
||||
T: t,
|
||||
checkFuncs: cmap.New(),
|
||||
name: name,
|
||||
args: args,
|
||||
@@ -48,40 +45,40 @@ func NewCmd(t *testing.T, name string, args ...string) *Cmd {
|
||||
}
|
||||
|
||||
// RegistFunc register check func
|
||||
func (t *Cmd) RegistFunc(key string, check checkFunc) {
|
||||
t.checkFuncs.Set(key, check)
|
||||
func (c *Cmd) RegistFunc(key string, check checkFunc) {
|
||||
c.checkFuncs.Set(key, check)
|
||||
}
|
||||
|
||||
// UnRegistFunc unregister check func
|
||||
func (t *Cmd) UnRegistFunc(key string) {
|
||||
t.checkFuncs.Pop(key)
|
||||
func (c *Cmd) UnRegistFunc(key string) {
|
||||
c.checkFuncs.Pop(key)
|
||||
}
|
||||
|
||||
func (t *Cmd) runCmd() {
|
||||
cmd := exec.Command(t.args[0], t.args[1:]...) //nolint:gosec
|
||||
cmd.Stdout = t
|
||||
cmd.Stderr = t
|
||||
func (c *Cmd) runCmd() {
|
||||
cmd := exec.Command(c.args[0], c.args[1:]...) //nolint:gosec
|
||||
cmd.Stdout = c
|
||||
cmd.Stderr = c
|
||||
_ = cmd.Run()
|
||||
}
|
||||
|
||||
// RunCmd parallel running when parallel is true.
|
||||
func (t *Cmd) RunCmd(parallel bool) {
|
||||
t.Log("cmd: ", t.args)
|
||||
func (c *Cmd) RunCmd(parallel bool) {
|
||||
fmt.Println("cmd: ", c.args)
|
||||
if parallel {
|
||||
go t.runCmd()
|
||||
go c.runCmd()
|
||||
} else {
|
||||
t.runCmd()
|
||||
c.runCmd()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Cmd) Write(data []byte) (int, error) {
|
||||
func (c *Cmd) Write(data []byte) (int, error) {
|
||||
out := string(data)
|
||||
if verbose {
|
||||
t.Logf("%s: %v", t.name, out)
|
||||
fmt.Printf("%s: %v", c.name, out)
|
||||
} else if strings.Contains(out, "error") || strings.Contains(out, "warning") {
|
||||
t.Logf("%s: %v", t.name, out)
|
||||
fmt.Printf("%s: %v", c.name, out)
|
||||
}
|
||||
go t.checkFuncs.IterCb(func(_ string, value interface{}) {
|
||||
go c.checkFuncs.IterCb(func(_ string, value interface{}) {
|
||||
check := value.(checkFunc)
|
||||
check(out)
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
@@ -13,13 +14,13 @@ import (
|
||||
|
||||
// RunApp exec's the current binary using name as argv[0] which will trigger the
|
||||
// reexec init function for that name (e.g. "geth-test" in cmd/geth/run_test.go)
|
||||
func (t *Cmd) RunApp(waitResult func() bool) {
|
||||
t.Log("cmd: ", append([]string{t.name}, t.args...))
|
||||
func (c *Cmd) RunApp(waitResult func() bool) {
|
||||
fmt.Println("cmd: ", append([]string{c.name}, c.args...))
|
||||
cmd := &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: append([]string{t.name}, t.args...),
|
||||
Stderr: t,
|
||||
Stdout: t,
|
||||
Args: append([]string{c.name}, c.args...),
|
||||
Stderr: c,
|
||||
Stdout: c,
|
||||
}
|
||||
if waitResult != nil {
|
||||
go func() {
|
||||
@@ -30,38 +31,39 @@ func (t *Cmd) RunApp(waitResult func() bool) {
|
||||
_ = cmd.Run()
|
||||
}
|
||||
|
||||
t.mu.Lock()
|
||||
t.cmd = cmd
|
||||
t.mu.Unlock()
|
||||
c.mu.Lock()
|
||||
c.cmd = cmd
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// WaitExit wait util process exit.
|
||||
func (t *Cmd) WaitExit() {
|
||||
func (c *Cmd) WaitExit() {
|
||||
// Wait all the check funcs are finished or test status is failed.
|
||||
for !(t.Failed() || t.checkFuncs.IsEmpty()) {
|
||||
for !(c.Err != nil || c.checkFuncs.IsEmpty()) {
|
||||
<-time.After(time.Millisecond * 500)
|
||||
}
|
||||
|
||||
// Send interrupt signal.
|
||||
t.mu.Lock()
|
||||
_ = t.cmd.Process.Signal(os.Interrupt)
|
||||
t.mu.Unlock()
|
||||
c.mu.Lock()
|
||||
_ = c.cmd.Process.Signal(os.Interrupt)
|
||||
_, _ = c.cmd.Process.Wait()
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// Interrupt send interrupt signal.
|
||||
func (t *Cmd) Interrupt() {
|
||||
t.mu.Lock()
|
||||
t.Err = t.cmd.Process.Signal(os.Interrupt)
|
||||
t.mu.Unlock()
|
||||
func (c *Cmd) Interrupt() {
|
||||
c.mu.Lock()
|
||||
c.Err = c.cmd.Process.Signal(os.Interrupt)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// WaitResult return true when get the keyword during timeout.
|
||||
func (t *Cmd) WaitResult(timeout time.Duration, keyword string) bool {
|
||||
func (c *Cmd) WaitResult(t *testing.T, timeout time.Duration, keyword string) bool {
|
||||
if keyword == "" {
|
||||
return false
|
||||
}
|
||||
okCh := make(chan struct{}, 1)
|
||||
t.RegistFunc(keyword, func(buf string) {
|
||||
c.RegistFunc(keyword, func(buf string) {
|
||||
if strings.Contains(buf, keyword) {
|
||||
select {
|
||||
case okCh <- struct{}{}:
|
||||
@@ -70,7 +72,7 @@ func (t *Cmd) WaitResult(timeout time.Duration, keyword string) bool {
|
||||
}
|
||||
}
|
||||
})
|
||||
defer t.UnRegistFunc(keyword)
|
||||
defer c.UnRegistFunc(keyword)
|
||||
select {
|
||||
case <-okCh:
|
||||
return true
|
||||
@@ -81,12 +83,12 @@ func (t *Cmd) WaitResult(timeout time.Duration, keyword string) bool {
|
||||
}
|
||||
|
||||
// ExpectWithTimeout wait result during timeout time.
|
||||
func (t *Cmd) ExpectWithTimeout(parallel bool, timeout time.Duration, keyword string) {
|
||||
func (c *Cmd) ExpectWithTimeout(t *testing.T, parallel bool, timeout time.Duration, keyword string) {
|
||||
if keyword == "" {
|
||||
return
|
||||
}
|
||||
okCh := make(chan struct{}, 1)
|
||||
t.RegistFunc(keyword, func(buf string) {
|
||||
c.RegistFunc(keyword, func(buf string) {
|
||||
if strings.Contains(buf, keyword) {
|
||||
select {
|
||||
case okCh <- struct{}{}:
|
||||
@@ -97,7 +99,7 @@ func (t *Cmd) ExpectWithTimeout(parallel bool, timeout time.Duration, keyword st
|
||||
})
|
||||
|
||||
waitResult := func() {
|
||||
defer t.UnRegistFunc(keyword)
|
||||
defer c.UnRegistFunc(keyword)
|
||||
select {
|
||||
case <-okCh:
|
||||
return
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestCmd(t *testing.T) {
|
||||
app := cmd.NewCmd(t, "curTime", "date", "+%Y-%m-%d")
|
||||
app := cmd.NewCmd("curTime", "date", "+%Y-%m-%d")
|
||||
|
||||
tm := time.Now()
|
||||
curTime := fmt.Sprintf("%d-%02d-%02d", tm.Year(), tm.Month(), tm.Day())
|
||||
|
||||
234
common/docker/docker_app.go
Normal file
234
common/docker/docker_app.go
Normal file
@@ -0,0 +1,234 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/modern-go/reflect2"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"scroll-tech/database"
|
||||
|
||||
"scroll-tech/common/cmd"
|
||||
"scroll-tech/common/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
l1StartPort = 10000
|
||||
l2StartPort = 20000
|
||||
dbStartPort = 30000
|
||||
)
|
||||
|
||||
// App is collection struct of runtime docker images
|
||||
type App struct {
|
||||
l1gethImg ImgInstance
|
||||
l2gethImg ImgInstance
|
||||
|
||||
dbImg ImgInstance
|
||||
dbConfig *database.DBConfig
|
||||
dbFile string
|
||||
|
||||
// common time stamp.
|
||||
timestamp int
|
||||
}
|
||||
|
||||
// NewDockerApp returns new instance of dokerApp struct
|
||||
func NewDockerApp() *App {
|
||||
timestamp := time.Now().Nanosecond()
|
||||
return &App{
|
||||
timestamp: timestamp,
|
||||
dbFile: fmt.Sprintf("/tmp/%d_db-config.json", timestamp),
|
||||
}
|
||||
}
|
||||
|
||||
// RunImages runs all images togather
|
||||
func (b *App) RunImages(t *testing.T) {
|
||||
b.runDBImage(t)
|
||||
b.runL1Geth(t)
|
||||
b.runL2Geth(t)
|
||||
}
|
||||
|
||||
func (b *App) runDBImage(t *testing.T) {
|
||||
if b.dbImg != nil {
|
||||
return
|
||||
}
|
||||
b.dbImg = newTestDBDocker(t, "postgres")
|
||||
if err := b.mockDBConfig(); err != nil {
|
||||
_ = b.dbImg.Stop()
|
||||
b.dbImg = nil
|
||||
_ = os.Remove(b.dbFile)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// RunDBApp runs DB app with command
|
||||
func (b *App) RunDBApp(t *testing.T, option, keyword string) {
|
||||
args := []string{option, "--config", b.dbFile}
|
||||
app := cmd.NewCmd("db_cli-test", args...)
|
||||
defer app.WaitExit()
|
||||
|
||||
// Wait expect result.
|
||||
app.ExpectWithTimeout(t, true, time.Second*3, keyword)
|
||||
app.RunApp(nil)
|
||||
}
|
||||
|
||||
// Free clear all running images
|
||||
func (b *App) Free() {
|
||||
if b.l1gethImg != nil {
|
||||
_ = b.l1gethImg.Stop()
|
||||
b.l1gethImg = nil
|
||||
}
|
||||
if b.l2gethImg != nil {
|
||||
_ = b.l2gethImg.Stop()
|
||||
b.l2gethImg = nil
|
||||
}
|
||||
if b.dbImg != nil {
|
||||
_ = b.dbImg.Stop()
|
||||
b.dbImg = nil
|
||||
_ = os.Remove(b.dbFile)
|
||||
}
|
||||
}
|
||||
|
||||
// L1GethEndpoint returns l1gethimg endpoint
|
||||
func (b *App) L1GethEndpoint() string {
|
||||
if b.l1gethImg != nil {
|
||||
return b.l1gethImg.Endpoint()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// L2GethEndpoint returns l2gethimg endpoint
|
||||
func (b *App) L2GethEndpoint() string {
|
||||
if b.l2gethImg != nil {
|
||||
return b.l2gethImg.Endpoint()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// DBEndpoint returns the endpoint of the dbimg
|
||||
func (b *App) DBEndpoint() string {
|
||||
return b.dbImg.Endpoint()
|
||||
}
|
||||
|
||||
func (b *App) runL1Geth(t *testing.T) {
|
||||
if b.l1gethImg != nil {
|
||||
return
|
||||
}
|
||||
b.l1gethImg = newTestL1Docker(t)
|
||||
}
|
||||
|
||||
// L1Client returns a ethclient by dialing running l1geth
|
||||
func (b *App) L1Client() (*ethclient.Client, error) {
|
||||
if b.l1gethImg == nil || reflect2.IsNil(b.l1gethImg) {
|
||||
return nil, fmt.Errorf("l1 geth is not running")
|
||||
}
|
||||
client, err := ethclient.Dial(b.l1gethImg.Endpoint())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (b *App) runL2Geth(t *testing.T) {
|
||||
if b.l2gethImg != nil {
|
||||
return
|
||||
}
|
||||
b.l2gethImg = newTestL2Docker(t)
|
||||
}
|
||||
|
||||
// L2Client returns a ethclient by dialing running l2geth
|
||||
func (b *App) L2Client() (*ethclient.Client, error) {
|
||||
if b.l2gethImg == nil || reflect2.IsNil(b.l2gethImg) {
|
||||
return nil, fmt.Errorf("l2 geth is not running")
|
||||
}
|
||||
client, err := ethclient.Dial(b.l2gethImg.Endpoint())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (b *App) mockDBConfig() error {
|
||||
if b.dbConfig == nil {
|
||||
|
||||
b.dbConfig = &database.DBConfig{
|
||||
DSN: "",
|
||||
DriverName: "postgres",
|
||||
MaxOpenNum: 200,
|
||||
MaxIdleNum: 20,
|
||||
}
|
||||
}
|
||||
|
||||
if b.dbImg != nil {
|
||||
b.dbConfig.DSN = b.dbImg.Endpoint()
|
||||
}
|
||||
data, err := json.Marshal(b.dbConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(b.dbFile, data, 0644) //nolint:gosec
|
||||
}
|
||||
|
||||
func newTestL1Docker(t *testing.T) ImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
imgL1geth := NewImgGeth("scroll_l1geth", "", "", 0, l1StartPort+int(id.Int64()))
|
||||
assert.NoError(t, imgL1geth.Start())
|
||||
|
||||
// try 3 times to get chainID until is ok.
|
||||
utils.TryTimes(3, func() bool {
|
||||
client, _ := ethclient.Dial(imgL1geth.Endpoint())
|
||||
if client != nil {
|
||||
if _, err := client.ChainID(context.Background()); err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
return imgL1geth
|
||||
}
|
||||
|
||||
func newTestL2Docker(t *testing.T) ImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
imgL2geth := NewImgGeth("scroll_l2geth", "", "", 0, l2StartPort+int(id.Int64()))
|
||||
assert.NoError(t, imgL2geth.Start())
|
||||
|
||||
// try 3 times to get chainID until is ok.
|
||||
utils.TryTimes(3, func() bool {
|
||||
client, _ := ethclient.Dial(imgL2geth.Endpoint())
|
||||
if client != nil {
|
||||
if _, err := client.ChainID(context.Background()); err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
return imgL2geth
|
||||
}
|
||||
|
||||
func newTestDBDocker(t *testing.T, driverName string) ImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
imgDB := NewImgDB(driverName, "123456", "test_db", dbStartPort+int(id.Int64()))
|
||||
assert.NoError(t, imgDB.Start())
|
||||
|
||||
// try 5 times until the db is ready.
|
||||
utils.TryTimes(5, func() bool {
|
||||
db, _ := sqlx.Open(driverName, imgDB.Endpoint())
|
||||
if db != nil {
|
||||
return db.Ping() == nil
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
return imgDB
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -28,7 +27,7 @@ type ImgDB struct {
|
||||
}
|
||||
|
||||
// NewImgDB return postgres db img instance.
|
||||
func NewImgDB(t *testing.T, image, password, dbName string, port int) ImgInstance {
|
||||
func NewImgDB(image, password, dbName string, port int) ImgInstance {
|
||||
img := &ImgDB{
|
||||
image: image,
|
||||
name: fmt.Sprintf("%s-%s_%d", image, dbName, port),
|
||||
@@ -36,7 +35,7 @@ func NewImgDB(t *testing.T, image, password, dbName string, port int) ImgInstanc
|
||||
dbName: dbName,
|
||||
port: port,
|
||||
}
|
||||
img.cmd = cmd.NewCmd(t, img.name, img.prepare()...)
|
||||
img.cmd = cmd.NewCmd(img.name, img.prepare()...)
|
||||
return img
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -30,7 +29,7 @@ type ImgGeth struct {
|
||||
}
|
||||
|
||||
// NewImgGeth return geth img instance.
|
||||
func NewImgGeth(t *testing.T, image, volume, ipc string, hPort, wPort int) ImgInstance {
|
||||
func NewImgGeth(image, volume, ipc string, hPort, wPort int) ImgInstance {
|
||||
img := &ImgGeth{
|
||||
image: image,
|
||||
name: fmt.Sprintf("%s-%d", image, time.Now().Nanosecond()),
|
||||
@@ -39,7 +38,7 @@ func NewImgGeth(t *testing.T, image, volume, ipc string, hPort, wPort int) ImgIn
|
||||
httpPort: hPort,
|
||||
wsPort: wPort,
|
||||
}
|
||||
img.cmd = cmd.NewCmd(t, img.name, img.prepare()...)
|
||||
img.cmd = cmd.NewCmd(img.name, img.prepare()...)
|
||||
return img
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package docker
|
||||
package docker_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -6,13 +6,36 @@ import (
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/lib/pq" //nolint:golint
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
_ "scroll-tech/database/cmd/app"
|
||||
|
||||
"scroll-tech/common/docker"
|
||||
)
|
||||
|
||||
func TestDocker(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
base *docker.App
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
base = docker.NewDockerApp()
|
||||
|
||||
m.Run()
|
||||
|
||||
base.Free()
|
||||
}
|
||||
|
||||
func TestStartProcess(t *testing.T) {
|
||||
base.RunImages(t)
|
||||
|
||||
// migrate db.
|
||||
base.RunDBApp(t, "reset", "successful to reset")
|
||||
base.RunDBApp(t, "migrate", "current version:")
|
||||
}
|
||||
|
||||
func TestDocker(t *testing.T) {
|
||||
base.RunImages(t)
|
||||
t.Parallel()
|
||||
t.Run("testL1Geth", testL1Geth)
|
||||
t.Run("testL2Geth", testL2Geth)
|
||||
t.Run("testDB", testDB)
|
||||
@@ -22,10 +45,7 @@ func testL1Geth(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
img := NewTestL1Docker(t)
|
||||
defer img.Stop()
|
||||
|
||||
client, err := ethclient.Dial(img.Endpoint())
|
||||
client, err := base.L1Client()
|
||||
assert.NoError(t, err)
|
||||
|
||||
chainID, err := client.ChainID(ctx)
|
||||
@@ -37,10 +57,7 @@ func testL2Geth(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
img := NewTestL2Docker(t)
|
||||
defer img.Stop()
|
||||
|
||||
client, err := ethclient.Dial(img.Endpoint())
|
||||
client, err := base.L2Client()
|
||||
assert.NoError(t, err)
|
||||
|
||||
chainID, err := client.ChainID(ctx)
|
||||
@@ -50,10 +67,8 @@ func testL2Geth(t *testing.T) {
|
||||
|
||||
func testDB(t *testing.T) {
|
||||
driverName := "postgres"
|
||||
dbImg := NewTestDBDocker(t, driverName)
|
||||
defer dbImg.Stop()
|
||||
|
||||
db, err := sqlx.Open(driverName, dbImg.Endpoint())
|
||||
db, err := sqlx.Open(driverName, base.DBEndpoint())
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.Ping())
|
||||
}
|
||||
|
||||
@@ -11,6 +11,6 @@ if [ ! -n "${IPC_PATH}" ];then
|
||||
IPC_PATH="/tmp/l1geth_path.ipc"
|
||||
fi
|
||||
|
||||
exec geth --mine --datadir "." --unlock 0 --password "./password" --allow-insecure-unlock --nodiscover \
|
||||
exec geth --mine --datadir "." --unlock 0 --miner.etherbase "0x1c5a77d9fa7ef466951b2f01f724bca3a5820b63" --password "./password" --allow-insecure-unlock --nodiscover \
|
||||
--http --http.addr "0.0.0.0" --http.port 8545 --ws --ws.addr "0.0.0.0" --ws.port 8546 --ipcpath ${IPC_PATH}
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/scroll-tech/go-ethereum/ethclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"scroll-tech/common/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
l1StartPort = 10000
|
||||
l2StartPort = 20000
|
||||
dbStartPort = 30000
|
||||
)
|
||||
|
||||
// NewTestL1Docker starts and returns l1geth docker
|
||||
func NewTestL1Docker(t *testing.T) ImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
imgL1geth := NewImgGeth(t, "scroll_l1geth", "", "", 0, l1StartPort+int(id.Int64()))
|
||||
assert.NoError(t, imgL1geth.Start())
|
||||
|
||||
// try 3 times to get chainID until is ok.
|
||||
utils.TryTimes(3, func() bool {
|
||||
client, _ := ethclient.Dial(imgL1geth.Endpoint())
|
||||
if client != nil {
|
||||
if _, err := client.ChainID(context.Background()); err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
return imgL1geth
|
||||
}
|
||||
|
||||
// NewTestL2Docker starts and returns l2geth docker
|
||||
func NewTestL2Docker(t *testing.T) ImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
imgL2geth := NewImgGeth(t, "scroll_l2geth", "", "", 0, l2StartPort+int(id.Int64()))
|
||||
assert.NoError(t, imgL2geth.Start())
|
||||
|
||||
// try 3 times to get chainID until is ok.
|
||||
utils.TryTimes(3, func() bool {
|
||||
client, _ := ethclient.Dial(imgL2geth.Endpoint())
|
||||
if client != nil {
|
||||
if _, err := client.ChainID(context.Background()); err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
return imgL2geth
|
||||
}
|
||||
|
||||
// NewTestDBDocker starts and returns database docker
|
||||
func NewTestDBDocker(t *testing.T, driverName string) ImgInstance {
|
||||
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
|
||||
imgDB := NewImgDB(t, driverName, "123456", "test_db", dbStartPort+int(id.Int64()))
|
||||
assert.NoError(t, imgDB.Start())
|
||||
|
||||
// try 5 times until the db is ready.
|
||||
utils.TryTimes(5, func() bool {
|
||||
db, _ := sqlx.Open(driverName, imgDB.Endpoint())
|
||||
if db != nil {
|
||||
return db.Ping() == nil
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
return imgDB
|
||||
}
|
||||
@@ -8,9 +8,10 @@ require (
|
||||
github.com/lib/pq v1.10.6
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-isatty v0.0.16
|
||||
github.com/modern-go/reflect2 v1.0.2
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230220082843-ec9254b0b1c6
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230321020420-127af384ed04
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa
|
||||
gotest.tools v2.2.0+incompatible
|
||||
)
|
||||
@@ -28,7 +29,7 @@ require (
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||
github.com/ethereum/go-ethereum v1.11.1 // indirect
|
||||
github.com/ethereum/go-ethereum v1.11.4 // indirect
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
@@ -45,7 +46,7 @@ require (
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.2.0 // indirect
|
||||
github.com/huin/goupnp v1.0.3 // indirect
|
||||
github.com/iden3/go-iden3-crypto v0.0.13 // indirect
|
||||
github.com/iden3/go-iden3-crypto v0.0.14 // indirect
|
||||
github.com/influxdata/influxdb v1.8.3 // indirect
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||
@@ -67,7 +68,7 @@ require (
|
||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/scroll-tech/zktrie v0.5.0 // indirect
|
||||
github.com/scroll-tech/zktrie v0.5.2 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/status-im/keycard-go v0.2.0 // indirect
|
||||
@@ -77,14 +78,15 @@ require (
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.6.0 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.6.0 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
||||
golang.org/x/tools v0.3.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
||||
141
common/go.sum
141
common/go.sum
@@ -18,28 +18,14 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
|
||||
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
|
||||
github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o=
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
@@ -50,15 +36,6 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM=
|
||||
github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||
@@ -75,7 +52,6 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f
|
||||
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
@@ -84,13 +60,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
||||
github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=
|
||||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
@@ -98,8 +69,6 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI=
|
||||
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
||||
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
|
||||
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
|
||||
github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=
|
||||
@@ -108,27 +77,21 @@ github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRk
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmXWsl/FEet9Uswog=
|
||||
github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
|
||||
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ethereum/go-ethereum v1.10.13/go.mod h1:W3yfrFyL9C1pHcwY5hmRHVDaorTiQxhYBkKyu5mEDHw=
|
||||
github.com/ethereum/go-ethereum v1.11.1 h1:EMymmWFzpS7G9l9NvVN8G73cgdUIqDPNRf2YTSGBXlk=
|
||||
github.com/ethereum/go-ethereum v1.11.1/go.mod h1:DuefStAgaxoaYGLR0FueVcVbehmn5n9QUcVrMCuOvuc=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/ethereum/go-ethereum v1.11.4 h1:KG81SnUHXWk8LJB3mBcHg/E2yLvXoiPmRMCIRxgx3cE=
|
||||
github.com/ethereum/go-ethereum v1.11.4/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo=
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
@@ -151,12 +114,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
@@ -185,7 +146,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
@@ -198,28 +158,22 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
||||
github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0=
|
||||
github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
||||
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
|
||||
@@ -233,14 +187,12 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU
|
||||
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
|
||||
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
|
||||
github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/iden3/go-iden3-crypto v0.0.12/go.mod h1:swXIv0HFbJKobbQBtsB50G7IHr6PbTowutSew/iBEoo=
|
||||
github.com/iden3/go-iden3-crypto v0.0.13 h1:ixWRiaqDULNyIDdOWz2QQJG5t4PpNHkQk2P6GV94cok=
|
||||
github.com/iden3/go-iden3-crypto v0.0.13/go.mod h1:swXIv0HFbJKobbQBtsB50G7IHr6PbTowutSew/iBEoo=
|
||||
github.com/iden3/go-iden3-crypto v0.0.14 h1:HQnFchY735JRNQxof6n/Vbyon4owj4+Ku+LNAamWV6c=
|
||||
github.com/iden3/go-iden3-crypto v0.0.14/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=
|
||||
github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8=
|
||||
@@ -256,13 +208,9 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y
|
||||
github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=
|
||||
github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=
|
||||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
@@ -275,7 +223,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
||||
github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
@@ -292,12 +239,9 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
|
||||
@@ -311,8 +255,6 @@ github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
@@ -337,12 +279,12 @@ github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA
|
||||
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
@@ -399,20 +341,17 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230220082843-ec9254b0b1c6 h1:2kXWJR+mOj09HBh5sUTb4L/OURPSXoQd1NC/10v7otM=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230220082843-ec9254b0b1c6/go.mod h1:eW+eyNdMoO0MyuczCc9xWSnW8dPJ0kOy5xsxgOKYEaA=
|
||||
github.com/scroll-tech/zktrie v0.5.0 h1:dABDR6lMZq6Hs+fWQSiHbX8s3AOX6hY+5nkhSYm5rmU=
|
||||
github.com/scroll-tech/zktrie v0.5.0/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230321020420-127af384ed04 h1:PpI31kaBVm6+7sZtyK03Ex0QIg3P821Ktae0FHFh7IM=
|
||||
github.com/scroll-tech/go-ethereum v1.10.14-0.20230321020420-127af384ed04/go.mod h1:jH8c08L9K8Hieaf0r/ur2P/cpesn4dFhmLm2Mmoi8kI=
|
||||
github.com/scroll-tech/zktrie v0.5.2 h1:U34jPXMLGOlRHfdvYp5VVgOcC0RuPeJmcS3bWotCWiY=
|
||||
github.com/scroll-tech/zktrie v0.5.2/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
@@ -422,12 +361,12 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
||||
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
|
||||
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
@@ -435,21 +374,18 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
||||
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
|
||||
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q=
|
||||
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
@@ -474,15 +410,12 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -511,9 +444,8 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -535,13 +467,8 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -553,10 +480,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -592,34 +517,22 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -656,8 +569,8 @@ golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
|
||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -715,16 +628,13 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
|
||||
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
@@ -741,6 +651,5 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
4
common/libzkp/impl/Cargo.lock
generated
4
common/libzkp/impl/Cargo.lock
generated
@@ -5014,7 +5014,7 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||
[[package]]
|
||||
name = "types"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/scroll-zkevm?branch=goerli-0215#a090be6f603f58f9e1fb9cf500834fa2e51e0ca9"
|
||||
source = "git+https://github.com/scroll-tech/scroll-zkevm?branch=goerli-0215#1f7a3c7da2370860087555a11346bd5d96f609fd"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"blake2",
|
||||
@@ -5682,7 +5682,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "zkevm"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/scroll-tech/scroll-zkevm?branch=goerli-0215#a090be6f603f58f9e1fb9cf500834fa2e51e0ca9"
|
||||
source = "git+https://github.com/scroll-tech/scroll-zkevm?branch=goerli-0215#1f7a3c7da2370860087555a11346bd5d96f609fd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"blake2",
|
||||
|
||||
@@ -10,12 +10,16 @@ import (
|
||||
"github.com/scroll-tech/go-ethereum/metrics"
|
||||
"github.com/scroll-tech/go-ethereum/metrics/prometheus"
|
||||
"github.com/scroll-tech/go-ethereum/rpc"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"scroll-tech/common/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
// ScrollRegistry is used for scroll metrics.
|
||||
ScrollRegistry = metrics.NewRegistry()
|
||||
)
|
||||
|
||||
// Serve starts the metrics server on the given address, will be closed when the given
|
||||
// context is canceled.
|
||||
func Serve(ctx context.Context, c *cli.Context) {
|
||||
@@ -30,7 +34,7 @@ func Serve(ctx context.Context, c *cli.Context) {
|
||||
|
||||
server := &http.Server{
|
||||
Addr: address,
|
||||
Handler: prometheus.Handler(metrics.DefaultRegistry),
|
||||
Handler: prometheus.Handler(ScrollRegistry),
|
||||
ReadTimeout: rpc.DefaultHTTPTimeouts.ReadTimeout,
|
||||
WriteTimeout: rpc.DefaultHTTPTimeouts.WriteTimeout,
|
||||
IdleTimeout: rpc.DefaultHTTPTimeouts.IdleTimeout,
|
||||
|
||||
@@ -57,7 +57,7 @@ var (
|
||||
Name: "metrics.addr",
|
||||
Usage: "Metrics reporting server listening address",
|
||||
Category: "METRICS",
|
||||
Value: "0.0.0.0",
|
||||
Value: "127.0.0.1",
|
||||
}
|
||||
// MetricsPort is listening port of Metrics reporting server
|
||||
MetricsPort = cli.IntFlag{
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package utils
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TryTimes try run several times until the function return true.
|
||||
func TryTimes(times int, run func() bool) {
|
||||
@@ -11,3 +14,31 @@ func TryTimes(times int, run func() bool) {
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
}
|
||||
}
|
||||
|
||||
// LoopWithContext Run the f func with context periodically.
|
||||
func LoopWithContext(ctx context.Context, period time.Duration, f func(ctx context.Context)) {
|
||||
tick := time.NewTicker(period)
|
||||
defer tick.Stop()
|
||||
for ; ; <-tick.C {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
f(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop Run the f func periodically.
|
||||
func Loop(ctx context.Context, period time.Duration, f func()) {
|
||||
tick := time.NewTicker(period)
|
||||
defer tick.Stop()
|
||||
for ; ; <-tick.C {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
f()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
51
common/utils/workerpool/workerpool.go
Normal file
51
common/utils/workerpool/workerpool.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package workerpool
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// WorkerPool is responsible for creating workers and managing verify proof task between them
|
||||
type WorkerPool struct {
|
||||
maxWorker int
|
||||
taskQueueChan chan func()
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewWorkerPool creates new worker pool with given amount of workers
|
||||
func NewWorkerPool(maxWorker int) *WorkerPool {
|
||||
return &WorkerPool{
|
||||
maxWorker: maxWorker,
|
||||
taskQueueChan: nil,
|
||||
wg: sync.WaitGroup{},
|
||||
}
|
||||
}
|
||||
|
||||
// Run runs WorkerPool
|
||||
func (vwp *WorkerPool) Run() {
|
||||
vwp.taskQueueChan = make(chan func())
|
||||
for i := 0; i < vwp.maxWorker; i++ {
|
||||
go func() {
|
||||
for task := range vwp.taskQueueChan {
|
||||
if task != nil {
|
||||
task()
|
||||
vwp.wg.Done()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stop WorkerPool
|
||||
func (vwp *WorkerPool) Stop() {
|
||||
vwp.wg.Wait()
|
||||
// close task queue channel, so that all goruotines listening from it stop
|
||||
close(vwp.taskQueueChan)
|
||||
}
|
||||
|
||||
// AddTask adds a task to WorkerPool
|
||||
func (vwp *WorkerPool) AddTask(task func()) {
|
||||
vwp.wg.Add(1)
|
||||
vwp.taskQueueChan <- task
|
||||
}
|
||||
57
common/utils/workerpool/workerpool_test.go
Normal file
57
common/utils/workerpool/workerpool_test.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package workerpool_test
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"scroll-tech/common/utils/workerpool"
|
||||
)
|
||||
|
||||
func TestWorkerPool(t *testing.T) {
|
||||
as := assert.New(t)
|
||||
|
||||
vwp := workerpool.NewWorkerPool(2)
|
||||
vwp.Run()
|
||||
var cnt int32 = 3
|
||||
|
||||
task := func() {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
atomic.AddInt32(&cnt, -1)
|
||||
}
|
||||
|
||||
go vwp.AddTask(task)
|
||||
go vwp.AddTask(task)
|
||||
go vwp.AddTask(task)
|
||||
|
||||
time.Sleep(600 * time.Millisecond)
|
||||
as.Equal(int32(1), atomic.LoadInt32(&cnt))
|
||||
vwp.Stop()
|
||||
as.Equal(int32(0), atomic.LoadInt32(&cnt))
|
||||
|
||||
}
|
||||
|
||||
func TestWorkerPoolStopAndStart(t *testing.T) {
|
||||
as := assert.New(t)
|
||||
vwp := workerpool.NewWorkerPool(1)
|
||||
var cnt int32 = 3
|
||||
|
||||
task := func() {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
atomic.AddInt32(&cnt, -1)
|
||||
}
|
||||
|
||||
vwp.Run()
|
||||
vwp.AddTask(task)
|
||||
vwp.AddTask(task)
|
||||
vwp.Stop()
|
||||
as.Equal(int32(1), atomic.LoadInt32(&cnt))
|
||||
|
||||
vwp.Run()
|
||||
vwp.AddTask(task)
|
||||
vwp.Stop()
|
||||
as.Equal(int32(0), atomic.LoadInt32(&cnt))
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var tag = "alpha-v1.13"
|
||||
var tag = "alpha-v2.3"
|
||||
|
||||
var commit = func() string {
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
|
||||
@@ -3,3 +3,6 @@ artifacts
|
||||
cache
|
||||
coverage*
|
||||
gasReporterOutput.json
|
||||
src/libraries/verifier/ZkTrieVerifier.sol
|
||||
src/libraries/verifier/PatriciaMerkleTrieVerifier.sol
|
||||
src/L2/predeploys/L1BlockContainer.sol
|
||||
|
||||
@@ -2,5 +2,17 @@
|
||||
"printWidth": 120,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"bracketSpacing": true
|
||||
"bracketSpacing": true,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "src/**/*.sol",
|
||||
"options": {
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
1
contracts/circomlib.d.ts
vendored
Normal file
1
contracts/circomlib.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module "circomlib/src/poseidon_gencontract";
|
||||
@@ -163,17 +163,6 @@ function owner() external view returns (address)
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### pause
|
||||
|
||||
```solidity
|
||||
function pause() external nonpayable
|
||||
```
|
||||
|
||||
Pause the contract
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
|
||||
### paused
|
||||
|
||||
```solidity
|
||||
@@ -264,6 +253,26 @@ The address of Rollup contract.
|
||||
|
||||
### sendMessage
|
||||
|
||||
```solidity
|
||||
function sendMessage(address _to, uint256 _value, bytes _message, uint256 _gasLimit, address _refundAddress) external payable
|
||||
```
|
||||
|
||||
Send cross chain message from L1 to L2 or L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
| _refundAddress | address | undefined |
|
||||
|
||||
### sendMessage
|
||||
|
||||
```solidity
|
||||
function sendMessage(address _to, uint256 _value, bytes _message, uint256 _gasLimit) external payable
|
||||
```
|
||||
@@ -281,6 +290,22 @@ Send cross chain message from L1 to L2 or L2 to L1.
|
||||
| _message | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### setPause
|
||||
|
||||
```solidity
|
||||
function setPause(bool _status) external nonpayable
|
||||
```
|
||||
|
||||
Pause the contract
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _status | bool | The pause status to update. |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
|
||||
@@ -212,17 +212,6 @@ function owner() external view returns (address)
|
||||
|---|---|---|
|
||||
| _0 | address | undefined |
|
||||
|
||||
### pause
|
||||
|
||||
```solidity
|
||||
function pause() external nonpayable
|
||||
```
|
||||
|
||||
Pause the contract
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
|
||||
### paused
|
||||
|
||||
```solidity
|
||||
@@ -294,6 +283,26 @@ function retryMessageWithProof(address _from, address _to, uint256 _value, uint2
|
||||
|
||||
### sendMessage
|
||||
|
||||
```solidity
|
||||
function sendMessage(address _to, uint256 _value, bytes _message, uint256 _gasLimit, address _refundAddress) external payable
|
||||
```
|
||||
|
||||
Send cross chain message from L1 to L2 or L2 to L1.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _to | address | undefined |
|
||||
| _value | uint256 | undefined |
|
||||
| _message | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
| _refundAddress | address | undefined |
|
||||
|
||||
### sendMessage
|
||||
|
||||
```solidity
|
||||
function sendMessage(address _to, uint256 _value, bytes _message, uint256 _gasLimit) external payable
|
||||
```
|
||||
@@ -311,6 +320,22 @@ Send cross chain message from L1 to L2 or L2 to L1.
|
||||
| _message | bytes | undefined |
|
||||
| _gasLimit | uint256 | undefined |
|
||||
|
||||
### setPause
|
||||
|
||||
```solidity
|
||||
function setPause(bool _status) external nonpayable
|
||||
```
|
||||
|
||||
Pause the contract
|
||||
|
||||
*This function can only called by contract owner.*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _status | bool | The pause status to update. |
|
||||
|
||||
### transferOwnership
|
||||
|
||||
```solidity
|
||||
|
||||
416
contracts/integration-test/ZkTrieVerifier.spec.ts
Normal file
416
contracts/integration-test/ZkTrieVerifier.spec.ts
Normal file
@@ -0,0 +1,416 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { expect } from "chai";
|
||||
import { concat } from "ethers/lib/utils";
|
||||
import { ethers } from "hardhat";
|
||||
import { MockZkTrieVerifier } from "../typechain";
|
||||
|
||||
import poseidonUnit from "circomlib/src/poseidon_gencontract";
|
||||
|
||||
interface ITestConfig {
|
||||
block: number;
|
||||
desc: string;
|
||||
account: string;
|
||||
storage: string;
|
||||
expectedRoot: string;
|
||||
expectedValue: string;
|
||||
accountProof: string[];
|
||||
storageProof: string[];
|
||||
}
|
||||
|
||||
const testcases: Array<ITestConfig> = [
|
||||
{
|
||||
block: 95216,
|
||||
desc: "contract with storage",
|
||||
account: "0x5300000000000000000000000000000000000004",
|
||||
storage: "0x9505174b0709a2a1997fe9797cb89648a93f17ce0096cbc1a6ed52b73170b96a",
|
||||
expectedRoot: "0x2dc794537b959b575dc216cd11389d802f9389fce7183278561a824aa8e950e2",
|
||||
expectedValue: "0x00000000000000000000000000000000000000000000000111346048bf18a14a",
|
||||
accountProof: [
|
||||
"0x001988ce414103e97cb80613adde47d5fe0611b30087d1cfcdb84284c42907467e24ac744be2edcb86cdfc42a9bbb7b2a270649161c3ce3a41d3ad5a26927d2c79",
|
||||
"0x0028db7c407cab6652f1f194401bd87bda33c9a1723b4f93515bd5929cad02668123fa5a3e69136c8e03a62c805f89c9d3578a6f5fac4bb281fc4d7df12fbcc5db",
|
||||
"0x000376d1bfe3d5c6afffb5707a34003209c57fbf15430daf0f8022b4df2bb947460ab4fda7be343efd34af2420e8e9d4268f436cb7700a005086df4eba083407c8",
|
||||
"0x0025df09dd66dd9d8b5b1abb82cee9985a2addd12e7f5671c910e27644ccaf498c2a2d7021169172e380831f43a00f0a3bef8576c7c74ac98fd7e7b1ec443ac92e",
|
||||
"0x00218d51f8e754bf89062007dd765b50b7385bbb4a57db258ac8dcf9ad69b6f4552ddc5a17cec74d8e8f06e16c0a6112023c34d6c001060bc783ab4d06a4a9801a",
|
||||
"0x001166c2eedfbbb4568ec27c57b2729437c0c8c38161fad643f03f76fbd807e712286d86bfdceb6729daedb6f219dd0f6080386d9a2a8f9c1dcb89792c8754e125",
|
||||
"0x0028fd666ed406e277f6496bcac13af8b303b58c74be937399095399f4dd141c6f2876f81684c2546ff90b221ba2fe1290e671770af08fd545868e3351401b1503",
|
||||
"0x000b9245c7ccc1eab305d40cced5e8aac6c8ddb877451075185bb7a6c1a4973a5d2852ce761c8e417a5f604a6ef4196ec101014aa1d1e4c684d1b5b8cbec5c37b1",
|
||||
"0x0019755e50ef22e13ae17cbc33d9e708ee9efc011941b3a920bc65da9825b04eb029a43488e5584b68d1a98a215f03f31e063734a3305600f9feed11607271d0d3",
|
||||
"0x002e10cc0afbf5b336e6a6eeae0c863df7a7c2ba61c599618fb973aeff397918e523b18c08a19fa6bc964ae41c56af610ab43d948db94ad2543e9807a5a0f1d2f0",
|
||||
"0x00247f3f0cebebf749e27c8ffd81e9919cab114bd3d75029e3260e99b6c7fe551d06a69531144f521b68d1a2c7450f5a20146efdaf7b47271782bb8746a023cf84",
|
||||
"0x0029ad88f0ee7198edcae37ab88efb2a27ea8956d6b988264b227843c175743c4329916ead363e6adfc27f400977d2d9efb1f896616a18d71e2702ec8201b82c57",
|
||||
"0x002a1de55ee84561850354085516a1101705f8240b8f1e1f9aea3a464650d637a52fad2de438ac5851b0e28508af90bd385dbcad5df8ea23ca78792f094ff7ca0d",
|
||||
"0x001ba118afa1977f1fda1411cd1c7f145ab97a35b1e724060d5cfc3d58b27141ee2b0a8dbf3d494c6a1bf6456c4de00de8e2f0d9be0716a3ca78d4df28948f975b",
|
||||
"0x0025bdbf508c1e3808415136bfdd6dfb548c33348d813882b0d405913405d575010c60f95c658dc8113f7c97935a35d78c23dba131c25866fc8d93920e318d2450",
|
||||
"0x0007bc3ec4d80df884c4d87f4541ffa522046a4c52e6cccb9ff7376ff56149e5d21b87a56676f679f4b8b4478c8a3aa80a09127258cccd4aa373a5c7c2344d2d03",
|
||||
"0x010aef26efde9e4bca477d460482bce3de3577f6e9a280dea6d3f9985b4151deab0508000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000013328350573dd32b38291529042b30b83bf20bfc7e18ab6a9755e2ea692d5a7644f896b0d629cf9740d72ccbc90dd6141deb3fab132f1ebc17ab963c612c7123d5a524d0158cc8291b081281272d79459760d885ea652024615d55b114b5872571b21aee99977b8681205300000000000000000000000000000000000004000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x000a52b818e0a009930d62c17f2b1244179b7c14f8e1ae317fb3bfd3a3ba6060031b2a4aa2df31e79f926474987eea69aab84f4581cfd61b0338438110f6be145b",
|
||||
"0x001684ff1ef6ea054c5a6a5cae45f9280dacfc10c6cde39d1f64a00ad3c77549fe1c14ff8a628c0244ba48d63610e5d0b514c1b7b60301b6f27f77a435caf8bd60",
|
||||
"0x001a2ba0ad7d6447d3c2476aa2e6bd04ab552ac1840450ce11f338f58a80fcdf420df4b9fc89108a0a44d844d981abe44d5ab20a5a101d07e94d131f07bf83ba62",
|
||||
"0x0007158ec8942174c68bde0ab3666eb29b3c5784693bbfcd21126789d98bbdd05409f0313df8ddc438abe4798854f30c9daa2274950ce833a2de21e09b8b2c11b2",
|
||||
"0x000ab27b84c73e447618f030ad9d621b0d61cc783e7ae5671ffcd3ff479b5093fe173d6126fa71986aa679b5384a2dc25f3a15f806a546e933f9fda6ac0a3460d9",
|
||||
"0x0024ca9a7c6b7bf77c7a7acdae9d8e551b08ec6adf30abb7d1c45a6bbd5058ea921802170d5cc7de7d294cf6c67b0ac0208fe76497803554fb5bba9f78721568eb",
|
||||
"0x0018a60c68b26022ced26cce2be1af1d6b33f4c16596d1ba18d5f47fea98ae490b12e66678391e289de1cf981c122e765265b94f0669614d94847480a77c2d3b74",
|
||||
"0x001a776d5e5902c9a073c86a71ee80d167d6e2eb92150df2afb3d87f18b2cce6f02af158ba1cfbc643b36c1e001b59473cc88663b44c8d70739a27b804ec387146",
|
||||
"0x0012cd2c1070b0d2eb215eb760fba9b843bd5c732102ce9773701076b0e37a437e136901c4ddc1cdbef42f46af629296ca5965b41a53cce65237612cea27477076",
|
||||
"0x002bf94aa1fcb474365039e949bbbeabe0162ffc490b1b63ffe0f84bf182a8bf16169fe345e742d176a80f6e733177736d93e40fc9fdd4866efa6cc45ad94e9577",
|
||||
"0x001a2e6e1b585fa0564fc606c3d62c26d9a113d75430966ff3f500e450c762edeb24fb1e5456ed4313d9418a1b073ae8b3f852f0f8435752bbbe65d21726ddb873",
|
||||
"0x002529704fb28f7d3f9d2f3e9d38b000b6bfc2a21cb0a1955797016536066307d70ba7397326ecf50b98153f9e3baa96608efdf7d772b1ff28649bef677860dba9",
|
||||
"0x0022f4f22a1d85ac83a56e7031559cf874c78a2f2ee6b6b93625f588313964a6d0052f6c873c6417d409c2a5317b31449b36fb4faede558d03b448b06b4a198daa",
|
||||
"0x0017167b295954b29f62d7347dab3158aedc8586d5aa233d3f69c14bc7fe31eb840000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x002d7bed0c0f0318a6fc60f903f4a42841cc4fa431ddf1a97fc34f35d6a267434b2a1a818d75328089a9578143e31b1f535517e09ff50a728b100483e712c8bc9a",
|
||||
"0x0126ae15b478408eb45ea8b6f61aad1345f2b6257efd1acc4a6024b26f664c98240101000000000000000000000000000000000000000000000000000111346048bf18a14a209505174b0709a2a1997fe9797cb89648a93f17ce0096cbc1a6ed52b73170b96a",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
{
|
||||
block: 95216,
|
||||
desc: "contract with empty storage node",
|
||||
account: "0xb75d7e84517e1504c151b270255b087fd746d34c",
|
||||
storage: "0x0000000000000000000000000000000000000000000000000000000000000002",
|
||||
expectedRoot: "0x2dc794537b959b575dc216cd11389d802f9389fce7183278561a824aa8e950e2",
|
||||
expectedValue: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
accountProof: [
|
||||
"0x001988ce414103e97cb80613adde47d5fe0611b30087d1cfcdb84284c42907467e24ac744be2edcb86cdfc42a9bbb7b2a270649161c3ce3a41d3ad5a26927d2c79",
|
||||
"0x0028db7c407cab6652f1f194401bd87bda33c9a1723b4f93515bd5929cad02668123fa5a3e69136c8e03a62c805f89c9d3578a6f5fac4bb281fc4d7df12fbcc5db",
|
||||
"0x0006801926f00b574e3a88162d192482fecba9918b77e133dd77587d9efaf5c7861712d244ac8ad4bc0bffe0dbe8ab261865c9a69b4b7769e9c188ec048460ce78",
|
||||
"0x002f3161746c2c70c7cefb74c07bc16b28bd9011343f5c6f8756471cd0b184601a25d05d5447a572452964b3c20f40ef841bf313c958e82a6923584e20496df67f",
|
||||
"0x000efef3e3e174da6f3f451b5a2652d2489fff449a217c10841e68e4a15995d6521c4b1552c592020fbc7219c5d67ff00bd630db8102ce5c6ca12bea29b80ba5e5",
|
||||
"0x0019b4749b17792c0ad9f7b460a0faf35400da9423be38ac5c40e81c805acc72592c0b933e1c25d05db98d98fc4f04b27610b2ee88281126099aed42f27cd96b00",
|
||||
"0x002b8d563c5041f28afa38da01b6ec9e7278250be79f7f55e2586955e75ab75fad2055ea72cd44209c41c94ddfb980fe5b007b3e997085bc1fe5b514f72f860c05",
|
||||
"0x001335698617876fcc272740f765d53d53ee511dc9dc33965aaa0a5584f2f0fc02274c435ba9cc0fd5b897350de8cc1837d3a2baaa54ef3f9c66f689f20eddaf1a",
|
||||
"0x0010f766b8dbe13e3f27f45da3ad7e5c31fd1c11c51f4f892851519182cdc9348921c10d83a16e057f99623dcd68ab28a78e48b655df756245631521d04e85e583",
|
||||
"0x002bb5fce9df47073438d61ee438d900ab4ab01ac7f053e57c6ffe3e8f1746285016a600e6b7ee90281bbc3bd9b9523a663261cda2208ae98efcf76df8c965fb76",
|
||||
"0x002cad2eb5194b59d880565b03cd667a842923c1310a60bd818685c8fe4120d86817ee8bfffdb490f78f23d6fb38bb1c27f10f877c5017b8b2c21ad14f23df0eab",
|
||||
"0x001f064044ca94d6f30ef93ee1bb6ae35450acf1c8f5b113b0f0ff39e4b65cfb9a25141ae7fc30c69000991e65c626c1b12fb76bca02c68f8116d15698a5934b71",
|
||||
"0x0014382fa3481f424cc33c39f77fd3df54c5951be347c629ab5baec238e46cab050b2b8bec8ebdbc97dd6c0ab867aae5746e51b69b7b8177c96dbc0c4531521d3e",
|
||||
"0x0011941db7a46d1a3ddbd27a4a57a0ce1865b6e224552b233d9d545745489257f408c8e3a0a147e117dbb89827018a2df52d124cee29e82b15643e4877cabe4d06",
|
||||
"0x0000d7b8f99e5f148297bf4bf7e5133f87dbdf1932dbb152e0cb14c472c7d26f26146c4f72b903bb98b0855c1ca5bef4bada14a773dcda341d10402004e999d757",
|
||||
"0x0104eeb1fce36df4d3f6423137af3855d16bc936184295529c58682bb5217d64d905080000000000000000000000000000000000000000000000000867000000000000000130644e72e131a029b85045b68181585d2833e84879b96ea2850beb8e012d423615fd9926356a5b1f3a4599c7cccd6df3b45097b6527756e572b90fc8c40496f831f2125c021fb94759cb1993a2f07eae01792311e13f209441ff8969cf1eb8351cafbbe8f01ed4c292d9a27be523919a274441a076b20c7d713d192dbe6485c220b75d7e84517e1504c151b270255b087fd746d34c000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x000c180cb3d57f72eb405dfc667d167967e4709cf3722a87b4c924f78a1d8fa9e926d16eb1f4902f8ac7a48fdf98274c9c4061f9f14f783e2fb41ef50c53d5f8ad",
|
||||
"0x000f78c968ee196c478c91d12a48edfde6c630d40203652c6420ff5aa3619549a4297615606d62866169d509f77c9cb38751ae282cafdc27caf891585b383b4795",
|
||||
"0x000798716960783afdcfd0749aa3b316d6e3d6ec2724853e629b42b5a9a10208e02e5f5fe3d5b8b823d3481aa1e738a1a24d6d1a63116e0003044672d73a7df2e4",
|
||||
"0x0014748f61c4954d239225204b4611d66384f08ef03db3da82957fd590ee00b6c92b873e4bd217f8dfb0fa29bca1087ac7bc29db616a6830ba456091bab772ac06",
|
||||
"0x000a1c900952239e98f5f1a3009e623bf6cf533d3b0d6d13d28d04f0496761927c0be199ff86f081ebb1c413e850450a4cce01dfd2c455156d7abde31385ae2ab8",
|
||||
"0x00028d4e89bc6ce55b5e6bba0f2f3758dafcdb4722e6c1a06f6faa8bae065bc8ae0644641c0ac696c265b3ec90889e3842c9a7a5902f1a5e807c5767ed49106982",
|
||||
"0x001e8434bf68ee6077d88efb5449ad286455a522e63a6bce5544cf785b77a5842d041a4e324bc47aa8ae42b56446f687758a8091986b6d760fd283a9e097a64e3a",
|
||||
"0x00250bc6ba916a2acb3ce53053a88be40b815fa749d144dc709a7a46a08361e83c05b2b5b05f45324ab921e04ae1278371ebe1e092203259f4e5306eb46ad50f8c",
|
||||
"0x0011c208e2c536c37674b1ecafff0261146c326c939544781da7062bbd0ac2fbca246f5225dc41e9fc17fe531f5bdc3325620e4003b3310a2cf7e31011b19c68a2",
|
||||
"0x001dc8d4177945ac89a3c61977ed787e50c9d8a0c5d85dd6b1409ec11213b324e6228005b222573db7882205be776a5bd2183944b6fcf63af604e31b9285bd010e",
|
||||
"0x0014ba74da33d2ca27e3f78bc1bd052c2b92176ce4136df751a8229051de383c2b0c8994f02704420f1f84963281364401d00f6d5aa9b6f52135bd96159c1c3b9b",
|
||||
"0x00188c7ee45a6c28fa7ad49a86206b70764066b1888b0de90e4410d7132a641f8b0eecbba072e28ed6705379104e30dd2557c47b30be7dd5e8c893b8a641d02701",
|
||||
"0x0010fb29a3bb8191eb03bd345ad1995bf6a57f09929f72dc8a9c42435c2eef734b1d565bfc8ae78d6c1496f2bdfeadff6890e8ddef4c6b730a5ec8575344800c90",
|
||||
"0x001b2abe5a1352c492c3ac47d2ff93896977a99a0783eedadc6246efc9b4e78ab408291f4e9234e4662a365f40090e1b323e3448fa2f6cdc9c929477095499c323",
|
||||
"0x00083b5711eb1cbba5e79c53227057d4987a22dd22b5ef715bf21f558917f48b17027f174fd4ca77e412ca65a7fbf6151e4473fa909ea384c7687b45f860d0103a",
|
||||
"0x00100158ee54f61ba5b093a43a348cfd202c87ba1533af2b24fc2f068de89a8d15100f3cc72c206d05d44db4272bd67db89bc6e5c86d7c1b03b40395ec4661595c",
|
||||
"0x002a15c17fcf2a10c6d1bcbd59ae262f80ad33518d499059a668e115045069ef012788a404ba41b5f8a96f0b294d0ba91e65b1bf58eee74adb8e55ca12f22fdccc",
|
||||
"0x00031177585837e616bc830056a4bd12821c9c779096df361ebe1d77379e96ff9e0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x02",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
{
|
||||
block: 95216,
|
||||
desc: "contract with no storage",
|
||||
account: "0x9c0fc47d9346e2be1e24f6cef76149779fe52715",
|
||||
storage: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
expectedRoot: "0x2dc794537b959b575dc216cd11389d802f9389fce7183278561a824aa8e950e2",
|
||||
expectedValue: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
accountProof: [
|
||||
"0x001988ce414103e97cb80613adde47d5fe0611b30087d1cfcdb84284c42907467e24ac744be2edcb86cdfc42a9bbb7b2a270649161c3ce3a41d3ad5a26927d2c79",
|
||||
"0x0007af09eec4d7cc8903e99bd9fb9b8e57c30b0c3e34b17da769b01a9a1b943f391c4537228dbbfd7e7cce02123416bfdd61fb83577725516123b569eafcd8087d",
|
||||
"0x0013a22efa6a843f6de1925fce2f6a83c7ed307182b16f661d0e7a8046561999393050830a440d2506adf42ccedece4e3aadc6bc80cea20fc1d8ed9e9c61597da0",
|
||||
"0x001056a19427eac81b91de5db696812b3a0384bf41b37a12e9cbb7dc62404a102a1465c13c8d3721e137a64d9e5ba1267ac418339b3648bfab5a2a86f2343c2b4d",
|
||||
"0x000794d2c0e19bc86772c2d1a43d46de87ad221847bddcfdffa19dbd34f3c3a9b507c5f198eb63c18640af5eff5480830147639cec070d276b778f21677d22ce32",
|
||||
"0x000b23d93f98ec6e3536ffcab6afc6e2eb9b73aeb573d288723350366c05469e2e23837ffea9235351ee533af680d14011825e098f81ce3f8f59e9f08deff05e3d",
|
||||
"0x002ad200ac8be8275ef12b8aeaec526d2b5255128968a2cd2ff775cab14e2ec4e907f2e9b849239e0e94332a50ac9d97320c56ca718c5e023cacd69f80b4c97c86",
|
||||
"0x00284be135a2d7f5822a7949189b90696df39b1b183206c764576bf457df4fd1560204a9fc6c0dc199eecb404acfcabf4a633916fc94d2790dcd34959809c2195d",
|
||||
"0x00270c2cd154aea3b575a1c7d47c62576bbdce6bbc7ccf5682e7962cf6cb77f0d317fdbac10917644860584c3057c750df695f529189f90910c30f114257719990",
|
||||
"0x00174956df87889921e2a6ddb257fa84508fd7ea22c5a622b84378678e781a2289053dc6b3c4f91335b64f4b170bfe70bb5e2e316227b329d2b1205e7c62c4f755",
|
||||
"0x002f9284ded18b8f281841094a93cb55b95884eec55d8eaa759c6175ddb2e037111c63bcee8ccf544fff55c3e502270e574d1f0b6265c4c7c6f42db5061b0120db",
|
||||
"0x00065fdf05e66407d26a36a49d042c9c5e8cebab3baa2d3fd1ae6e673c3636cf7e2d9dbf3781e3f26f06fb503638a8bf00882f58dc83500338df4b7e08a290a5fb",
|
||||
"0x00138987046c770f02f5d8e7d073f6c055536450fa55ccd2a23957598b6070297926f3a0b645072c5bd5c15cdcf03a4474e94d760e3a76fb8714b20b9d74608823",
|
||||
"0x00280e7f8e278e02e43843aaba5a9a722a89af0ece06b5892284f825974e1c1984185be1fda9b5322a4c41023127eee438849ea23390e6c2d4d9abdedb5a1a43fc",
|
||||
"0x00208f32072c6e20863710406ad34339da1124c639941e935818dd9ad9419849c91e0e37873df7eb190a2846789df889bbfd522200e2a41423ff9ab0acf2592be0",
|
||||
"0x0005fb23491fabbc9b3eead71117b86a27952e8fd4b3380336ac3f479832e94bad109a1b6dca757696b8831d2529ffda29f37af36f92fec738376df77561491083",
|
||||
"0x0028baee42b4a9a70b7ec1e50ea1a6817f812082a28598dca106aaecf2761fb63c06e5b589490c27f5cfc233890456ec47a7365ff2882a27c73968f4829d011b05",
|
||||
"0x001708247f7a96b84cad27c31985cd39b6cc9435b4ec3f4db9aeed3311c213de651e2f271ae0fa011e5e6fccd121492400327efb915c95d85956a9cd27ceb4321a",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000002332e856217b3bab09901f1daa9ddc91edf56964e03675d260d00ffdf6e2e715",
|
||||
"0x000571dce6fee951f457db89bae18abbd78b6b06504602a103133d2a38cabf5f5b1ecb13b03e3493e217c65da70baf4c4fad74808110658924869ba0e75d0871db",
|
||||
"0x001738a6461148300d30699edb55d3b5bb62760aeb9384c07d61aa062c401f3a7d0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x000c14152707412177bbe1cfed882d7d7bdfca4e96be701a3c41bb3d254491f0bf0096ebc25015b9a40d4fe7490bda8ecb7f3a01e858d7833dce8f1993be4db07d",
|
||||
"0x0117294cb69b0984b3a26d77eae252f9d8e438808bf276ee8c0c0546b7316c9bca05080000000000000000000000000000000000000000000000000ab1000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ed3aa0dd2cd363d4cea5d5283ec359f75be36a12ceddc7f80a58af9d39a418a02b6a0ff9eb34bf0e52f67047f95556a96c4f40822412da0c8bd0340996a754f4209c0fc47d9346e2be1e24f6cef76149779fe52715000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x02",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
{
|
||||
block: 95216,
|
||||
desc: "EOA with balance",
|
||||
account: "0x0384a6f7e2588bb251688f9ab8d10932a98e9f28",
|
||||
storage: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
expectedRoot: "0x2dc794537b959b575dc216cd11389d802f9389fce7183278561a824aa8e950e2",
|
||||
expectedValue: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
accountProof: [
|
||||
"0x001988ce414103e97cb80613adde47d5fe0611b30087d1cfcdb84284c42907467e24ac744be2edcb86cdfc42a9bbb7b2a270649161c3ce3a41d3ad5a26927d2c79",
|
||||
"0x0028db7c407cab6652f1f194401bd87bda33c9a1723b4f93515bd5929cad02668123fa5a3e69136c8e03a62c805f89c9d3578a6f5fac4bb281fc4d7df12fbcc5db",
|
||||
"0x0006801926f00b574e3a88162d192482fecba9918b77e133dd77587d9efaf5c7861712d244ac8ad4bc0bffe0dbe8ab261865c9a69b4b7769e9c188ec048460ce78",
|
||||
"0x002f3161746c2c70c7cefb74c07bc16b28bd9011343f5c6f8756471cd0b184601a25d05d5447a572452964b3c20f40ef841bf313c958e82a6923584e20496df67f",
|
||||
"0x0007602275f17f6c339ec3febc879c2ca72efa782ff1888b04553f82333eb0e60c068c8e4fe6da32f7f80a4acb50b690a7204581e5e4b8e9e7daa115dfcb466ae1",
|
||||
"0x000cb512d4ab158b5e7d5852cc7531788f11e64e5959cc1233d7a64eaaca36426116fea9120cf06c241843db50d81978b402281dfe15ba7d8a8c689bfbe0b31a1a",
|
||||
"0x002eb4fff0642f7be6d8e95793d9371d606df48efd0b62a7eb01b0a9669307be2b0ee7d01463afc3dac441f66e675ba06fec67b692e3f7a46510d096836468a3cb",
|
||||
"0x0003ea09dc5b0ca3ce2961d3200c09b837ea535447e3ba45e5583dbb4e9db48b2208abfec237c907584104b11444f55fa3fa7e6f6a5954817ecea6361516f0271b",
|
||||
"0x001c654478a700ac0414f5cd8da557e04f9570939802c3963e801523f001ebb4d916d301b50f89760520da2a662b03a207e9372902153ba84ef0f5438472f466c6",
|
||||
"0x0009f3b0d95ec5d88cfc2db19520f43d110d12c757a58ae7f578095de96e5d319d2c8f43a67b0c01008670f07eb53071b835f19cbb45d6e76281a083087217d988",
|
||||
"0x000348f024d617f64de7be803547c109b98f833b090e8a3dea0c2bed201ce752c12a4fb71f098941741c42e156651d8a42632e3acbf6f14cd9763b50216af75d61",
|
||||
"0x0029f85b49319fe7dfced69a258b1baf213d638fe3082b9a13f38e553e9d3269333054c4cb6d1e91bc2dfced1559b58cd6474ac6583a1fc5a2bef5eaa7b96ecea0",
|
||||
"0x000a4d19e2ec5f98d9ccdc1e94d9334668b87ea451195f9a8319b98cfdb077c5ce1adc64852505188363c7e98b83501e876862d8ffbd8b4051f3cb6dde7f0e8afe",
|
||||
"0x002568d5d87f19b2b3f2b7341ee61fb45f56dc76734beaa4f1a9865b80b9d9a7d500a191ba054a28841f25c34ad384817a2af2ebada6047517dbb2b6a1338e48c7",
|
||||
"0x0027f6df1a3610c7447efd280fa6a949713456a1ba79b50dc7fb87c5cb3312b19311b3c9c4420874b02bdc1ea102dc77bb803c1a5042d565aea99054ae0eb816b2",
|
||||
"0x0018a3d33e2c0d076ca4ddb093516d90cb8ba8b508e8d372d3a8a93aa9eef6079b138df6cb61c8f92dcbea8cd90ead1efa49f3a24f814c88a7bdca8fd83f4d0675",
|
||||
"0x00268f3122e558d5084a1b3ffc293b67bd2436152fbee80566226d4a753b5b44c40b6d06e2f5f17009a7e146889c2f492b077a462d602e0e72f53373a154aa450e",
|
||||
"0x0006c81bc9375fe1a0ebb75b151c8a321b85970c1a8a5aa7396a7076a4d6f26c8118a7e9e0987d7c6d0100180c9ba496db2b967f6acf7bc11d002314693416b3bf",
|
||||
"0x011fb221b659992b8d98a645cb37666f934ded70f1f5d82dad67dace71d7191f8105080000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000d8d6f2b3da41cda2e0000000000000000000000000000000000000000000000000000000000000000c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4702098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864200384a6f7e2588bb251688f9ab8d10932a98e9f28000000000000000000000000",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
storageProof: [
|
||||
"0x02",
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704449",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
describe("ZkTrieVerifier", async () => {
|
||||
let verifier: MockZkTrieVerifier;
|
||||
|
||||
beforeEach(async () => {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const Poseidon2Elements = new ethers.ContractFactory(
|
||||
poseidonUnit.generateABI(2),
|
||||
poseidonUnit.createCode(2),
|
||||
deployer
|
||||
);
|
||||
|
||||
const poseidon = await Poseidon2Elements.deploy();
|
||||
await poseidon.deployed();
|
||||
|
||||
const MockZkTrieVerifier = await ethers.getContractFactory("MockZkTrieVerifier", deployer);
|
||||
verifier = await MockZkTrieVerifier.deploy(poseidon.address);
|
||||
await verifier.deployed();
|
||||
});
|
||||
|
||||
for (const test of testcases) {
|
||||
it(`should succeed for block[${test.block}] desc[${test.desc}] account[${test.account}] storage[${test.storage}]`, async () => {
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
const [root, value, gasUsed] = await verifier.verifyZkTrieProof(test.account, test.storage, proof);
|
||||
expect(test.expectedRoot).to.eq(root);
|
||||
expect(test.expectedValue).to.eq(value);
|
||||
console.log("gas usage:", gasUsed.toString());
|
||||
});
|
||||
}
|
||||
|
||||
it("should revert, when parent node invalid", async () => {
|
||||
const test = testcases[0];
|
||||
test.accountProof[0] =
|
||||
"0x010a52b818e0a009930d62c17f2b1244179b7c14f8e1ae317fb3bfd3a3ba6060031b2a4aa2df31e79f926474987eea69aab84f4581cfd61b0338438110f6be145b";
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid parent node");
|
||||
|
||||
test.accountProof[0] =
|
||||
"0x000a52b818e0a009930d62c17f2b1244179b7c14f8e1ae317fb3bfd3a3ba6060031b2a4aa2df31e79f926474987eea69aab84f4581cfd61b0338438110f6be145b";
|
||||
test.storageProof[0] =
|
||||
"0x010a52b818e0a009930d62c17f2b1244179b7c14f8e1ae317fb3bfd3a3ba6060031b2a4aa2df31e79f926474987eea69aab84f4581cfd61b0338438110f6be145b";
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid parent node");
|
||||
});
|
||||
|
||||
it("should revert, when hash mismatch", async () => {
|
||||
const test = testcases[0];
|
||||
test.accountProof[1] =
|
||||
"0x0028db7c407cab6652f1f194401bd87bda33c9a1723b4f93515bd5929cad02668123fa5a3e69136c8e03a62c805f89c9d3578a6f5fac4bb281fc4d7df12fbcc5dc";
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Hash mismatch");
|
||||
});
|
||||
|
||||
it("should revert, when invalid proof magic bytes", async () => {
|
||||
const test = testcases[0];
|
||||
test.accountProof[17] =
|
||||
"0x5448495320495320534f4d45204d4147494320425954455320464f5220534d54206d3172525867503278704448";
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid ProofMagicBytes");
|
||||
});
|
||||
|
||||
it("should revert, when invalid leaf node in account proof", async () => {
|
||||
const test = testcases[0];
|
||||
// Invalid leaf node in account proof
|
||||
test.accountProof[16] =
|
||||
"0x000aef26efde9e4bca477d460482bce3de3577f6e9a280dea6d3f9985b4151deab0508000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000013328350573dd32b38291529042b30b83bf20bfc7e18ab6a9755e2ea692d5a7644f896b0d629cf9740d72ccbc90dd6141deb3fab132f1ebc17ab963c612c7123d5a524d0158cc8291b081281272d79459760d885ea652024615d55b114b5872571b21aee99977b8681205300000000000000000000000000000000000004000000000000000000000000";
|
||||
let proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid leaf node");
|
||||
|
||||
// Node key mismatch in account proof
|
||||
test.accountProof[16] =
|
||||
"0x010aef16efde9e4bca477d460482bce3de3577f6e9a280dea6d3f9985b4151deab0508000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000013328350573dd32b38291529042b30b83bf20bfc7e18ab6a9755e2ea692d5a7644f896b0d629cf9740d72ccbc90dd6141deb3fab132f1ebc17ab963c612c7123d5a524d0158cc8291b081281272d79459760d885ea652024615d55b114b5872571b21aee99977b8681205300000000000000000000000000000000000004000000000000000000000000";
|
||||
proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Node key mismatch");
|
||||
|
||||
// Invalid leaf node hash in account proof
|
||||
test.accountProof[16] =
|
||||
"0x010aef26efde9e4bca477d460482bce3de3577f6e9a280dea6d3f9985b4151deab0508000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000013328350573dd32b38291529042b30b83bf20bfc7e18ab6a9755e2ea692d5a7644f896b0d629cf9740d72ccbc90dd6141deb3fab132f1ebc17ab963c612c7123d5a524d0158cc8291b081281272d79459760d885ea652024615d55b114b5872571b21aee99977b8681205300000000000000000000000000000000000004000000000000000000000000";
|
||||
proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid leaf node hash");
|
||||
|
||||
// Invalid KeyPreimage length in account proof
|
||||
test.accountProof[16] =
|
||||
"0x010aef26efde9e4bca477d460482bce3de3577f6e9a280dea6d3f9985b4151deab0508000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000013328350573dd32b38291529042b30b83bf20bfc7e18ab6a9755e2ea692d5a7644f896b0d629cf9740d72ccbc90dd6141deb3fab132f1ebc17ab963c612c7123d5a524d0158cc8291b081281272d79459760d885ea652024615d55b114b5872571b21aee99977b8681215300000000000000000000000000000000000004000000000000000000000000";
|
||||
proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith(
|
||||
"Invalid KeyPreimage length"
|
||||
);
|
||||
|
||||
// Invalid KeyPreimage in account proof
|
||||
test.accountProof[16] =
|
||||
"0x010aef26efde9e4bca477d460482bce3de3577f6e9a280dea6d3f9985b4151deab0508000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000013328350573dd32b38291529042b30b83bf20bfc7e18ab6a9755e2ea692d5a7644f896b0d629cf9740d72ccbc90dd6141deb3fab132f1ebc17ab963c612c7123d5a524d0158cc8291b081281272d79459760d885ea652024615d55b114b5872571b21aee99977b8681205300000000000000000000000000000000000003000000000000000000000000";
|
||||
proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid KeyPreimage");
|
||||
});
|
||||
|
||||
it("should revert, when storage root mismatch", async () => {
|
||||
const test = testcases[0];
|
||||
test.storageProof[0] =
|
||||
"0x000a52b818e0a009930d62c17f2b1244179b7c14f8e1ae317fb3bfd3a3ba6060031b2a4aa2df31e79f926474987eea69aab84f4581cfd61b0338438110f6be145c";
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Storage root mismatch");
|
||||
});
|
||||
|
||||
it("should revert, when invalid leaf node in storage proof", async () => {
|
||||
const test = testcases[0];
|
||||
// Invalid leaf node in account proof
|
||||
test.storageProof[15] =
|
||||
"0x0026ae15b478408eb45ea8b6f61aad1345f2b6257efd1acc4a6024b26f664c98240101000000000000000000000000000000000000000000000000000111346048bf18a14a209505174b0709a2a1997fe9797cb89648a93f17ce0096cbc1a6ed52b73170b96a";
|
||||
let proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid leaf node");
|
||||
|
||||
// Node key mismatch in account proof
|
||||
test.storageProof[15] =
|
||||
"0x0136ae15b478408eb45ea8b6f61aad1345f2b6257efd1acc4a6024b26f664c98240101000000000000000000000000000000000000000000000000000111346048bf18a14a209505174b0709a2a1997fe9797cb89648a93f17ce0096cbc1a6ed52b73170b96a";
|
||||
proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Node key mismatch");
|
||||
|
||||
// Invalid leaf node hash in account proof
|
||||
test.storageProof[15] =
|
||||
"0x0126ae15b478408eb45ea8b6f61aad1345f2b6257efd1acc4a6024b26f664c98240101000000000000000000000000000000000000000000000000000111446048bf18a14a209505174b0709a2a1997fe9797cb89648a93f17ce0096cbc1a6ed52b73170b96a";
|
||||
proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid leaf node hash");
|
||||
|
||||
// Invalid KeyPreimage length in account proof
|
||||
test.storageProof[15] =
|
||||
"0x0126ae15b478408eb45ea8b6f61aad1345f2b6257efd1acc4a6024b26f664c98240101000000000000000000000000000000000000000000000000000111346048bf18a14a219505174b0709a2a1997fe9797cb89648a93f17ce0096cbc1a6ed52b73170b96a";
|
||||
proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith(
|
||||
"Invalid KeyPreimage length"
|
||||
);
|
||||
|
||||
// Invalid KeyPreimage in account proof
|
||||
test.storageProof[15] =
|
||||
"0x0126ae15b478408eb45ea8b6f61aad1345f2b6257efd1acc4a6024b26f664c98240101000000000000000000000000000000000000000000000000000111346048bf18a14a209505174b0709a2a1997fe9797cb89648a93f17ce0096cbc1a6ed52b73170b97a";
|
||||
proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Invalid KeyPreimage");
|
||||
});
|
||||
|
||||
it("should revert, when proof length mismatch", async () => {
|
||||
const test = testcases[0];
|
||||
const proof = concat([
|
||||
`0x${test.accountProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.accountProof,
|
||||
`0x${test.storageProof.length.toString(16).padStart(2, "0")}`,
|
||||
...test.storageProof,
|
||||
"0x00",
|
||||
]);
|
||||
await expect(verifier.verifyZkTrieProof(test.account, test.storage, proof)).revertedWith("Proof length mismatch");
|
||||
});
|
||||
});
|
||||
@@ -27,6 +27,8 @@
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
||||
"@typescript-eslint/parser": "^4.29.1",
|
||||
"chai": "^4.2.0",
|
||||
"circom": "^0.5.46",
|
||||
"circomlib": "^0.5.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"edit-json-file": "^1.7.0",
|
||||
"eslint": "^7.29.0",
|
||||
|
||||
42
contracts/scripts/ScrollChainCommitmentVerifier.deploy.ts
Normal file
42
contracts/scripts/ScrollChainCommitmentVerifier.deploy.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import * as dotenv from "dotenv";
|
||||
|
||||
import { ethers } from "hardhat";
|
||||
import poseidonUnit from "circomlib/src/poseidon_gencontract";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
async function main() {
|
||||
const [deployer] = await ethers.getSigners();
|
||||
|
||||
const ScrollChainCommitmentVerifier = await ethers.getContractFactory("ScrollChainCommitmentVerifier", deployer);
|
||||
|
||||
const L1ScrollChainAddress = process.env.L1_ZK_ROLLUP_PROXY_ADDR!;
|
||||
let PoseidonUnit2Address = process.env.POSEIDON_UNIT2_ADDR;
|
||||
|
||||
if (!PoseidonUnit2Address) {
|
||||
const Poseidon2Elements = new ethers.ContractFactory(
|
||||
poseidonUnit.generateABI(2),
|
||||
poseidonUnit.createCode(2),
|
||||
deployer
|
||||
);
|
||||
|
||||
const poseidon = await Poseidon2Elements.deploy();
|
||||
console.log("Deploy PoseidonUnit2 contract, hash:", poseidon.deployTransaction.hash);
|
||||
const receipt = await poseidon.deployTransaction.wait();
|
||||
console.log(`✅ Deploy PoseidonUnit2 contract at: ${poseidon.address}, gas used: ${receipt.gasUsed}`);
|
||||
PoseidonUnit2Address = poseidon.address;
|
||||
}
|
||||
|
||||
const verifier = await ScrollChainCommitmentVerifier.deploy(PoseidonUnit2Address, L1ScrollChainAddress);
|
||||
console.log("Deploy ScrollChainCommitmentVerifier contract, hash:", verifier.deployTransaction.hash);
|
||||
const receipt = await verifier.deployTransaction.wait();
|
||||
console.log(`✅ Deploy ScrollChainCommitmentVerifier contract at: ${verifier.address}, gas used: ${receipt.gasUsed}`);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
import { Script } from "forge-std/Script.sol";
|
||||
import { console } from "forge-std/console.sol";
|
||||
|
||||
import { ScrollChainCommitmentVerifier } from "../../src/L1/rollup/ScrollChainCommitmentVerifier.sol";
|
||||
|
||||
contract DeployScrollChainCommitmentVerifier is Script {
|
||||
uint256 L1_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_DEPLOYER_PRIVATE_KEY");
|
||||
|
||||
address L1_ZK_ROLLUP_PROXY_ADDR = vm.envAddress("L1_ZK_ROLLUP_PROXY_ADDR");
|
||||
|
||||
address POSEIDON_UNIT2_ADDR = vm.envAddress("POSEIDON_UNIT2_ADDR");
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(L1_DEPLOYER_PRIVATE_KEY);
|
||||
|
||||
deployScrollChainCommitmentVerifier();
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function deployScrollChainCommitmentVerifier() internal {
|
||||
ScrollChainCommitmentVerifier verifier = new ScrollChainCommitmentVerifier(
|
||||
POSEIDON_UNIT2_ADDR,
|
||||
L1_ZK_ROLLUP_PROXY_ADDR
|
||||
);
|
||||
|
||||
logAddress("L1_SCROLL_CHAIN_COMMITMENT_VERIFIER", address(verifier));
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
30
contracts/scripts/foundry/DeployWeth.s.sol
Normal file
30
contracts/scripts/foundry/DeployWeth.s.sol
Normal file
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
import { Script } from "forge-std/Script.sol";
|
||||
import { console } from "forge-std/console.sol";
|
||||
|
||||
import { WETH9 } from "../../src/L2/predeploys/WETH9.sol";
|
||||
|
||||
contract DeployWeth is Script {
|
||||
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
|
||||
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
|
||||
|
||||
function run() external {
|
||||
// deploy weth only if we're running a private L1 network
|
||||
if (L1_WETH_ADDR == address(0)) {
|
||||
uint256 L1_WETH_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_WETH_DEPLOYER_PRIVATE_KEY");
|
||||
vm.startBroadcast(L1_WETH_DEPLOYER_PRIVATE_KEY);
|
||||
WETH9 weth = new WETH9();
|
||||
L1_WETH_ADDR = address(weth);
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
logAddress("L1_WETH_ADDR", L1_WETH_ADDR);
|
||||
logAddress("L2_WETH_ADDR", L2_WETH_ADDR);
|
||||
}
|
||||
|
||||
function logAddress(string memory name, address addr) internal view {
|
||||
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
||||
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
||||
|
||||
@@ -2,55 +2,55 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { IScrollMessenger } from "../libraries/IScrollMessenger.sol";
|
||||
import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";
|
||||
|
||||
interface IL1ScrollMessenger is IScrollMessenger {
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
|
||||
struct L2MessageProof {
|
||||
// The hash of the batch where the message belongs to.
|
||||
bytes32 batchHash;
|
||||
// Concatenation of merkle proof for withdraw merkle trie.
|
||||
bytes merkleProof;
|
||||
}
|
||||
struct L2MessageProof {
|
||||
// The hash of the batch where the message belongs to.
|
||||
bytes32 batchHash;
|
||||
// Concatenation of merkle proof for withdraw merkle trie.
|
||||
bytes merkleProof;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Relay a L2 => L1 message with message proof.
|
||||
/// @param from The address of the sender of the message.
|
||||
/// @param to The address of the recipient of the message.
|
||||
/// @param value The msg.value passed to the message call.
|
||||
/// @param nonce The nonce of the message to avoid replay attack.
|
||||
/// @param message The content of the message.
|
||||
/// @param proof The proof used to verify the correctness of the transaction.
|
||||
function relayMessageWithProof(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value,
|
||||
uint256 nonce,
|
||||
bytes memory message,
|
||||
L2MessageProof memory proof
|
||||
) external;
|
||||
/// @notice Relay a L2 => L1 message with message proof.
|
||||
/// @param from The address of the sender of the message.
|
||||
/// @param to The address of the recipient of the message.
|
||||
/// @param value The msg.value passed to the message call.
|
||||
/// @param nonce The nonce of the message to avoid replay attack.
|
||||
/// @param message The content of the message.
|
||||
/// @param proof The proof used to verify the correctness of the transaction.
|
||||
function relayMessageWithProof(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value,
|
||||
uint256 nonce,
|
||||
bytes memory message,
|
||||
L2MessageProof memory proof
|
||||
) external;
|
||||
|
||||
/// @notice Replay an exsisting message.
|
||||
/// @param from The address of the sender of the message.
|
||||
/// @param to The address of the recipient of the message.
|
||||
/// @param value The msg.value passed to the message call.
|
||||
/// @param queueIndex The queue index for the message to replay.
|
||||
/// @param message The content of the message.
|
||||
/// @param oldGasLimit Original gas limit used to send the message.
|
||||
/// @param newGasLimit New gas limit to be used for this message.
|
||||
function replayMessage(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value,
|
||||
uint256 queueIndex,
|
||||
bytes memory message,
|
||||
uint32 oldGasLimit,
|
||||
uint32 newGasLimit
|
||||
) external;
|
||||
/// @notice Replay an exsisting message.
|
||||
/// @param from The address of the sender of the message.
|
||||
/// @param to The address of the recipient of the message.
|
||||
/// @param value The msg.value passed to the message call.
|
||||
/// @param queueIndex The queue index for the message to replay.
|
||||
/// @param message The content of the message.
|
||||
/// @param oldGasLimit Original gas limit used to send the message.
|
||||
/// @param newGasLimit New gas limit to be used for this message.
|
||||
function replayMessage(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value,
|
||||
uint256 queueIndex,
|
||||
bytes memory message,
|
||||
uint32 oldGasLimit,
|
||||
uint32 newGasLimit
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
||||
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
||||
|
||||
import { IScrollChain } from "./rollup/IScrollChain.sol";
|
||||
import { IL1MessageQueue } from "./rollup/IL1MessageQueue.sol";
|
||||
import { IL1ScrollMessenger } from "./IL1ScrollMessenger.sol";
|
||||
import { ScrollConstants } from "../libraries/constants/ScrollConstants.sol";
|
||||
import { IScrollMessenger } from "../libraries/IScrollMessenger.sol";
|
||||
import { ScrollMessengerBase } from "../libraries/ScrollMessengerBase.sol";
|
||||
import { WithdrawTrieVerifier } from "../libraries/verifier/WithdrawTrieVerifier.sol";
|
||||
import {IScrollChain} from "./rollup/IScrollChain.sol";
|
||||
import {IL1MessageQueue} from "./rollup/IL1MessageQueue.sol";
|
||||
import {IL1ScrollMessenger} from "./IL1ScrollMessenger.sol";
|
||||
import {ScrollConstants} from "../libraries/constants/ScrollConstants.sol";
|
||||
import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";
|
||||
import {ScrollMessengerBase} from "../libraries/ScrollMessengerBase.sol";
|
||||
import {WithdrawTrieVerifier} from "../libraries/verifier/WithdrawTrieVerifier.sol";
|
||||
|
||||
// solhint-disable avoid-low-level-calls
|
||||
|
||||
@@ -25,157 +25,228 @@ import { WithdrawTrieVerifier } from "../libraries/verifier/WithdrawTrieVerifier
|
||||
/// @dev All deposited Ether (including `WETH` deposited throng `L1WETHGateway`) will locked in
|
||||
/// this contract.
|
||||
contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1ScrollMessenger {
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from relay id to relay status.
|
||||
mapping(bytes32 => bool) public isL1MessageRelayed;
|
||||
/// @notice Mapping from relay id to relay status.
|
||||
mapping(bytes32 => bool) public isL1MessageRelayed;
|
||||
|
||||
/// @notice Mapping from L1 message hash to sent status.
|
||||
mapping(bytes32 => bool) public isL1MessageSent;
|
||||
/// @notice Mapping from L1 message hash to sent status.
|
||||
mapping(bytes32 => bool) public isL1MessageSent;
|
||||
|
||||
/// @notice Mapping from L2 message hash to a boolean value indicating if the message has been successfully executed.
|
||||
mapping(bytes32 => bool) public isL2MessageExecuted;
|
||||
/// @notice Mapping from L2 message hash to a boolean value indicating if the message has been successfully executed.
|
||||
mapping(bytes32 => bool) public isL2MessageExecuted;
|
||||
|
||||
/// @notice The address of Rollup contract.
|
||||
address public rollup;
|
||||
/// @notice The address of Rollup contract.
|
||||
address public rollup;
|
||||
|
||||
/// @notice The address of L1MessageQueue contract.
|
||||
address public messageQueue;
|
||||
/// @notice The address of L1MessageQueue contract.
|
||||
address public messageQueue;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
// @note move to ScrollMessengerBase in next big refactor
|
||||
/// @dev The status of for non-reentrant check.
|
||||
uint256 private _lock_status;
|
||||
|
||||
/// @notice Initialize the storage of L1ScrollMessenger.
|
||||
/// @param _counterpart The address of L2ScrollMessenger contract in L2.
|
||||
/// @param _feeVault The address of fee vault, which will be used to collect relayer fee.
|
||||
/// @param _rollup The address of ScrollChain contract.
|
||||
/// @param _messageQueue The address of L1MessageQueue contract.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _feeVault,
|
||||
address _rollup,
|
||||
address _messageQueue
|
||||
) public initializer {
|
||||
PausableUpgradeable.__Pausable_init();
|
||||
ScrollMessengerBase._initialize(_counterpart, _feeVault);
|
||||
/**********************
|
||||
* Function Modifiers *
|
||||
**********************/
|
||||
|
||||
rollup = _rollup;
|
||||
messageQueue = _messageQueue;
|
||||
modifier nonReentrant() {
|
||||
// On the first call to nonReentrant, _notEntered will be true
|
||||
require(_lock_status != _ENTERED, "ReentrancyGuard: reentrant call");
|
||||
|
||||
// initialize to a nonzero value
|
||||
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
|
||||
}
|
||||
// Any calls to nonReentrant after this point will fail
|
||||
_lock_status = _ENTERED;
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
_;
|
||||
|
||||
/// @inheritdoc IScrollMessenger
|
||||
function sendMessage(
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external payable override whenNotPaused {
|
||||
address _messageQueue = messageQueue; // gas saving
|
||||
address _counterpart = counterpart; // gas saving
|
||||
|
||||
// compute the actual cross domain message calldata.
|
||||
uint256 _messageNonce = IL1MessageQueue(_messageQueue).nextCrossDomainMessageIndex();
|
||||
bytes memory _xDomainCalldata = _encodeXDomainCalldata(msg.sender, _to, _value, _messageNonce, _message);
|
||||
|
||||
// compute and deduct the messaging fee to fee vault.
|
||||
uint256 _fee = IL1MessageQueue(_messageQueue).estimateCrossDomainMessageFee(
|
||||
address(this),
|
||||
_counterpart,
|
||||
_xDomainCalldata,
|
||||
_gasLimit
|
||||
);
|
||||
require(msg.value >= _fee + _value, "Insufficient msg.value");
|
||||
if (_fee > 0) {
|
||||
(bool _success, ) = feeVault.call{ value: _fee }("");
|
||||
require(_success, "Failed to deduct the fee");
|
||||
// By storing the original value once again, a refund is triggered (see
|
||||
// https://eips.ethereum.org/EIPS/eip-2200)
|
||||
_lock_status = _NOT_ENTERED;
|
||||
}
|
||||
|
||||
// append message to L1MessageQueue
|
||||
IL1MessageQueue(_messageQueue).appendCrossDomainMessage(_counterpart, _gasLimit, _xDomainCalldata);
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
// record the message hash for future use.
|
||||
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
|
||||
isL1MessageSent[_xDomainCalldataHash] = true;
|
||||
/// @notice Initialize the storage of L1ScrollMessenger.
|
||||
/// @param _counterpart The address of L2ScrollMessenger contract in L2.
|
||||
/// @param _feeVault The address of fee vault, which will be used to collect relayer fee.
|
||||
/// @param _rollup The address of ScrollChain contract.
|
||||
/// @param _messageQueue The address of L1MessageQueue contract.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _feeVault,
|
||||
address _rollup,
|
||||
address _messageQueue
|
||||
) public initializer {
|
||||
PausableUpgradeable.__Pausable_init();
|
||||
ScrollMessengerBase._initialize(_counterpart, _feeVault);
|
||||
|
||||
emit SentMessage(msg.sender, _to, _value, _messageNonce, _gasLimit, _message);
|
||||
}
|
||||
rollup = _rollup;
|
||||
messageQueue = _messageQueue;
|
||||
|
||||
/// @inheritdoc IL1ScrollMessenger
|
||||
function relayMessageWithProof(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
uint256 _nonce,
|
||||
bytes memory _message,
|
||||
L2MessageProof memory _proof
|
||||
) external override whenNotPaused onlyWhitelistedSender(msg.sender) {
|
||||
require(xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER, "Message is already in execution");
|
||||
// initialize to a nonzero value
|
||||
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
|
||||
}
|
||||
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
|
||||
require(!isL2MessageExecuted[_xDomainCalldataHash], "Message was already successfully executed");
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
{
|
||||
address _rollup = rollup;
|
||||
require(IScrollChain(_rollup).isBatchFinalized(_proof.batchHash), "Batch is not finalized");
|
||||
// @note skip verify for now
|
||||
/*
|
||||
/// @inheritdoc IScrollMessenger
|
||||
function sendMessage(
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external payable override whenNotPaused {
|
||||
_sendMessage(_to, _value, _message, _gasLimit, tx.origin);
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollMessenger
|
||||
function sendMessage(
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes calldata _message,
|
||||
uint256 _gasLimit,
|
||||
address _refundAddress
|
||||
) external payable override whenNotPaused {
|
||||
_sendMessage(_to, _value, _message, _gasLimit, _refundAddress);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ScrollMessenger
|
||||
function relayMessageWithProof(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
uint256 _nonce,
|
||||
bytes memory _message,
|
||||
L2MessageProof memory _proof
|
||||
) external override whenNotPaused onlyWhitelistedSender(msg.sender) {
|
||||
require(
|
||||
xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER,
|
||||
"Message is already in execution"
|
||||
);
|
||||
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
|
||||
require(!isL2MessageExecuted[_xDomainCalldataHash], "Message was already successfully executed");
|
||||
|
||||
{
|
||||
address _rollup = rollup;
|
||||
require(IScrollChain(_rollup).isBatchFinalized(_proof.batchHash), "Batch is not finalized");
|
||||
// @note skip verify for now
|
||||
/*
|
||||
bytes32 _messageRoot = IScrollChain(_rollup).getL2MessageRoot(_proof.batchHash);
|
||||
require(
|
||||
WithdrawTrieVerifier.verifyMerkleProof(_messageRoot, _xDomainCalldataHash, _nonce, _proof.merkleProof),
|
||||
"Invalid proof"
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
// @todo check more `_to` address to avoid attack.
|
||||
require(_to != messageQueue, "Forbid to call message queue");
|
||||
require(_to != address(this), "Forbid to call self");
|
||||
|
||||
// @note This usually will never happen, just in case.
|
||||
require(_from != xDomainMessageSender, "Invalid message sender");
|
||||
|
||||
xDomainMessageSender = _from;
|
||||
(bool success, ) = _to.call{value: _value}(_message);
|
||||
// reset value to refund gas.
|
||||
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
|
||||
|
||||
if (success) {
|
||||
isL2MessageExecuted[_xDomainCalldataHash] = true;
|
||||
emit RelayedMessage(_xDomainCalldataHash);
|
||||
} else {
|
||||
emit FailedRelayedMessage(_xDomainCalldataHash);
|
||||
}
|
||||
|
||||
bytes32 _relayId = keccak256(abi.encodePacked(_xDomainCalldataHash, msg.sender, block.number));
|
||||
isL1MessageRelayed[_relayId] = true;
|
||||
}
|
||||
|
||||
// @note This usually will never happen, just in case.
|
||||
require(_from != xDomainMessageSender, "Invalid message sender");
|
||||
|
||||
xDomainMessageSender = _from;
|
||||
(bool success, ) = _to.call{ value: _value }(_message);
|
||||
// reset value to refund gas.
|
||||
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
|
||||
|
||||
if (success) {
|
||||
isL2MessageExecuted[_xDomainCalldataHash] = true;
|
||||
emit RelayedMessage(_xDomainCalldataHash);
|
||||
} else {
|
||||
emit FailedRelayedMessage(_xDomainCalldataHash);
|
||||
/// @inheritdoc IL1ScrollMessenger
|
||||
function replayMessage(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
uint256 _queueIndex,
|
||||
bytes memory _message,
|
||||
uint32 _oldGasLimit,
|
||||
uint32 _newGasLimit
|
||||
) external override whenNotPaused {
|
||||
// @todo
|
||||
}
|
||||
|
||||
bytes32 _relayId = keccak256(abi.encodePacked(_xDomainCalldataHash, msg.sender, block.number));
|
||||
isL1MessageRelayed[_relayId] = true;
|
||||
}
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @inheritdoc IL1ScrollMessenger
|
||||
function replayMessage(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
uint256 _queueIndex,
|
||||
bytes memory _message,
|
||||
uint32 _oldGasLimit,
|
||||
uint32 _newGasLimit
|
||||
) external override whenNotPaused {
|
||||
// @todo
|
||||
}
|
||||
/// @notice Pause the contract
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _status The pause status to update.
|
||||
function setPause(bool _status) external onlyOwner {
|
||||
if (_status) {
|
||||
_pause();
|
||||
} else {
|
||||
_unpause();
|
||||
}
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @notice Pause the contract
|
||||
/// @dev This function can only called by contract owner.
|
||||
function pause() external onlyOwner {
|
||||
_pause();
|
||||
}
|
||||
function _sendMessage(
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit,
|
||||
address _refundAddress
|
||||
) internal nonReentrant {
|
||||
address _messageQueue = messageQueue; // gas saving
|
||||
address _counterpart = counterpart; // gas saving
|
||||
|
||||
// compute the actual cross domain message calldata.
|
||||
uint256 _messageNonce = IL1MessageQueue(_messageQueue).nextCrossDomainMessageIndex();
|
||||
bytes memory _xDomainCalldata = _encodeXDomainCalldata(msg.sender, _to, _value, _messageNonce, _message);
|
||||
|
||||
// compute and deduct the messaging fee to fee vault.
|
||||
uint256 _fee = IL1MessageQueue(_messageQueue).estimateCrossDomainMessageFee(
|
||||
address(this),
|
||||
_counterpart,
|
||||
_xDomainCalldata,
|
||||
_gasLimit
|
||||
);
|
||||
require(msg.value >= _fee + _value, "Insufficient msg.value");
|
||||
if (_fee > 0) {
|
||||
(bool _success, ) = feeVault.call{value: _fee}("");
|
||||
require(_success, "Failed to deduct the fee");
|
||||
}
|
||||
|
||||
// append message to L1MessageQueue
|
||||
IL1MessageQueue(_messageQueue).appendCrossDomainMessage(_counterpart, _gasLimit, _xDomainCalldata);
|
||||
|
||||
// record the message hash for future use.
|
||||
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
|
||||
|
||||
// normally this won't happen, since each message has different nonce, but just in case.
|
||||
require(!isL1MessageSent[_xDomainCalldataHash], "Duplicated message");
|
||||
isL1MessageSent[_xDomainCalldataHash] = true;
|
||||
|
||||
emit SentMessage(msg.sender, _to, _value, _messageNonce, _gasLimit, _message);
|
||||
|
||||
// refund fee to tx.origin
|
||||
unchecked {
|
||||
uint256 _refund = msg.value - _fee - _value;
|
||||
if (_refund > 0) {
|
||||
(bool _success, ) = _refundAddress.call{value: _refund}("");
|
||||
require(_success, "Failed to refund the fee");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,163 +4,163 @@ pragma solidity ^0.8.0;
|
||||
|
||||
/// @title The interface for the ERC1155 cross chain gateway in layer 1.
|
||||
interface IL1ERC1155Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when the ERC1155 NFT is transfered to recipient in layer 1.
|
||||
/// @param _l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenId The token id of the ERC1155 NFT to withdraw from layer 2.
|
||||
/// @param _amount The number of token to withdraw from layer 2.
|
||||
event FinalizeWithdrawERC1155(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
);
|
||||
/// @notice Emitted when the ERC1155 NFT is transfered to recipient in layer 1.
|
||||
/// @param _l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenId The token id of the ERC1155 NFT to withdraw from layer 2.
|
||||
/// @param _amount The number of token to withdraw from layer 2.
|
||||
event FinalizeWithdrawERC1155(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC1155 NFT is batch transfered to recipient in layer 1.
|
||||
/// @param _l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenIds The list of token ids of the ERC1155 NFT to withdraw from layer 2.
|
||||
/// @param _amounts The list of corresponding number of token to withdraw from layer 2.
|
||||
event FinalizeBatchWithdrawERC1155(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256[] _tokenIds,
|
||||
uint256[] _amounts
|
||||
);
|
||||
/// @notice Emitted when the ERC1155 NFT is batch transfered to recipient in layer 1.
|
||||
/// @param _l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenIds The list of token ids of the ERC1155 NFT to withdraw from layer 2.
|
||||
/// @param _amounts The list of corresponding number of token to withdraw from layer 2.
|
||||
event FinalizeBatchWithdrawERC1155(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256[] _tokenIds,
|
||||
uint256[] _amounts
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC1155 NFT is deposited to gateway in layer 1.
|
||||
/// @param _l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id of the ERC1155 NFT to deposit in layer 1.
|
||||
/// @param _amount The number of token to deposit in layer 1.
|
||||
event DepositERC1155(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
);
|
||||
/// @notice Emitted when the ERC1155 NFT is deposited to gateway in layer 1.
|
||||
/// @param _l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id of the ERC1155 NFT to deposit in layer 1.
|
||||
/// @param _amount The number of token to deposit in layer 1.
|
||||
event DepositERC1155(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC1155 NFT is batch deposited to gateway in layer 1.
|
||||
/// @param _l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids of the ERC1155 NFT to deposit in layer 1.
|
||||
/// @param _amounts The list of corresponding number of token to deposit in layer 1.
|
||||
event BatchDepositERC1155(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256[] _tokenIds,
|
||||
uint256[] _amounts
|
||||
);
|
||||
/// @notice Emitted when the ERC1155 NFT is batch deposited to gateway in layer 1.
|
||||
/// @param _l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids of the ERC1155 NFT to deposit in layer 1.
|
||||
/// @param _amounts The list of corresponding number of token to deposit in layer 1.
|
||||
event BatchDepositERC1155(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256[] _tokenIds,
|
||||
uint256[] _amounts
|
||||
);
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Deposit some ERC1155 NFT to caller's account on layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _amount The amount of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function depositERC1155(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit some ERC1155 NFT to caller's account on layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _amount The amount of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function depositERC1155(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit some ERC1155 NFT to a recipient's account on layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _amount The amount of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function depositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit some ERC1155 NFT to a recipient's account on layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _amount The amount of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function depositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit a list of some ERC1155 NFT to caller's account on layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _amounts The list of corresponding number of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function batchDepositERC1155(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit a list of some ERC1155 NFT to caller's account on layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _amounts The list of corresponding number of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function batchDepositERC1155(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit a list of some ERC1155 NFT to a recipient's account on layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _amounts The list of corresponding number of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function batchDepositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit a list of some ERC1155 NFT to a recipient's account on layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _amounts The list of corresponding number of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function batchDepositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Complete ERC1155 withdraw from layer 2 to layer 1 and send fund to recipient's account in layer 1.
|
||||
/// The function should only be called by L1ScrollMessenger.
|
||||
/// The function should also only be called by L2ERC1155Gateway in layer 2.
|
||||
/// @param _l1Token The address of corresponding layer 1 token.
|
||||
/// @param _l2Token The address of corresponding layer 2 token.
|
||||
/// @param _from The address of account who withdraw the token in layer 2.
|
||||
/// @param _to The address of recipient in layer 1 to receive the token.
|
||||
/// @param _tokenId The token id to withdraw.
|
||||
/// @param _amount The amount of token to withdraw.
|
||||
function finalizeWithdrawERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
) external;
|
||||
/// @notice Complete ERC1155 withdraw from layer 2 to layer 1 and send fund to recipient's account in layer 1.
|
||||
/// The function should only be called by L1ScrollMessenger.
|
||||
/// The function should also only be called by L2ERC1155Gateway in layer 2.
|
||||
/// @param _l1Token The address of corresponding layer 1 token.
|
||||
/// @param _l2Token The address of corresponding layer 2 token.
|
||||
/// @param _from The address of account who withdraw the token in layer 2.
|
||||
/// @param _to The address of recipient in layer 1 to receive the token.
|
||||
/// @param _tokenId The token id to withdraw.
|
||||
/// @param _amount The amount of token to withdraw.
|
||||
function finalizeWithdrawERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
) external;
|
||||
|
||||
/// @notice Complete ERC1155 batch withdraw from layer 2 to layer 1 and send fund to recipient's account in layer 1.
|
||||
/// The function should only be called by L1ScrollMessenger.
|
||||
/// The function should also only be called by L2ERC1155Gateway in layer 2.
|
||||
/// @param _l1Token The address of corresponding layer 1 token.
|
||||
/// @param _l2Token The address of corresponding layer 2 token.
|
||||
/// @param _from The address of account who withdraw the token in layer 2.
|
||||
/// @param _to The address of recipient in layer 1 to receive the token.
|
||||
/// @param _tokenIds The list of token ids to withdraw.
|
||||
/// @param _amounts The list of corresponding number of token to withdraw.
|
||||
function finalizeBatchWithdrawERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts
|
||||
) external;
|
||||
/// @notice Complete ERC1155 batch withdraw from layer 2 to layer 1 and send fund to recipient's account in layer 1.
|
||||
/// The function should only be called by L1ScrollMessenger.
|
||||
/// The function should also only be called by L2ERC1155Gateway in layer 2.
|
||||
/// @param _l1Token The address of corresponding layer 1 token.
|
||||
/// @param _l2Token The address of corresponding layer 2 token.
|
||||
/// @param _from The address of account who withdraw the token in layer 2.
|
||||
/// @param _to The address of recipient in layer 1 to receive the token.
|
||||
/// @param _tokenIds The list of token ids to withdraw.
|
||||
/// @param _amounts The list of corresponding number of token to withdraw.
|
||||
function finalizeBatchWithdrawERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -3,109 +3,109 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IL1ERC20Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when ERC20 token is withdrawn from L2 to L1 and transfer to recipient.
|
||||
/// @param l1Token The address of the token in L1.
|
||||
/// @param l2Token The address of the token in L2.
|
||||
/// @param from The address of sender in L2.
|
||||
/// @param to The address of recipient in L1.
|
||||
/// @param amount The amount of token withdrawn from L2 to L1.
|
||||
/// @param data The optional calldata passed to recipient in L1.
|
||||
event FinalizeWithdrawERC20(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
/// @notice Emitted when ERC20 token is withdrawn from L2 to L1 and transfer to recipient.
|
||||
/// @param l1Token The address of the token in L1.
|
||||
/// @param l2Token The address of the token in L2.
|
||||
/// @param from The address of sender in L2.
|
||||
/// @param to The address of recipient in L1.
|
||||
/// @param amount The amount of token withdrawn from L2 to L1.
|
||||
/// @param data The optional calldata passed to recipient in L1.
|
||||
event FinalizeWithdrawERC20(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/// @notice Emitted when someone deposit ERC20 token from L1 to L2.
|
||||
/// @param l1Token The address of the token in L1.
|
||||
/// @param l2Token The address of the token in L2.
|
||||
/// @param from The address of sender in L1.
|
||||
/// @param to The address of recipient in L2.
|
||||
/// @param amount The amount of token will be deposited from L1 to L2.
|
||||
/// @param data The optional calldata passed to recipient in L2.
|
||||
event DepositERC20(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
/// @notice Emitted when someone deposit ERC20 token from L1 to L2.
|
||||
/// @param l1Token The address of the token in L1.
|
||||
/// @param l2Token The address of the token in L2.
|
||||
/// @param from The address of sender in L1.
|
||||
/// @param to The address of recipient in L2.
|
||||
/// @param amount The amount of token will be deposited from L1 to L2.
|
||||
/// @param data The optional calldata passed to recipient in L2.
|
||||
event DepositERC20(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Return the corresponding l2 token address given l1 token address.
|
||||
/// @param _l1Token The address of l1 token.
|
||||
function getL2ERC20Address(address _l1Token) external view returns (address);
|
||||
/// @notice Return the corresponding l2 token address given l1 token address.
|
||||
/// @param _l1Token The address of l1 token.
|
||||
function getL2ERC20Address(address _l1Token) external view returns (address);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Deposit some token to a caller's account on L2.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param _token The address of token in L1.
|
||||
/// @param _amount The amount of token to transfer.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit some token to a caller's account on L2.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param _token The address of token in L1.
|
||||
/// @param _amount The amount of token to transfer.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit some token to a recipient's account on L2.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param _token The address of token in L1.
|
||||
/// @param _to The address of recipient's account on L2.
|
||||
/// @param _amount The amount of token to transfer.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit some token to a recipient's account on L2.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param _token The address of token in L1.
|
||||
/// @param _to The address of recipient's account on L2.
|
||||
/// @param _amount The amount of token to transfer.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit some token to a recipient's account on L2 and call.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param _token The address of token in L1.
|
||||
/// @param _to The address of recipient's account on L2.
|
||||
/// @param _amount The amount of token to transfer.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit some token to a recipient's account on L2 and call.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param _token The address of token in L1.
|
||||
/// @param _to The address of recipient's account on L2.
|
||||
/// @param _amount The amount of token to transfer.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Complete ERC20 withdraw from L2 to L1 and send fund to recipient's account in L1.
|
||||
/// @dev Make this function payable to handle WETH deposit/withdraw.
|
||||
/// The function should only be called by L1ScrollMessenger.
|
||||
/// The function should also only be called by L2ERC20Gateway in L2.
|
||||
/// @param _l1Token The address of corresponding L1 token.
|
||||
/// @param _l2Token The address of corresponding L2 token.
|
||||
/// @param _from The address of account who withdraw the token in L2.
|
||||
/// @param _to The address of recipient in L1 to receive the token.
|
||||
/// @param _amount The amount of the token to withdraw.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
function finalizeWithdrawERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable;
|
||||
/// @notice Complete ERC20 withdraw from L2 to L1 and send fund to recipient's account in L1.
|
||||
/// @dev Make this function payable to handle WETH deposit/withdraw.
|
||||
/// The function should only be called by L1ScrollMessenger.
|
||||
/// The function should also only be called by L2ERC20Gateway in L2.
|
||||
/// @param _l1Token The address of corresponding L1 token.
|
||||
/// @param _l2Token The address of corresponding L2 token.
|
||||
/// @param _from The address of account who withdraw the token in L2.
|
||||
/// @param _to The address of recipient in L1 to receive the token.
|
||||
/// @param _amount The amount of the token to withdraw.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
function finalizeWithdrawERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable;
|
||||
}
|
||||
|
||||
@@ -4,145 +4,145 @@ pragma solidity ^0.8.0;
|
||||
|
||||
/// @title The interface for the ERC721 cross chain gateway in layer 1.
|
||||
interface IL1ERC721Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when the ERC721 NFT is transfered to recipient in layer 1.
|
||||
/// @param _l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenId The token id of the ERC721 NFT to withdraw from layer 2.
|
||||
event FinalizeWithdrawERC721(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
);
|
||||
/// @notice Emitted when the ERC721 NFT is transfered to recipient in layer 1.
|
||||
/// @param _l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenId The token id of the ERC721 NFT to withdraw from layer 2.
|
||||
event FinalizeWithdrawERC721(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC721 NFT is batch transfered to recipient in layer 1.
|
||||
/// @param _l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenIds The list of token ids of the ERC721 NFT to withdraw from layer 2.
|
||||
event FinalizeBatchWithdrawERC721(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256[] _tokenIds
|
||||
);
|
||||
/// @notice Emitted when the ERC721 NFT is batch transfered to recipient in layer 1.
|
||||
/// @param _l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenIds The list of token ids of the ERC721 NFT to withdraw from layer 2.
|
||||
event FinalizeBatchWithdrawERC721(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256[] _tokenIds
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC721 NFT is deposited to gateway in layer 1.
|
||||
/// @param _l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id of the ERC721 NFT to deposit in layer 1.
|
||||
event DepositERC721(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
);
|
||||
/// @notice Emitted when the ERC721 NFT is deposited to gateway in layer 1.
|
||||
/// @param _l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id of the ERC721 NFT to deposit in layer 1.
|
||||
event DepositERC721(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC721 NFT is batch deposited to gateway in layer 1.
|
||||
/// @param _l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids of the ERC721 NFT to deposit in layer 1.
|
||||
event BatchDepositERC721(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256[] _tokenIds
|
||||
);
|
||||
/// @notice Emitted when the ERC721 NFT is batch deposited to gateway in layer 1.
|
||||
/// @param _l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param _l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param _from The address of sender in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids of the ERC721 NFT to deposit in layer 1.
|
||||
event BatchDepositERC721(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256[] _tokenIds
|
||||
);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Deposit some ERC721 NFT to caller's account on layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function depositERC721(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit some ERC721 NFT to caller's account on layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function depositERC721(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit some ERC721 NFT to a recipient's account on layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function depositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit some ERC721 NFT to a recipient's account on layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function depositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit a list of some ERC721 NFT to caller's account on layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function batchDepositERC721(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit a list of some ERC721 NFT to caller's account on layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function batchDepositERC721(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit a list of some ERC721 NFT to a recipient's account on layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function batchDepositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit a list of some ERC721 NFT to a recipient's account on layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function batchDepositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Complete ERC721 withdraw from layer 2 to layer 1 and send NFT to recipient's account in layer 1.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L1ScrollMessenger.
|
||||
/// - The function should also only be called by L2ERC721Gateway in layer 2.
|
||||
/// @param _l1Token The address of corresponding layer 1 token.
|
||||
/// @param _l2Token The address of corresponding layer 2 token.
|
||||
/// @param _from The address of account who withdraw the token in layer 2.
|
||||
/// @param _to The address of recipient in layer 1 to receive the token.
|
||||
/// @param _tokenId The token id to withdraw.
|
||||
function finalizeWithdrawERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
) external;
|
||||
/// @notice Complete ERC721 withdraw from layer 2 to layer 1 and send NFT to recipient's account in layer 1.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L1ScrollMessenger.
|
||||
/// - The function should also only be called by L2ERC721Gateway in layer 2.
|
||||
/// @param _l1Token The address of corresponding layer 1 token.
|
||||
/// @param _l2Token The address of corresponding layer 2 token.
|
||||
/// @param _from The address of account who withdraw the token in layer 2.
|
||||
/// @param _to The address of recipient in layer 1 to receive the token.
|
||||
/// @param _tokenId The token id to withdraw.
|
||||
function finalizeWithdrawERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
) external;
|
||||
|
||||
/// @notice Complete ERC721 batch withdraw from layer 2 to layer 1 and send NFT to recipient's account in layer 1.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L1ScrollMessenger.
|
||||
/// - The function should also only be called by L2ERC721Gateway in layer 2.
|
||||
/// @param _l1Token The address of corresponding layer 1 token.
|
||||
/// @param _l2Token The address of corresponding layer 2 token.
|
||||
/// @param _from The address of account who withdraw the token in layer 2.
|
||||
/// @param _to The address of recipient in layer 1 to receive the token.
|
||||
/// @param _tokenIds The list of token ids to withdraw.
|
||||
function finalizeBatchWithdrawERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds
|
||||
) external;
|
||||
/// @notice Complete ERC721 batch withdraw from layer 2 to layer 1 and send NFT to recipient's account in layer 1.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L1ScrollMessenger.
|
||||
/// - The function should also only be called by L2ERC721Gateway in layer 2.
|
||||
/// @param _l1Token The address of corresponding layer 1 token.
|
||||
/// @param _l2Token The address of corresponding layer 2 token.
|
||||
/// @param _from The address of account who withdraw the token in layer 2.
|
||||
/// @param _to The address of recipient in layer 1 to receive the token.
|
||||
/// @param _tokenIds The list of token ids to withdraw.
|
||||
function finalizeBatchWithdrawERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -3,66 +3,66 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IL1ETHGateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when ETH is withdrawn from L2 to L1 and transfer to recipient.
|
||||
/// @param from The address of sender in L2.
|
||||
/// @param to The address of recipient in L1.
|
||||
/// @param amount The amount of ETH withdrawn from L2 to L1.
|
||||
/// @param data The optional calldata passed to recipient in L1.
|
||||
event FinalizeWithdrawETH(address indexed from, address indexed to, uint256 amount, bytes data);
|
||||
/// @notice Emitted when ETH is withdrawn from L2 to L1 and transfer to recipient.
|
||||
/// @param from The address of sender in L2.
|
||||
/// @param to The address of recipient in L1.
|
||||
/// @param amount The amount of ETH withdrawn from L2 to L1.
|
||||
/// @param data The optional calldata passed to recipient in L1.
|
||||
event FinalizeWithdrawETH(address indexed from, address indexed to, uint256 amount, bytes data);
|
||||
|
||||
/// @notice Emitted when someone deposit ETH from L1 to L2.
|
||||
/// @param from The address of sender in L1.
|
||||
/// @param to The address of recipient in L2.
|
||||
/// @param amount The amount of ETH will be deposited from L1 to L2.
|
||||
/// @param data The optional calldata passed to recipient in L2.
|
||||
event DepositETH(address indexed from, address indexed to, uint256 amount, bytes data);
|
||||
/// @notice Emitted when someone deposit ETH from L1 to L2.
|
||||
/// @param from The address of sender in L1.
|
||||
/// @param to The address of recipient in L2.
|
||||
/// @param amount The amount of ETH will be deposited from L1 to L2.
|
||||
/// @param data The optional calldata passed to recipient in L2.
|
||||
event DepositETH(address indexed from, address indexed to, uint256 amount, bytes data);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Deposit ETH to caller's account in L2.
|
||||
/// @param amount The amount of ETH to be deposited.
|
||||
/// @param gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositETH(uint256 amount, uint256 gasLimit) external payable;
|
||||
/// @notice Deposit ETH to caller's account in L2.
|
||||
/// @param amount The amount of ETH to be deposited.
|
||||
/// @param gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositETH(uint256 amount, uint256 gasLimit) external payable;
|
||||
|
||||
/// @notice Deposit ETH to some recipient's account in L2.
|
||||
/// @param to The address of recipient's account on L2.
|
||||
/// @param amount The amount of ETH to be deposited.
|
||||
/// @param gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositETH(
|
||||
address to,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit ETH to some recipient's account in L2.
|
||||
/// @param to The address of recipient's account on L2.
|
||||
/// @param amount The amount of ETH to be deposited.
|
||||
/// @param gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositETH(
|
||||
address to,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Deposit ETH to some recipient's account in L2 and call the target contract.
|
||||
/// @param to The address of recipient's account on L2.
|
||||
/// @param amount The amount of ETH to be deposited.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
/// @param gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositETHAndCall(
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
/// @notice Deposit ETH to some recipient's account in L2 and call the target contract.
|
||||
/// @param to The address of recipient's account on L2.
|
||||
/// @param amount The amount of ETH to be deposited.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
/// @param gasLimit Gas limit required to complete the deposit on L2.
|
||||
function depositETHAndCall(
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Complete ETH withdraw from L2 to L1 and send fund to recipient's account in L1.
|
||||
/// @dev This function should only be called by L1ScrollMessenger.
|
||||
/// This function should also only be called by L1ETHGateway in L2.
|
||||
/// @param from The address of account who withdraw ETH in L2.
|
||||
/// @param to The address of recipient in L1 to receive ETH.
|
||||
/// @param amount The amount of ETH to withdraw.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
function finalizeWithdrawETH(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data
|
||||
) external payable;
|
||||
/// @notice Complete ETH withdraw from L2 to L1 and send fund to recipient's account in L1.
|
||||
/// @dev This function should only be called by L1ScrollMessenger.
|
||||
/// This function should also only be called by L1ETHGateway in L2.
|
||||
/// @param from The address of account who withdraw ETH in L2.
|
||||
/// @param to The address of recipient in L1 to receive ETH.
|
||||
/// @param amount The amount of ETH to withdraw.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
function finalizeWithdrawETH(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data
|
||||
) external payable;
|
||||
}
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { IL1ETHGateway } from "./IL1ETHGateway.sol";
|
||||
import { IL1ERC20Gateway } from "./IL1ERC20Gateway.sol";
|
||||
import {IL1ETHGateway} from "./IL1ETHGateway.sol";
|
||||
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
|
||||
|
||||
interface IL1GatewayRouter is IL1ETHGateway, IL1ERC20Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when the address of ETH Gateway is updated.
|
||||
/// @param ethGateway The address of new ETH Gateway.
|
||||
event SetETHGateway(address indexed ethGateway);
|
||||
/// @notice Emitted when the address of ETH Gateway is updated.
|
||||
/// @param ethGateway The address of new ETH Gateway.
|
||||
event SetETHGateway(address indexed ethGateway);
|
||||
|
||||
/// @notice Emitted when the address of default ERC20 Gateway is updated.
|
||||
/// @param defaultERC20Gateway The address of new default ERC20 Gateway.
|
||||
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway);
|
||||
/// @notice Emitted when the address of default ERC20 Gateway is updated.
|
||||
/// @param defaultERC20Gateway The address of new default ERC20 Gateway.
|
||||
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway);
|
||||
|
||||
/// @notice Emitted when the `gateway` for `token` is updated.
|
||||
/// @param token The address of token updated.
|
||||
/// @param gateway The corresponding address of gateway updated.
|
||||
event SetERC20Gateway(address indexed token, address indexed gateway);
|
||||
/// @notice Emitted when the `gateway` for `token` is updated.
|
||||
/// @param token The address of token updated.
|
||||
/// @param gateway The corresponding address of gateway updated.
|
||||
event SetERC20Gateway(address indexed token, address indexed gateway);
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
||||
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
||||
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
|
||||
|
||||
import { IL2ERC20Gateway } from "../../L2/gateways/IL2ERC20Gateway.sol";
|
||||
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
|
||||
import { IL1ERC20Gateway } from "./IL1ERC20Gateway.sol";
|
||||
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
|
||||
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
|
||||
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
|
||||
|
||||
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import { L1ERC20Gateway } from "./L1ERC20Gateway.sol";
|
||||
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
|
||||
|
||||
/// @title L1CustomERC20Gateway
|
||||
/// @notice The `L1CustomERC20Gateway` is used to deposit custom ERC20 compatible tokens in layer 1 and
|
||||
@@ -19,139 +19,139 @@ import { L1ERC20Gateway } from "./L1ERC20Gateway.sol";
|
||||
/// @dev The deposited tokens are held in this gateway. On finalizing withdraw, the corresponding
|
||||
/// tokens will be transfer to the recipient directly.
|
||||
contract L1CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20Gateway {
|
||||
using SafeERC20Upgradeable for IERC20Upgradeable;
|
||||
using SafeERC20Upgradeable for IERC20Upgradeable;
|
||||
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when token mapping for ERC20 token is updated.
|
||||
/// @param _l1Token The address of ERC20 token in layer 1.
|
||||
/// @param _l2Token The address of corresponding ERC20 token in layer 2.
|
||||
event UpdateTokenMapping(address _l1Token, address _l2Token);
|
||||
/// @notice Emitted when token mapping for ERC20 token is updated.
|
||||
/// @param _l1Token The address of ERC20 token in layer 1.
|
||||
/// @param _l2Token The address of corresponding ERC20 token in layer 2.
|
||||
event UpdateTokenMapping(address _l1Token, address _l2Token);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from l1 token address to l2 token address for ERC20 token.
|
||||
mapping(address => address) public tokenMapping;
|
||||
/// @notice Mapping from l1 token address to l2 token address for ERC20 token.
|
||||
mapping(address => address) public tokenMapping;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
/// @notice Initialize the storage of L1CustomERC20Gateway.
|
||||
/// @param _counterpart The address of L2CustomERC20Gateway in L2.
|
||||
/// @param _router The address of L1GatewayRouter.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
/// @notice Initialize the storage of L1CustomERC20Gateway.
|
||||
/// @param _counterpart The address of L2CustomERC20Gateway in L2.
|
||||
/// @param _router The address of L1GatewayRouter.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function getL2ERC20Address(address _l1Token) public view override returns (address) {
|
||||
return tokenMapping[_l1Token];
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function finalizeWithdrawERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(msg.value == 0, "nonzero msg.value");
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
// @note can possible trigger reentrant call to this contract or messenger,
|
||||
// but it seems not a big problem.
|
||||
IERC20Upgradeable(_l1Token).safeTransfer(_to, _amount);
|
||||
|
||||
// @todo forward `_data` to `_to` in the near future
|
||||
|
||||
emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 1 to layer 2 token mapping.
|
||||
/// @param _l1Token The address of ERC20 token in layer 1.
|
||||
/// @param _l2Token The address of corresponding ERC20 token in layer 2.
|
||||
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
|
||||
require(_l2Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l1Token] = _l2Token;
|
||||
|
||||
emit UpdateTokenMapping(_l1Token, _l2Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L1ERC20Gateway
|
||||
function _deposit(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override nonReentrant {
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "no corresponding l2 token");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
{
|
||||
// common practice to handle fee on transfer token.
|
||||
uint256 _before = IERC20Upgradeable(_token).balanceOf(address(this));
|
||||
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
uint256 _after = IERC20Upgradeable(_token).balanceOf(address(this));
|
||||
// no unchecked here, since some weird token may return arbitrary balance.
|
||||
_amount = _after - _before;
|
||||
// ignore weird fee on transfer token
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function getL2ERC20Address(address _l1Token) public view override returns (address) {
|
||||
return tokenMapping[_l1Token];
|
||||
}
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
// 4. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, 0, _message, _gasLimit);
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function finalizeWithdrawERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(msg.value == 0, "nonzero msg.value");
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
emit DepositERC20(_token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
// @note can possible trigger reentrant call to this contract or messenger,
|
||||
// but it seems not a big problem.
|
||||
IERC20Upgradeable(_l1Token).safeTransfer(_to, _amount);
|
||||
|
||||
// @todo forward `_data` to `_to` in the near future
|
||||
|
||||
emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 1 to layer 2 token mapping.
|
||||
/// @param _l1Token The address of ERC20 token in layer 1.
|
||||
/// @param _l2Token The address of corresponding ERC20 token in layer 2.
|
||||
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
|
||||
require(_l2Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l1Token] = _l2Token;
|
||||
|
||||
emit UpdateTokenMapping(_l1Token, _l2Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L1ERC20Gateway
|
||||
function _deposit(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override nonReentrant {
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "no corresponding l2 token");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
{
|
||||
// common practice to handle fee on transfer token.
|
||||
uint256 _before = IERC20Upgradeable(_token).balanceOf(address(this));
|
||||
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
uint256 _after = IERC20Upgradeable(_token).balanceOf(address(this));
|
||||
// no unchecked here, since some weird token may return arbitrary balance.
|
||||
_amount = _after - _before;
|
||||
// ignore weird fee on transfer token
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
}
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
|
||||
// 4. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit DepositERC20(_token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import { IERC1155Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
|
||||
import { ERC1155HolderUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {IERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
|
||||
import {ERC1155HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
|
||||
|
||||
import { IL2ERC1155Gateway } from "../../L2/gateways/IL2ERC1155Gateway.sol";
|
||||
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
|
||||
import { IL1ERC1155Gateway } from "./IL1ERC1155Gateway.sol";
|
||||
import {IL2ERC1155Gateway} from "../../L2/gateways/IL2ERC1155Gateway.sol";
|
||||
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
|
||||
import {IL1ERC1155Gateway} from "./IL1ERC1155Gateway.sol";
|
||||
|
||||
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
|
||||
/// @title L1ERC1155Gateway
|
||||
/// @notice The `L1ERC1155Gateway` is used to deposit ERC1155 compatible NFT in layer 1 and
|
||||
@@ -21,209 +21,209 @@ import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol
|
||||
/// This will be changed if we have more specific scenarios.
|
||||
// @todo Current implementation doesn't support calling from `L1GatewayRouter`.
|
||||
contract L1ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC1155Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when token mapping for ERC1155 token is updated.
|
||||
/// @param _l1Token The address of ERC1155 token in layer 1.
|
||||
/// @param _l1Token The address of corresponding ERC1155 token in layer 2.
|
||||
event UpdateTokenMapping(address _l1Token, address _l2Token);
|
||||
/// @notice Emitted when token mapping for ERC1155 token is updated.
|
||||
/// @param _l1Token The address of ERC1155 token in layer 1.
|
||||
/// @param _l1Token The address of corresponding ERC1155 token in layer 2.
|
||||
event UpdateTokenMapping(address _l1Token, address _l2Token);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from l1 token address to l2 token address for ERC1155 NFT.
|
||||
mapping(address => address) public tokenMapping;
|
||||
/// @notice Mapping from l1 token address to l2 token address for ERC1155 NFT.
|
||||
mapping(address => address) public tokenMapping;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
/// @notice Initialize the storage of L1ERC1155Gateway.
|
||||
/// @param _counterpart The address of L2ERC1155Gateway in L2.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(address _counterpart, address _messenger) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function depositERC1155(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC1155(_token, msg.sender, _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function depositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC1155(_token, _to, _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function batchDepositERC1155(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC1155(_token, msg.sender, _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function batchDepositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC1155(_token, _to, _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function finalizeWithdrawERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
IERC1155Upgradeable(_l1Token).safeTransferFrom(address(this), _to, _tokenId, _amount, "");
|
||||
|
||||
emit FinalizeWithdrawERC1155(_l1Token, _l2Token, _from, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function finalizeBatchWithdrawERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
IERC1155Upgradeable(_l1Token).safeBatchTransferFrom(address(this), _to, _tokenIds, _amounts, "");
|
||||
|
||||
emit FinalizeBatchWithdrawERC1155(_l1Token, _l2Token, _from, _to, _tokenIds, _amounts);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 2 token mapping.
|
||||
/// @param _l1Token The address of ERC1155 token in layer 1.
|
||||
/// @param _l1Token The address of corresponding ERC1155 token in layer 2.
|
||||
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
|
||||
require(_l2Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l1Token] = _l2Token;
|
||||
|
||||
emit UpdateTokenMapping(_l1Token, _l2Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to deposit ERC1155 NFT to layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _amount The amount of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function _depositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC1155Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenId, _amount, "");
|
||||
|
||||
// 2. Generate message passed to L2ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC1155Gateway.finalizeDepositERC1155.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenId,
|
||||
_amount
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit DepositERC1155(_token, _l2Token, msg.sender, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch deposit ERC1155 NFT to layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _amounts The list of corresponding number of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function _batchDepositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_tokenIds.length > 0, "no token to deposit");
|
||||
require(_tokenIds.length == _amounts.length, "length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _amounts.length; i++) {
|
||||
require(_amounts[i] > 0, "deposit zero amount");
|
||||
/// @notice Initialize the storage of L1ERC1155Gateway.
|
||||
/// @param _counterpart The address of L2ERC1155Gateway in L2.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(address _counterpart, address _messenger) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
|
||||
}
|
||||
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "token not supported");
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC1155Upgradeable(_token).safeBatchTransferFrom(msg.sender, address(this), _tokenIds, _amounts, "");
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function depositERC1155(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC1155(_token, msg.sender, _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L2ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC1155Gateway.finalizeBatchDepositERC1155.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenIds,
|
||||
_amounts
|
||||
);
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function depositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC1155(_token, _to, _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, 0, _message, _gasLimit);
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function batchDepositERC1155(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC1155(_token, msg.sender, _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
emit BatchDepositERC1155(_token, _l2Token, msg.sender, _to, _tokenIds, _amounts);
|
||||
}
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function batchDepositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC1155(_token, _to, _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function finalizeWithdrawERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
IERC1155Upgradeable(_l1Token).safeTransferFrom(address(this), _to, _tokenId, _amount, "");
|
||||
|
||||
emit FinalizeWithdrawERC1155(_l1Token, _l2Token, _from, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC1155Gateway
|
||||
function finalizeBatchWithdrawERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
IERC1155Upgradeable(_l1Token).safeBatchTransferFrom(address(this), _to, _tokenIds, _amounts, "");
|
||||
|
||||
emit FinalizeBatchWithdrawERC1155(_l1Token, _l2Token, _from, _to, _tokenIds, _amounts);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 2 token mapping.
|
||||
/// @param _l1Token The address of ERC1155 token in layer 1.
|
||||
/// @param _l1Token The address of corresponding ERC1155 token in layer 2.
|
||||
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
|
||||
require(_l2Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l1Token] = _l2Token;
|
||||
|
||||
emit UpdateTokenMapping(_l1Token, _l2Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to deposit ERC1155 NFT to layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _amount The amount of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function _depositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC1155Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenId, _amount, "");
|
||||
|
||||
// 2. Generate message passed to L2ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC1155Gateway.finalizeDepositERC1155.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenId,
|
||||
_amount
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit DepositERC1155(_token, _l2Token, msg.sender, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch deposit ERC1155 NFT to layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _amounts The list of corresponding number of token to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function _batchDepositERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_tokenIds.length > 0, "no token to deposit");
|
||||
require(_tokenIds.length == _amounts.length, "length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _amounts.length; i++) {
|
||||
require(_amounts[i] > 0, "deposit zero amount");
|
||||
}
|
||||
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC1155Upgradeable(_token).safeBatchTransferFrom(msg.sender, address(this), _tokenIds, _amounts, "");
|
||||
|
||||
// 2. Generate message passed to L2ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC1155Gateway.finalizeBatchDepositERC1155.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenIds,
|
||||
_amounts
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit BatchDepositERC1155(_token, _l2Token, msg.sender, _to, _tokenIds, _amounts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,61 +2,61 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { IL1ERC20Gateway } from "./IL1ERC20Gateway.sol";
|
||||
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
|
||||
abstract contract L1ERC20Gateway is IL1ERC20Gateway {
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_token, _to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_token, _to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_token, _to, _amount, _data, _gasLimit);
|
||||
}
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_token, _to, _amount, _data, _gasLimit);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to do all the deposit operations.
|
||||
///
|
||||
/// @param _token The token to deposit.
|
||||
/// @param _to The recipient address to recieve the token in L2.
|
||||
/// @param _amount The amount of token to deposit.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function _deposit(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual;
|
||||
/// @dev Internal function to do all the deposit operations.
|
||||
///
|
||||
/// @param _token The token to deposit.
|
||||
/// @param _to The recipient address to recieve the token in L2.
|
||||
/// @param _amount The amount of token to deposit.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function _deposit(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import { IERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
|
||||
import { ERC721HolderUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
|
||||
import {ERC721HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
|
||||
|
||||
import { IL2ERC721Gateway } from "../../L2/gateways/IL2ERC721Gateway.sol";
|
||||
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
|
||||
import { IL1ERC721Gateway } from "./IL1ERC721Gateway.sol";
|
||||
import {IL2ERC721Gateway} from "../../L2/gateways/IL2ERC721Gateway.sol";
|
||||
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
|
||||
import {IL1ERC721Gateway} from "./IL1ERC721Gateway.sol";
|
||||
|
||||
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
|
||||
/// @title L1ERC721Gateway
|
||||
/// @notice The `L1ERC721Gateway` is used to deposit ERC721 compatible NFT in layer 1 and
|
||||
@@ -21,194 +21,194 @@ import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol
|
||||
/// This will be changed if we have more specific scenarios.
|
||||
// @todo Current implementation doesn't support calling from `L1GatewayRouter`.
|
||||
contract L1ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC721Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when token mapping for ERC721 token is updated.
|
||||
/// @param _l1Token The address of ERC721 token in layer 1.
|
||||
/// @param _l1Token The address of corresponding ERC721 token in layer 2.
|
||||
event UpdateTokenMapping(address _l1Token, address _l2Token);
|
||||
/// @notice Emitted when token mapping for ERC721 token is updated.
|
||||
/// @param _l1Token The address of ERC721 token in layer 1.
|
||||
/// @param _l1Token The address of corresponding ERC721 token in layer 2.
|
||||
event UpdateTokenMapping(address _l1Token, address _l2Token);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from l1 token address to l2 token address for ERC721 NFT.
|
||||
mapping(address => address) public tokenMapping;
|
||||
/// @notice Mapping from l1 token address to l2 token address for ERC721 NFT.
|
||||
mapping(address => address) public tokenMapping;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
/// @notice Initialize the storage of L1ERC721Gateway.
|
||||
/// @param _counterpart The address of L2ERC721Gateway in L2.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(address _counterpart, address _messenger) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function depositERC721(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC721(_token, msg.sender, _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function depositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC721(_token, _to, _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function batchDepositERC721(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC721(_token, msg.sender, _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function batchDepositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC721(_token, _to, _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function finalizeWithdrawERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
IERC721Upgradeable(_l1Token).safeTransferFrom(address(this), _to, _tokenId);
|
||||
|
||||
emit FinalizeWithdrawERC721(_l1Token, _l2Token, _from, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function finalizeBatchWithdrawERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
IERC721Upgradeable(_l1Token).safeTransferFrom(address(this), _to, _tokenIds[i]);
|
||||
/// @notice Initialize the storage of L1ERC721Gateway.
|
||||
/// @param _counterpart The address of L2ERC721Gateway in L2.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(address _counterpart, address _messenger) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
|
||||
}
|
||||
|
||||
emit FinalizeBatchWithdrawERC721(_l1Token, _l2Token, _from, _to, _tokenIds);
|
||||
}
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 2 token mapping.
|
||||
/// @param _l1Token The address of ERC721 token in layer 1.
|
||||
/// @param _l1Token The address of corresponding ERC721 token in layer 2.
|
||||
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
|
||||
require(_l2Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l1Token] = _l2Token;
|
||||
|
||||
emit UpdateTokenMapping(_l1Token, _l2Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to deposit ERC721 NFT to layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function _depositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC721Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenId);
|
||||
|
||||
// 2. Generate message passed to L2ERC721Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC721Gateway.finalizeDepositERC721.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenId
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit DepositERC721(_token, _l2Token, msg.sender, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch deposit ERC721 NFT to layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function _batchDepositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_tokenIds.length > 0, "no token to deposit");
|
||||
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
IERC721Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenIds[i]);
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function depositERC721(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC721(_token, msg.sender, _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L2ERC721Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC721Gateway.finalizeBatchDepositERC721.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenIds
|
||||
);
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function depositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_depositERC721(_token, _to, _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, 0, _message, _gasLimit);
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function batchDepositERC721(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC721(_token, msg.sender, _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
emit BatchDepositERC721(_token, _l2Token, msg.sender, _to, _tokenIds);
|
||||
}
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function batchDepositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_batchDepositERC721(_token, _to, _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function finalizeWithdrawERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
IERC721Upgradeable(_l1Token).safeTransferFrom(address(this), _to, _tokenId);
|
||||
|
||||
emit FinalizeWithdrawERC721(_l1Token, _l2Token, _from, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC721Gateway
|
||||
function finalizeBatchWithdrawERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
require(_l2Token == tokenMapping[_l1Token], "l2 token mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
IERC721Upgradeable(_l1Token).safeTransferFrom(address(this), _to, _tokenIds[i]);
|
||||
}
|
||||
|
||||
emit FinalizeBatchWithdrawERC721(_l1Token, _l2Token, _from, _to, _tokenIds);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 2 token mapping.
|
||||
/// @param _l1Token The address of ERC721 token in layer 1.
|
||||
/// @param _l1Token The address of corresponding ERC721 token in layer 2.
|
||||
function updateTokenMapping(address _l1Token, address _l2Token) external onlyOwner {
|
||||
require(_l2Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l1Token] = _l2Token;
|
||||
|
||||
emit UpdateTokenMapping(_l1Token, _l2Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to deposit ERC721 NFT to layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function _depositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IERC721Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenId);
|
||||
|
||||
// 2. Generate message passed to L2ERC721Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC721Gateway.finalizeDepositERC721.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenId
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit DepositERC721(_token, _l2Token, msg.sender, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch deposit ERC721 NFT to layer 2.
|
||||
/// @param _token The address of ERC721 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to deposit.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the deposit on layer 2.
|
||||
function _batchDepositERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_tokenIds.length > 0, "no token to deposit");
|
||||
|
||||
address _l2Token = tokenMapping[_token];
|
||||
require(_l2Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
IERC721Upgradeable(_token).safeTransferFrom(msg.sender, address(this), _tokenIds[i]);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L2ERC721Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC721Gateway.finalizeBatchDepositERC721.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenIds
|
||||
);
|
||||
|
||||
// 3. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit BatchDepositERC721(_token, _l2Token, msg.sender, _to, _tokenIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
|
||||
import { IL2ETHGateway } from "../../L2/gateways/IL2ETHGateway.sol";
|
||||
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
|
||||
import { IL1ETHGateway } from "./IL1ETHGateway.sol";
|
||||
import {IL2ETHGateway} from "../../L2/gateways/IL2ETHGateway.sol";
|
||||
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
|
||||
import {IL1ETHGateway} from "./IL1ETHGateway.sol";
|
||||
|
||||
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
|
||||
/// @title L1ETHGateway
|
||||
/// @notice The `L1ETHGateway` is used to deposit ETH in layer 1 and
|
||||
@@ -16,103 +16,103 @@ import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol
|
||||
/// @dev The deposited ETH tokens are held in this gateway. On finalizing withdraw, the corresponding
|
||||
/// ETH will be transfer to the recipient directly.
|
||||
contract L1ETHGateway is Initializable, ScrollGatewayBase, IL1ETHGateway {
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
/// @notice Initialize the storage of L1ETHGateway.
|
||||
/// @param _counterpart The address of L2ETHGateway in L2.
|
||||
/// @param _router The address of L1GatewayRouter.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
_deposit(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
_deposit(_to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETHAndCall(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_to, _amount, _data, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function finalizeWithdrawETH(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
// @note can possible trigger reentrant call to this contract or messenger,
|
||||
// but it seems not a big problem.
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool _success, ) = _to.call{ value: _amount }("");
|
||||
require(_success, "ETH transfer failed");
|
||||
|
||||
// @todo farward _data to `_to` in near future.
|
||||
|
||||
emit FinalizeWithdrawETH(_from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev The internal ETH deposit implementation.
|
||||
/// @param _to The address of recipient's account on L2.
|
||||
/// @param _amount The amount of ETH to be deposited.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function _deposit(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_amount > 0, "deposit zero eth");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
/// @notice Initialize the storage of L1ETHGateway.
|
||||
/// @param _counterpart The address of L2ETHGateway in L2.
|
||||
/// @param _router The address of L1GatewayRouter.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L1ScrollMessenger.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ETHGateway.finalizeDepositETH.selector,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
IL1ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, _amount, _message, _gasLimit);
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
_deposit(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
emit DepositETH(_from, _to, _amount, _data);
|
||||
}
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
_deposit(_to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETHAndCall(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_deposit(_to, _amount, _data, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function finalizeWithdrawETH(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
// @note can possible trigger reentrant call to this contract or messenger,
|
||||
// but it seems not a big problem.
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool _success, ) = _to.call{value: _amount}("");
|
||||
require(_success, "ETH transfer failed");
|
||||
|
||||
// @todo farward _data to `_to` in near future.
|
||||
|
||||
emit FinalizeWithdrawETH(_from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev The internal ETH deposit implementation.
|
||||
/// @param _to The address of recipient's account on L2.
|
||||
/// @param _amount The amount of ETH to be deposited.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
/// @param _gasLimit Gas limit required to complete the deposit on L2.
|
||||
function _deposit(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_amount > 0, "deposit zero eth");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L1ScrollMessenger.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ETHGateway.finalizeDepositETH.selector,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, _amount, _message, _gasLimit);
|
||||
|
||||
emit DepositETH(_from, _to, _amount, _data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
|
||||
import { IL2GatewayRouter } from "../../L2/gateways/IL2GatewayRouter.sol";
|
||||
import { IScrollGateway } from "../../libraries/gateway/IScrollGateway.sol";
|
||||
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
|
||||
import { IL1ETHGateway } from "./IL1ETHGateway.sol";
|
||||
import { IL1ERC20Gateway } from "./IL1ERC20Gateway.sol";
|
||||
import { IL1GatewayRouter } from "./IL1GatewayRouter.sol";
|
||||
import {IL2GatewayRouter} from "../../L2/gateways/IL2GatewayRouter.sol";
|
||||
import {IScrollGateway} from "../../libraries/gateway/IScrollGateway.sol";
|
||||
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
|
||||
import {IL1ETHGateway} from "./IL1ETHGateway.sol";
|
||||
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
|
||||
import {IL1GatewayRouter} from "./IL1GatewayRouter.sol";
|
||||
|
||||
/// @title L1GatewayRouter
|
||||
/// @notice The `L1GatewayRouter` is the main entry for depositing Ether and ERC20 tokens.
|
||||
@@ -17,198 +17,198 @@ import { IL1GatewayRouter } from "./IL1GatewayRouter.sol";
|
||||
/// @dev One can also use this contract to query L1/L2 token address mapping.
|
||||
/// In the future, ERC-721 and ERC-1155 tokens will be added to the router too.
|
||||
contract L1GatewayRouter is OwnableUpgradeable, IL1GatewayRouter {
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice The address of L1ETHGateway.
|
||||
address public ethGateway;
|
||||
/// @notice The address of L1ETHGateway.
|
||||
address public ethGateway;
|
||||
|
||||
/// @notice The addess of default ERC20 gateway, normally the L1StandardERC20Gateway contract.
|
||||
address public defaultERC20Gateway;
|
||||
/// @notice The addess of default ERC20 gateway, normally the L1StandardERC20Gateway contract.
|
||||
address public defaultERC20Gateway;
|
||||
|
||||
/// @notice Mapping from ERC20 token address to corresponding L1ERC20Gateway.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public ERC20Gateway;
|
||||
/// @notice Mapping from ERC20 token address to corresponding L1ERC20Gateway.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public ERC20Gateway;
|
||||
|
||||
// @todo: add ERC721/ERC1155 Gateway mapping.
|
||||
// @todo: add ERC721/ERC1155 Gateway mapping.
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
/// @notice Initialize the storage of L1GatewayRouter.
|
||||
/// @param _ethGateway The address of L1ETHGateway contract.
|
||||
/// @param _defaultERC20Gateway The address of default ERC20 Gateway contract.
|
||||
function initialize(address _ethGateway, address _defaultERC20Gateway) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
/// @notice Initialize the storage of L1GatewayRouter.
|
||||
/// @param _ethGateway The address of L1ETHGateway contract.
|
||||
/// @param _defaultERC20Gateway The address of default ERC20 Gateway contract.
|
||||
function initialize(address _ethGateway, address _defaultERC20Gateway) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
|
||||
// it can be zero during initialization
|
||||
if (_defaultERC20Gateway != address(0)) {
|
||||
defaultERC20Gateway = _defaultERC20Gateway;
|
||||
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
|
||||
// it can be zero during initialization
|
||||
if (_defaultERC20Gateway != address(0)) {
|
||||
defaultERC20Gateway = _defaultERC20Gateway;
|
||||
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
|
||||
}
|
||||
|
||||
// it can be zero during initialization
|
||||
if (_ethGateway != address(0)) {
|
||||
ethGateway = _ethGateway;
|
||||
emit SetETHGateway(_ethGateway);
|
||||
}
|
||||
}
|
||||
|
||||
// it can be zero during initialization
|
||||
if (_ethGateway != address(0)) {
|
||||
ethGateway = _ethGateway;
|
||||
emit SetETHGateway(_ethGateway);
|
||||
}
|
||||
}
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function getL2ERC20Address(address _l1Address) external view override returns (address) {
|
||||
address _gateway = getERC20Gateway(_l1Address);
|
||||
if (_gateway == address(0)) {
|
||||
return address(0);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function getL2ERC20Address(address _l1Address) external view override returns (address) {
|
||||
address _gateway = getERC20Gateway(_l1Address);
|
||||
if (_gateway == address(0)) {
|
||||
return address(0);
|
||||
return IL1ERC20Gateway(_gateway).getL2ERC20Address(_l1Address);
|
||||
}
|
||||
|
||||
return IL1ERC20Gateway(_gateway).getL2ERC20Address(_l1Address);
|
||||
}
|
||||
|
||||
/// @notice Return the corresponding gateway address for given token address.
|
||||
/// @param _token The address of token to query.
|
||||
function getERC20Gateway(address _token) public view returns (address) {
|
||||
address _gateway = ERC20Gateway[_token];
|
||||
if (_gateway == address(0)) {
|
||||
_gateway = defaultERC20Gateway;
|
||||
/// @notice Return the corresponding gateway address for given token address.
|
||||
/// @param _token The address of token to query.
|
||||
function getERC20Gateway(address _token) public view returns (address) {
|
||||
address _gateway = ERC20Gateway[_token];
|
||||
if (_gateway == address(0)) {
|
||||
_gateway = defaultERC20Gateway;
|
||||
}
|
||||
return _gateway;
|
||||
}
|
||||
return _gateway;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Public Mutated Functions from L1ERC20Gateway *
|
||||
************************************************/
|
||||
/*************************************************
|
||||
* Public Mutating Functions from L1ERC20Gateway *
|
||||
*************************************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
depositERC20AndCall(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
depositERC20AndCall(_token, _to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
address _gateway = getERC20Gateway(_token);
|
||||
require(_gateway != address(0), "no gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
|
||||
IL1ERC20Gateway(_gateway).depositERC20AndCall{ value: msg.value }(_token, _to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function finalizeWithdrawERC20(
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external payable virtual override {
|
||||
revert("should never be called");
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Public Mutated Functions from L1ETHGateway *
|
||||
**********************************************/
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
depositETHAndCall(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
depositETHAndCall(_to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETHAndCall(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
address _gateway = ethGateway;
|
||||
require(_gateway != address(0), "eth gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
|
||||
IL1ETHGateway(_gateway).depositETHAndCall{ value: msg.value }(_to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function finalizeWithdrawETH(
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external payable virtual override {
|
||||
revert("should never be called");
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update the address of ETH gateway contract.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _ethGateway The address to update.
|
||||
function setETHGateway(address _ethGateway) external onlyOwner {
|
||||
ethGateway = _ethGateway;
|
||||
|
||||
emit SetETHGateway(_ethGateway);
|
||||
}
|
||||
|
||||
/// @notice Update the address of default ERC20 gateway contract.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _defaultERC20Gateway The address to update.
|
||||
function setDefaultERC20Gateway(address _defaultERC20Gateway) external onlyOwner {
|
||||
defaultERC20Gateway = _defaultERC20Gateway;
|
||||
|
||||
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
|
||||
}
|
||||
|
||||
/// @notice Update the mapping from token address to gateway address.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _tokens The list of addresses of tokens to update.
|
||||
/// @param _gateways The list of addresses of gateways to update.
|
||||
function setERC20Gateway(address[] memory _tokens, address[] memory _gateways) external onlyOwner {
|
||||
require(_tokens.length == _gateways.length, "length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
||||
ERC20Gateway[_tokens[i]] = _gateways[i];
|
||||
|
||||
emit SetERC20Gateway(_tokens[i], _gateways[i]);
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
depositERC20AndCall(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
depositERC20AndCall(_token, _to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function depositERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
address _gateway = getERC20Gateway(_token);
|
||||
require(_gateway != address(0), "no gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
|
||||
IL1ERC20Gateway(_gateway).depositERC20AndCall{value: msg.value}(_token, _to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function finalizeWithdrawERC20(
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external payable virtual override {
|
||||
revert("should never be called");
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Public Mutating Functions from L1ETHGateway *
|
||||
***********************************************/
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
depositETHAndCall(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETH(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
depositETHAndCall(_to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function depositETHAndCall(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
address _gateway = ethGateway;
|
||||
require(_gateway != address(0), "eth gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
|
||||
IL1ETHGateway(_gateway).depositETHAndCall{value: msg.value}(_to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ETHGateway
|
||||
function finalizeWithdrawETH(
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external payable virtual override {
|
||||
revert("should never be called");
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update the address of ETH gateway contract.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _ethGateway The address to update.
|
||||
function setETHGateway(address _ethGateway) external onlyOwner {
|
||||
ethGateway = _ethGateway;
|
||||
|
||||
emit SetETHGateway(_ethGateway);
|
||||
}
|
||||
|
||||
/// @notice Update the address of default ERC20 gateway contract.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _defaultERC20Gateway The address to update.
|
||||
function setDefaultERC20Gateway(address _defaultERC20Gateway) external onlyOwner {
|
||||
defaultERC20Gateway = _defaultERC20Gateway;
|
||||
|
||||
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
|
||||
}
|
||||
|
||||
/// @notice Update the mapping from token address to gateway address.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _tokens The list of addresses of tokens to update.
|
||||
/// @param _gateways The list of addresses of gateways to update.
|
||||
function setERC20Gateway(address[] memory _tokens, address[] memory _gateways) external onlyOwner {
|
||||
require(_tokens.length == _gateways.length, "length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
||||
ERC20Gateway[_tokens[i]] = _gateways[i];
|
||||
|
||||
emit SetERC20Gateway(_tokens[i], _gateways[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
|
||||
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
|
||||
|
||||
import { IERC20Metadata } from "../../interfaces/IERC20Metadata.sol";
|
||||
import { IL2ERC20Gateway } from "../../L2/gateways/IL2ERC20Gateway.sol";
|
||||
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
|
||||
import { IL1ERC20Gateway } from "./IL1ERC20Gateway.sol";
|
||||
import {IERC20Metadata} from "../../interfaces/IERC20Metadata.sol";
|
||||
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
|
||||
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
|
||||
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
|
||||
|
||||
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import { L1ERC20Gateway } from "./L1ERC20Gateway.sol";
|
||||
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
|
||||
|
||||
/// @title L1StandardERC20Gateway
|
||||
/// @notice The `L1StandardERC20Gateway` is used to deposit standard ERC20 tokens in layer 1 and
|
||||
@@ -22,147 +22,147 @@ import { L1ERC20Gateway } from "./L1ERC20Gateway.sol";
|
||||
/// token will be transfer to the recipient directly. Any ERC20 that requires non-standard functionality
|
||||
/// should use a separate gateway.
|
||||
contract L1StandardERC20Gateway is Initializable, ScrollGatewayBase, L1ERC20Gateway {
|
||||
using SafeERC20 for IERC20;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice The address of ScrollStandardERC20 implementation in L2.
|
||||
address public l2TokenImplementation;
|
||||
/// @notice The address of ScrollStandardERC20 implementation in L2.
|
||||
address public l2TokenImplementation;
|
||||
|
||||
/// @notice The address of ScrollStandardERC20Factory contract in L2.
|
||||
address public l2TokenFactory;
|
||||
/// @notice The address of ScrollStandardERC20Factory contract in L2.
|
||||
address public l2TokenFactory;
|
||||
|
||||
/// @notice Mapping from l1 token address to l2 token address.
|
||||
/// @dev This is not necessary, since we can compute the address directly. But, we use this mapping
|
||||
/// to keep track on whether we have deployed the token in L2 using the L2ScrollStandardERC20Factory and
|
||||
/// pass deploy data on first call to the token.
|
||||
mapping(address => address) private tokenMapping;
|
||||
/// @notice Mapping from l1 token address to l2 token address.
|
||||
/// @dev This is not necessary, since we can compute the address directly. But, we use this mapping
|
||||
/// to keep track on whether we have deployed the token in L2 using the L2ScrollStandardERC20Factory and
|
||||
/// pass deploy data on first call to the token.
|
||||
mapping(address => address) private tokenMapping;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
/// @notice Initialize the storage of L1StandardERC20Gateway.
|
||||
/// @param _counterpart The address of L2StandardERC20Gateway in L2.
|
||||
/// @param _router The address of L1GatewayRouter.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
/// @param _l2TokenImplementation The address of ScrollStandardERC20 implementation in L2.
|
||||
/// @param _l2TokenFactory The address of ScrollStandardERC20Factory contract in L2.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger,
|
||||
address _l2TokenImplementation,
|
||||
address _l2TokenFactory
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
/// @notice Initialize the storage of L1StandardERC20Gateway.
|
||||
/// @param _counterpart The address of L2StandardERC20Gateway in L2.
|
||||
/// @param _router The address of L1GatewayRouter.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
/// @param _l2TokenImplementation The address of ScrollStandardERC20 implementation in L2.
|
||||
/// @param _l2TokenFactory The address of ScrollStandardERC20Factory contract in L2.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger,
|
||||
address _l2TokenImplementation,
|
||||
address _l2TokenFactory
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
|
||||
require(_l2TokenImplementation != address(0), "zero implementation hash");
|
||||
require(_l2TokenFactory != address(0), "zero factory address");
|
||||
require(_l2TokenImplementation != address(0), "zero implementation hash");
|
||||
require(_l2TokenFactory != address(0), "zero factory address");
|
||||
|
||||
l2TokenImplementation = _l2TokenImplementation;
|
||||
l2TokenFactory = _l2TokenFactory;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function getL2ERC20Address(address _l1Token) public view override returns (address) {
|
||||
// In StandardERC20Gateway, all corresponding l2 tokens are depoyed by Create2 with salt,
|
||||
// we can calculate the l2 address directly.
|
||||
bytes32 _salt = keccak256(abi.encodePacked(counterpart, keccak256(abi.encodePacked(_l1Token))));
|
||||
|
||||
return Clones.predictDeterministicAddress(l2TokenImplementation, _salt, l2TokenFactory);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function finalizeWithdrawERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(msg.value == 0, "nonzero msg.value");
|
||||
|
||||
// @note can possible trigger reentrant call to this contract or messenger,
|
||||
// but it seems not a big problem.
|
||||
IERC20(_l1Token).safeTransfer(_to, _amount);
|
||||
|
||||
// @todo forward `_data` to `_to` in the near future
|
||||
|
||||
emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L1ERC20Gateway
|
||||
function _deposit(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override nonReentrant {
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
l2TokenImplementation = _l2TokenImplementation;
|
||||
l2TokenFactory = _l2TokenFactory;
|
||||
}
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
{
|
||||
// common practice to handle fee on transfer token.
|
||||
uint256 _before = IERC20(_token).balanceOf(address(this));
|
||||
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
uint256 _after = IERC20(_token).balanceOf(address(this));
|
||||
// no unchecked here, since some weird token may return arbitrary balance.
|
||||
_amount = _after - _before;
|
||||
// ignore weird fee on transfer token
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function getL2ERC20Address(address _l1Token) public view override returns (address) {
|
||||
// In StandardERC20Gateway, all corresponding l2 tokens are depoyed by Create2 with salt,
|
||||
// we can calculate the l2 address directly.
|
||||
bytes32 _salt = keccak256(abi.encodePacked(counterpart, keccak256(abi.encodePacked(_l1Token))));
|
||||
|
||||
return Clones.predictDeterministicAddress(l2TokenImplementation, _salt, l2TokenFactory);
|
||||
}
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
address _l2Token = tokenMapping[_token];
|
||||
bytes memory _l2Data = _data;
|
||||
if (_l2Token == address(0)) {
|
||||
// It is a new token, compute and store mapping in storage.
|
||||
_l2Token = getL2ERC20Address(_token);
|
||||
tokenMapping[_token] = _l2Token;
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
// passing symbol/name/decimal in order to deploy in L2.
|
||||
string memory _symbol = IERC20Metadata(_token).symbol();
|
||||
string memory _name = IERC20Metadata(_token).name();
|
||||
uint8 _decimals = IERC20Metadata(_token).decimals();
|
||||
_l2Data = abi.encode(_data, abi.encode(_symbol, _name, _decimals));
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function finalizeWithdrawERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(msg.value == 0, "nonzero msg.value");
|
||||
|
||||
// @note can possible trigger reentrant call to this contract or messenger,
|
||||
// but it seems not a big problem.
|
||||
IERC20(_l1Token).safeTransfer(_to, _amount);
|
||||
|
||||
// @todo forward `_data` to `_to` in the near future
|
||||
|
||||
emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_l2Data
|
||||
);
|
||||
|
||||
// 4. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, 0, _message, _gasLimit);
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
emit DepositERC20(_token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
/// @inheritdoc L1ERC20Gateway
|
||||
function _deposit(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override nonReentrant {
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
{
|
||||
// common practice to handle fee on transfer token.
|
||||
uint256 _before = IERC20(_token).balanceOf(address(this));
|
||||
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
uint256 _after = IERC20(_token).balanceOf(address(this));
|
||||
// no unchecked here, since some weird token may return arbitrary balance.
|
||||
_amount = _after - _before;
|
||||
// ignore weird fee on transfer token
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
}
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
address _l2Token = tokenMapping[_token];
|
||||
bytes memory _l2Data = _data;
|
||||
if (_l2Token == address(0)) {
|
||||
// It is a new token, compute and store mapping in storage.
|
||||
_l2Token = getL2ERC20Address(_token);
|
||||
tokenMapping[_token] = _l2Token;
|
||||
|
||||
// passing symbol/name/decimal in order to deploy in L2.
|
||||
string memory _symbol = IERC20Metadata(_token).symbol();
|
||||
string memory _name = IERC20Metadata(_token).name();
|
||||
uint8 _decimals = IERC20Metadata(_token).decimals();
|
||||
_l2Data = abi.encode(_data, abi.encode(_symbol, _name, _decimals));
|
||||
}
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
_token,
|
||||
_l2Token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_l2Data
|
||||
);
|
||||
|
||||
// 4. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit DepositERC20(_token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
|
||||
import { IWETH } from "../../interfaces/IWETH.sol";
|
||||
import { IL2ERC20Gateway } from "../../L2/gateways/IL2ERC20Gateway.sol";
|
||||
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
|
||||
import { IL1ERC20Gateway } from "./IL1ERC20Gateway.sol";
|
||||
import {IWETH} from "../../interfaces/IWETH.sol";
|
||||
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
|
||||
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
|
||||
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
|
||||
|
||||
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import { L1ERC20Gateway } from "./L1ERC20Gateway.sol";
|
||||
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
|
||||
|
||||
/// @title L1WETHGateway
|
||||
/// @notice The `L1WETHGateway` contract is used to deposit `WETH` token in layer 1 and
|
||||
@@ -22,118 +22,123 @@ import { L1ERC20Gateway } from "./L1ERC20Gateway.sol";
|
||||
/// On finalizing withdraw, the Ether will be transfered from `L1ScrollMessenger`, then
|
||||
/// wrapped as WETH and finally transfer to recipient.
|
||||
contract L1WETHGateway is Initializable, ScrollGatewayBase, L1ERC20Gateway {
|
||||
using SafeERC20 for IERC20;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
|
||||
/// @notice The address of L2 WETH address.
|
||||
address public immutable l2WETH;
|
||||
/// @notice The address of L2 WETH address.
|
||||
address public immutable l2WETH;
|
||||
|
||||
/// @notice The address of L1 WETH address.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
address public immutable WETH;
|
||||
/// @notice The address of L1 WETH address.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
address public immutable WETH;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
constructor(address _WETH, address _l2WETH) {
|
||||
WETH = _WETH;
|
||||
l2WETH = _l2WETH;
|
||||
}
|
||||
|
||||
/// @notice Initialize the storage of L1WETHGateway.
|
||||
/// @param _counterpart The address of L2ETHGateway in L2.
|
||||
/// @param _router The address of L1GatewayRouter.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
receive() external payable {
|
||||
require(msg.sender == WETH, "only WETH");
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function getL2ERC20Address(address) public view override returns (address) {
|
||||
return l2WETH;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function finalizeWithdrawERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(_l1Token == WETH, "l1 token not WETH");
|
||||
require(_l2Token == l2WETH, "l2 token not WETH");
|
||||
require(_amount == msg.value, "msg.value mismatch");
|
||||
|
||||
IWETH(_l1Token).deposit{ value: _amount }();
|
||||
IERC20(_l1Token).safeTransfer(_to, _amount);
|
||||
|
||||
// @todo forward `_data` to `_to`.
|
||||
|
||||
emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L1ERC20Gateway
|
||||
function _deposit(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override nonReentrant {
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
require(_token == WETH, "only WETH is allowed");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
constructor(address _WETH, address _l2WETH) {
|
||||
WETH = _WETH;
|
||||
l2WETH = _l2WETH;
|
||||
}
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
IWETH(_token).withdraw(_amount);
|
||||
/// @notice Initialize the storage of L1WETHGateway.
|
||||
/// @param _counterpart The address of L2ETHGateway in L2.
|
||||
/// @param _router The address of L1GatewayRouter.
|
||||
/// @param _messenger The address of L1ScrollMessenger.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
_token,
|
||||
l2WETH,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
receive() external payable {
|
||||
require(msg.sender == WETH, "only WETH");
|
||||
}
|
||||
|
||||
// 4. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{ value: _amount + msg.value }(counterpart, _amount, _message, _gasLimit);
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
emit DepositERC20(_token, l2WETH, _from, _to, _amount, _data);
|
||||
}
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function getL2ERC20Address(address) public view override returns (address) {
|
||||
return l2WETH;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @inheritdoc IL1ERC20Gateway
|
||||
function finalizeWithdrawERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(_l1Token == WETH, "l1 token not WETH");
|
||||
require(_l2Token == l2WETH, "l2 token not WETH");
|
||||
require(_amount == msg.value, "msg.value mismatch");
|
||||
|
||||
IWETH(_l1Token).deposit{value: _amount}();
|
||||
IERC20(_l1Token).safeTransfer(_to, _amount);
|
||||
|
||||
// @todo forward `_data` to `_to`.
|
||||
|
||||
emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L1ERC20Gateway
|
||||
function _deposit(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override nonReentrant {
|
||||
require(_amount > 0, "deposit zero amount");
|
||||
require(_token == WETH, "only WETH is allowed");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
IWETH(_token).withdraw(_amount);
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
_token,
|
||||
l2WETH,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
|
||||
// 4. Send message to L1ScrollMessenger.
|
||||
IL1ScrollMessenger(messenger).sendMessage{value: _amount + msg.value}(
|
||||
counterpart,
|
||||
_amount,
|
||||
_message,
|
||||
_gasLimit
|
||||
);
|
||||
|
||||
emit DepositERC20(_token, l2WETH, _from, _to, _amount, _data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,76 +3,76 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IL1MessageQueue {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when a new L1 => L2 transaction is appended to the queue.
|
||||
/// @param sender The address of account who initiates the transaction.
|
||||
/// @param target The address of account who will recieve the transaction.
|
||||
/// @param value The value passed with the transaction.
|
||||
/// @param queueIndex The index of this transaction in the queue.
|
||||
/// @param gasLimit Gas limit required to complete the message relay on L2.
|
||||
/// @param data The calldata of the transaction.
|
||||
event QueueTransaction(
|
||||
address indexed sender,
|
||||
address indexed target,
|
||||
uint256 value,
|
||||
uint256 queueIndex,
|
||||
uint256 gasLimit,
|
||||
bytes data
|
||||
);
|
||||
/// @notice Emitted when a new L1 => L2 transaction is appended to the queue.
|
||||
/// @param sender The address of account who initiates the transaction.
|
||||
/// @param target The address of account who will recieve the transaction.
|
||||
/// @param value The value passed with the transaction.
|
||||
/// @param queueIndex The index of this transaction in the queue.
|
||||
/// @param gasLimit Gas limit required to complete the message relay on L2.
|
||||
/// @param data The calldata of the transaction.
|
||||
event QueueTransaction(
|
||||
address indexed sender,
|
||||
address indexed target,
|
||||
uint256 value,
|
||||
uint256 queueIndex,
|
||||
uint256 gasLimit,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Return the index of next appended message.
|
||||
/// @dev Also the total number of appended messages.
|
||||
function nextCrossDomainMessageIndex() external view returns (uint256);
|
||||
/// @notice Return the index of next appended message.
|
||||
/// @dev Also the total number of appended messages.
|
||||
function nextCrossDomainMessageIndex() external view returns (uint256);
|
||||
|
||||
/// @notice Return the message of in `queueIndex`.
|
||||
/// @param queueIndex The index to query.
|
||||
function getCrossDomainMessage(uint256 queueIndex) external view returns (bytes32);
|
||||
/// @notice Return the message of in `queueIndex`.
|
||||
/// @param queueIndex The index to query.
|
||||
function getCrossDomainMessage(uint256 queueIndex) external view returns (bytes32);
|
||||
|
||||
/// @notice Return the amount of ETH should pay for cross domain message.
|
||||
/// @param sender The address of account who initiates the message in L1.
|
||||
/// @param target The address of account who will recieve the message in L2.
|
||||
/// @param message The content of the message.
|
||||
/// @param gasLimit Gas limit required to complete the message relay on L2.
|
||||
function estimateCrossDomainMessageFee(
|
||||
address sender,
|
||||
address target,
|
||||
bytes memory message,
|
||||
uint256 gasLimit
|
||||
) external view returns (uint256);
|
||||
/// @notice Return the amount of ETH should pay for cross domain message.
|
||||
/// @param sender The address of account who initiates the message in L1.
|
||||
/// @param target The address of account who will recieve the message in L2.
|
||||
/// @param message The content of the message.
|
||||
/// @param gasLimit Gas limit required to complete the message relay on L2.
|
||||
function estimateCrossDomainMessageFee(
|
||||
address sender,
|
||||
address target,
|
||||
bytes memory message,
|
||||
uint256 gasLimit
|
||||
) external view returns (uint256);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Append a L1 to L2 message into this contract.
|
||||
/// @param target The address of target contract to call in L2.
|
||||
/// @param gasLimit The maximum gas should be used for relay this message in L2.
|
||||
/// @param data The calldata passed to target contract.
|
||||
function appendCrossDomainMessage(
|
||||
address target,
|
||||
uint256 gasLimit,
|
||||
bytes calldata data
|
||||
) external;
|
||||
/// @notice Append a L1 to L2 message into this contract.
|
||||
/// @param target The address of target contract to call in L2.
|
||||
/// @param gasLimit The maximum gas should be used for relay this message in L2.
|
||||
/// @param data The calldata passed to target contract.
|
||||
function appendCrossDomainMessage(
|
||||
address target,
|
||||
uint256 gasLimit,
|
||||
bytes calldata data
|
||||
) external;
|
||||
|
||||
/// @notice Append an enforced transaction to this contract.
|
||||
/// @dev The address of sender should be an EOA.
|
||||
/// @param sender The address of sender who will initiate this transaction in L2.
|
||||
/// @param target The address of target contract to call in L2.
|
||||
/// @param value The value passed
|
||||
/// @param gasLimit The maximum gas should be used for this transaction in L2.
|
||||
/// @param data The calldata passed to target contract.
|
||||
function appendEnforcedTransaction(
|
||||
address sender,
|
||||
address target,
|
||||
uint256 value,
|
||||
uint256 gasLimit,
|
||||
bytes calldata data
|
||||
) external;
|
||||
/// @notice Append an enforced transaction to this contract.
|
||||
/// @dev The address of sender should be an EOA.
|
||||
/// @param sender The address of sender who will initiate this transaction in L2.
|
||||
/// @param target The address of target contract to call in L2.
|
||||
/// @param value The value passed
|
||||
/// @param gasLimit The maximum gas should be used for this transaction in L2.
|
||||
/// @param data The calldata passed to target contract.
|
||||
function appendEnforcedTransaction(
|
||||
address sender,
|
||||
address target,
|
||||
uint256 value,
|
||||
uint256 gasLimit,
|
||||
bytes calldata data
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IL2GasPriceOracle {
|
||||
/// @notice Estimate fee for cross chain message call.
|
||||
/// @param _sender The address of sender who invoke the call.
|
||||
/// @param _to The target address to receive the call.
|
||||
/// @param _message The message will be passed to the target address.
|
||||
function estimateCrossDomainMessageFee(
|
||||
address _sender,
|
||||
address _to,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external view returns (uint256);
|
||||
/// @notice Estimate fee for cross chain message call.
|
||||
/// @param _sender The address of sender who invoke the call.
|
||||
/// @param _to The target address to receive the call.
|
||||
/// @param _message The message will be passed to the target address.
|
||||
function estimateCrossDomainMessageFee(
|
||||
address _sender,
|
||||
address _to,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external view returns (uint256);
|
||||
}
|
||||
|
||||
@@ -3,102 +3,102 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IScrollChain {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when a new batch is commited.
|
||||
/// @param batchHash The hash of the batch
|
||||
event CommitBatch(bytes32 indexed batchHash);
|
||||
/// @notice Emitted when a new batch is commited.
|
||||
/// @param batchHash The hash of the batch
|
||||
event CommitBatch(bytes32 indexed batchHash);
|
||||
|
||||
/// @notice Emitted when a batch is reverted.
|
||||
/// @param batchHash The identification of the batch.
|
||||
event RevertBatch(bytes32 indexed batchHash);
|
||||
/// @notice Emitted when a batch is reverted.
|
||||
/// @param batchHash The identification of the batch.
|
||||
event RevertBatch(bytes32 indexed batchHash);
|
||||
|
||||
/// @notice Emitted when a batch is finalized.
|
||||
/// @param batchHash The hash of the batch
|
||||
event FinalizeBatch(bytes32 indexed batchHash);
|
||||
/// @notice Emitted when a batch is finalized.
|
||||
/// @param batchHash The hash of the batch
|
||||
event FinalizeBatch(bytes32 indexed batchHash);
|
||||
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
|
||||
struct BlockContext {
|
||||
// The hash of this block.
|
||||
bytes32 blockHash;
|
||||
// The parent hash of this block.
|
||||
bytes32 parentHash;
|
||||
// The height of this block.
|
||||
uint64 blockNumber;
|
||||
// The timestamp of this block.
|
||||
uint64 timestamp;
|
||||
// The base fee of this block.
|
||||
// Currently, it is not used, because we disable EIP-1559.
|
||||
// We keep it for future proof.
|
||||
uint256 baseFee;
|
||||
// The gas limit of this block.
|
||||
uint64 gasLimit;
|
||||
// The number of transactions in this block, both L1 & L2 txs.
|
||||
uint16 numTransactions;
|
||||
// The number of l1 messages in this block.
|
||||
uint16 numL1Messages;
|
||||
}
|
||||
struct BlockContext {
|
||||
// The hash of this block.
|
||||
bytes32 blockHash;
|
||||
// The parent hash of this block.
|
||||
bytes32 parentHash;
|
||||
// The height of this block.
|
||||
uint64 blockNumber;
|
||||
// The timestamp of this block.
|
||||
uint64 timestamp;
|
||||
// The base fee of this block.
|
||||
// Currently, it is not used, because we disable EIP-1559.
|
||||
// We keep it for future proof.
|
||||
uint256 baseFee;
|
||||
// The gas limit of this block.
|
||||
uint64 gasLimit;
|
||||
// The number of transactions in this block, both L1 & L2 txs.
|
||||
uint16 numTransactions;
|
||||
// The number of l1 messages in this block.
|
||||
uint16 numL1Messages;
|
||||
}
|
||||
|
||||
struct Batch {
|
||||
// The list of blocks in this batch
|
||||
BlockContext[] blocks; // MAX_NUM_BLOCKS = 100, about 5 min
|
||||
// The state root of previous batch.
|
||||
// The first batch will use 0x0 for prevStateRoot
|
||||
bytes32 prevStateRoot;
|
||||
// The state root of the last block in this batch.
|
||||
bytes32 newStateRoot;
|
||||
// The withdraw trie root of the last block in this batch.
|
||||
bytes32 withdrawTrieRoot;
|
||||
// The index of the batch.
|
||||
uint64 batchIndex;
|
||||
// The parent batch hash.
|
||||
bytes32 parentBatchHash;
|
||||
// Concatenated raw data of RLP encoded L2 txs
|
||||
bytes l2Transactions;
|
||||
}
|
||||
struct Batch {
|
||||
// The list of blocks in this batch
|
||||
BlockContext[] blocks; // MAX_NUM_BLOCKS = 100, about 5 min
|
||||
// The state root of previous batch.
|
||||
// The first batch will use 0x0 for prevStateRoot
|
||||
bytes32 prevStateRoot;
|
||||
// The state root of the last block in this batch.
|
||||
bytes32 newStateRoot;
|
||||
// The withdraw trie root of the last block in this batch.
|
||||
bytes32 withdrawTrieRoot;
|
||||
// The index of the batch.
|
||||
uint64 batchIndex;
|
||||
// The parent batch hash.
|
||||
bytes32 parentBatchHash;
|
||||
// Concatenated raw data of RLP encoded L2 txs
|
||||
bytes l2Transactions;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Return whether the batch is finalized by batch hash.
|
||||
/// @param batchHash The hash of the batch to query.
|
||||
function isBatchFinalized(bytes32 batchHash) external view returns (bool);
|
||||
/// @notice Return whether the batch is finalized by batch hash.
|
||||
/// @param batchHash The hash of the batch to query.
|
||||
function isBatchFinalized(bytes32 batchHash) external view returns (bool);
|
||||
|
||||
/// @notice Return the merkle root of L2 message tree.
|
||||
/// @param batchHash The hash of the batch to query.
|
||||
function getL2MessageRoot(bytes32 batchHash) external view returns (bytes32);
|
||||
/// @notice Return the merkle root of L2 message tree.
|
||||
/// @param batchHash The hash of the batch to query.
|
||||
function getL2MessageRoot(bytes32 batchHash) external view returns (bytes32);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice commit a batch in layer 1
|
||||
/// @param batch The layer2 batch to commit.
|
||||
function commitBatch(Batch memory batch) external;
|
||||
/// @notice commit a batch in layer 1
|
||||
/// @param batch The layer2 batch to commit.
|
||||
function commitBatch(Batch memory batch) external;
|
||||
|
||||
/// @notice commit a list of batches in layer 1
|
||||
/// @param batches The list of layer2 batches to commit.
|
||||
function commitBatches(Batch[] memory batches) external;
|
||||
/// @notice commit a list of batches in layer 1
|
||||
/// @param batches The list of layer2 batches to commit.
|
||||
function commitBatches(Batch[] memory batches) external;
|
||||
|
||||
/// @notice revert a pending batch.
|
||||
/// @dev one can only revert unfinalized batches.
|
||||
/// @param batchId The identification of the batch.
|
||||
function revertBatch(bytes32 batchId) external;
|
||||
/// @notice revert a pending batch.
|
||||
/// @dev one can only revert unfinalized batches.
|
||||
/// @param batchId The identification of the batch.
|
||||
function revertBatch(bytes32 batchId) external;
|
||||
|
||||
/// @notice finalize commited batch in layer 1
|
||||
/// @dev will add more parameters if needed.
|
||||
/// @param batchId The identification of the commited batch.
|
||||
/// @param proof The corresponding proof of the commited batch.
|
||||
/// @param instances Instance used to verify, generated from batch.
|
||||
function finalizeBatchWithProof(
|
||||
bytes32 batchId,
|
||||
uint256[] memory proof,
|
||||
uint256[] memory instances
|
||||
) external;
|
||||
/// @notice finalize commited batch in layer 1
|
||||
/// @dev will add more parameters if needed.
|
||||
/// @param batchId The identification of the commited batch.
|
||||
/// @param proof The corresponding proof of the commited batch.
|
||||
/// @param instances Instance used to verify, generated from batch.
|
||||
function finalizeBatchWithProof(
|
||||
bytes32 batchId,
|
||||
uint256[] memory proof,
|
||||
uint256[] memory instances
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -2,122 +2,122 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
|
||||
import { IL2GasPriceOracle } from "./IL2GasPriceOracle.sol";
|
||||
import { IL1MessageQueue } from "./IL1MessageQueue.sol";
|
||||
import {IL2GasPriceOracle} from "./IL2GasPriceOracle.sol";
|
||||
import {IL1MessageQueue} from "./IL1MessageQueue.sol";
|
||||
|
||||
import { AddressAliasHelper } from "../../libraries/common/AddressAliasHelper.sol";
|
||||
import {AddressAliasHelper} from "../../libraries/common/AddressAliasHelper.sol";
|
||||
|
||||
/// @title L1MessageQueue
|
||||
/// @notice This contract will hold all L1 to L2 messages.
|
||||
/// Each appended message is assigned with a unique and increasing `uint256` index denoting the message nonce.
|
||||
contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when owner updates gas oracle contract.
|
||||
/// @param _oldGasOracle The address of old gas oracle contract.
|
||||
/// @param _newGasOracle The address of new gas oracle contract.
|
||||
event UpdateGasOracle(address _oldGasOracle, address _newGasOracle);
|
||||
/// @notice Emitted when owner updates gas oracle contract.
|
||||
/// @param _oldGasOracle The address of old gas oracle contract.
|
||||
/// @param _newGasOracle The address of new gas oracle contract.
|
||||
event UpdateGasOracle(address _oldGasOracle, address _newGasOracle);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice The address of L1ScrollMessenger contract.
|
||||
address public messenger;
|
||||
/// @notice The address of L1ScrollMessenger contract.
|
||||
address public messenger;
|
||||
|
||||
/// @notice The address of GasOracle contract.
|
||||
address public gasOracle;
|
||||
/// @notice The address of GasOracle contract.
|
||||
address public gasOracle;
|
||||
|
||||
/// @notice The list of queued cross domain messages.
|
||||
bytes32[] public messageQueue;
|
||||
/// @notice The list of queued cross domain messages.
|
||||
bytes32[] public messageQueue;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
function initialize(address _messenger, address _gasOracle) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
function initialize(address _messenger, address _gasOracle) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
|
||||
messenger = _messenger;
|
||||
gasOracle = _gasOracle;
|
||||
}
|
||||
messenger = _messenger;
|
||||
gasOracle = _gasOracle;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function nextCrossDomainMessageIndex() external view returns (uint256) {
|
||||
return messageQueue.length;
|
||||
}
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function nextCrossDomainMessageIndex() external view returns (uint256) {
|
||||
return messageQueue.length;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function getCrossDomainMessage(uint256 _queueIndex) external view returns (bytes32) {
|
||||
return messageQueue[_queueIndex];
|
||||
}
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function getCrossDomainMessage(uint256 _queueIndex) external view returns (bytes32) {
|
||||
return messageQueue[_queueIndex];
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function estimateCrossDomainMessageFee(
|
||||
address _sender,
|
||||
address _target,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external view override returns (uint256) {
|
||||
address _oracle = gasOracle;
|
||||
if (_oracle == address(0)) return 0;
|
||||
return IL2GasPriceOracle(_oracle).estimateCrossDomainMessageFee(_sender, _target, _message, _gasLimit);
|
||||
}
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function estimateCrossDomainMessageFee(
|
||||
address _sender,
|
||||
address _target,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external view override returns (uint256) {
|
||||
address _oracle = gasOracle;
|
||||
if (_oracle == address(0)) return 0;
|
||||
return IL2GasPriceOracle(_oracle).estimateCrossDomainMessageFee(_sender, _target, _message, _gasLimit);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function appendCrossDomainMessage(
|
||||
address _target,
|
||||
uint256 _gasLimit,
|
||||
bytes calldata _data
|
||||
) external override {
|
||||
require(msg.sender == messenger, "Only callable by the L1ScrollMessenger");
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function appendCrossDomainMessage(
|
||||
address _target,
|
||||
uint256 _gasLimit,
|
||||
bytes calldata _data
|
||||
) external override {
|
||||
require(msg.sender == messenger, "Only callable by the L1ScrollMessenger");
|
||||
|
||||
// do address alias to avoid replay attack in L2.
|
||||
address _sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
|
||||
// do address alias to avoid replay attack in L2.
|
||||
address _sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
|
||||
|
||||
// @todo Change it to rlp encoding later.
|
||||
bytes32 _hash = keccak256(abi.encode(_sender, _target, 0, _gasLimit, _data));
|
||||
// @todo Change it to rlp encoding later.
|
||||
bytes32 _hash = keccak256(abi.encode(_sender, _target, 0, _gasLimit, _data));
|
||||
|
||||
uint256 _queueIndex = messageQueue.length;
|
||||
emit QueueTransaction(_sender, _target, 0, _queueIndex, _gasLimit, _data);
|
||||
uint256 _queueIndex = messageQueue.length;
|
||||
emit QueueTransaction(_sender, _target, 0, _queueIndex, _gasLimit, _data);
|
||||
|
||||
messageQueue.push(_hash);
|
||||
}
|
||||
messageQueue.push(_hash);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function appendEnforcedTransaction(
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external override {
|
||||
// @todo
|
||||
}
|
||||
/// @inheritdoc IL1MessageQueue
|
||||
function appendEnforcedTransaction(
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external override {
|
||||
// @todo
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update the address of gas oracle.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newGasOracle The address to update.
|
||||
function updateGasOracle(address _newGasOracle) external onlyOwner {
|
||||
address _oldGasOracle = gasOracle;
|
||||
gasOracle = _newGasOracle;
|
||||
/// @notice Update the address of gas oracle.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newGasOracle The address to update.
|
||||
function updateGasOracle(address _newGasOracle) external onlyOwner {
|
||||
address _oldGasOracle = gasOracle;
|
||||
gasOracle = _newGasOracle;
|
||||
|
||||
emit UpdateGasOracle(_oldGasOracle, _newGasOracle);
|
||||
}
|
||||
emit UpdateGasOracle(_oldGasOracle, _newGasOracle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,162 +2,162 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
|
||||
import { IWhitelist } from "../../libraries/common/IWhitelist.sol";
|
||||
import {IWhitelist} from "../../libraries/common/IWhitelist.sol";
|
||||
|
||||
import { IL2GasPriceOracle } from "./IL2GasPriceOracle.sol";
|
||||
import {IL2GasPriceOracle} from "./IL2GasPriceOracle.sol";
|
||||
|
||||
contract L2GasPriceOracle is OwnableUpgradeable, IL2GasPriceOracle {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when owner updates whitelist contract.
|
||||
/// @param _oldWhitelist The address of old whitelist contract.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
event UpdateWhitelist(address _oldWhitelist, address _newWhitelist);
|
||||
/// @notice Emitted when owner updates whitelist contract.
|
||||
/// @param _oldWhitelist The address of old whitelist contract.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
event UpdateWhitelist(address _oldWhitelist, address _newWhitelist);
|
||||
|
||||
/// @notice Emitted when current fee overhead is updated.
|
||||
/// @param overhead The current fee overhead updated.
|
||||
event OverheadUpdated(uint256 overhead);
|
||||
/// @notice Emitted when current fee overhead is updated.
|
||||
/// @param overhead The current fee overhead updated.
|
||||
event OverheadUpdated(uint256 overhead);
|
||||
|
||||
/// @notice Emitted when current fee scalar is updated.
|
||||
/// @param scalar The current fee scalar updated.
|
||||
event ScalarUpdated(uint256 scalar);
|
||||
/// @notice Emitted when current fee scalar is updated.
|
||||
/// @param scalar The current fee scalar updated.
|
||||
event ScalarUpdated(uint256 scalar);
|
||||
|
||||
/// @notice Emitted when current l2 base fee is updated.
|
||||
/// @param l2BaseFee The current l2 base fee updated.
|
||||
event L2BaseFeeUpdated(uint256 l2BaseFee);
|
||||
/// @notice Emitted when current l2 base fee is updated.
|
||||
/// @param l2BaseFee The current l2 base fee updated.
|
||||
event L2BaseFeeUpdated(uint256 l2BaseFee);
|
||||
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
|
||||
/// @dev The precision used in the scalar.
|
||||
uint256 private constant PRECISION = 1e9;
|
||||
/// @dev The precision used in the scalar.
|
||||
uint256 private constant PRECISION = 1e9;
|
||||
|
||||
/// @dev The maximum possible l1 fee overhead.
|
||||
/// Computed based on current l1 block gas limit.
|
||||
uint256 private constant MAX_OVERHEAD = 30000000 / 16;
|
||||
/// @dev The maximum possible l1 fee overhead.
|
||||
/// Computed based on current l1 block gas limit.
|
||||
uint256 private constant MAX_OVERHEAD = 30000000 / 16;
|
||||
|
||||
/// @dev The maximum possible l1 fee scale.
|
||||
/// x1000 should be enough.
|
||||
uint256 private constant MAX_SCALE = 1000 * PRECISION;
|
||||
/// @dev The maximum possible l1 fee scale.
|
||||
/// x1000 should be enough.
|
||||
uint256 private constant MAX_SCALE = 1000 * PRECISION;
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice The current l1 fee overhead.
|
||||
uint256 public overhead;
|
||||
/// @notice The current l1 fee overhead.
|
||||
uint256 public overhead;
|
||||
|
||||
/// @notice The current l1 fee scalar.
|
||||
uint256 public scalar;
|
||||
/// @notice The current l1 fee scalar.
|
||||
uint256 public scalar;
|
||||
|
||||
/// @notice The latest known l2 base fee.
|
||||
uint256 public l2BaseFee;
|
||||
/// @notice The latest known l2 base fee.
|
||||
uint256 public l2BaseFee;
|
||||
|
||||
/// @notice The address of whitelist contract.
|
||||
IWhitelist public whitelist;
|
||||
/// @notice The address of whitelist contract.
|
||||
IWhitelist public whitelist;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
function initialize() external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Return the current l1 base fee.
|
||||
function l1BaseFee() public view returns (uint256) {
|
||||
return block.basefee;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2GasPriceOracle
|
||||
function estimateCrossDomainMessageFee(
|
||||
address,
|
||||
address,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external view override returns (uint256) {
|
||||
unchecked {
|
||||
uint256 _l1GasUsed = getL1GasUsed(_message);
|
||||
uint256 _rollupFee = (_l1GasUsed * l1BaseFee() * scalar) / PRECISION;
|
||||
uint256 _l2Fee = _gasLimit * l2BaseFee;
|
||||
return _l2Fee + _rollupFee;
|
||||
function initialize() external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
}
|
||||
}
|
||||
|
||||
/// @notice Computes the amount of L1 gas used for a transaction. Adds the overhead which
|
||||
/// represents the per-transaction gas overhead of posting the transaction and state
|
||||
/// roots to L1. Adds 68 bytes of padding to account for the fact that the input does
|
||||
/// not have a signature.
|
||||
/// @param _data Unsigned fully RLP-encoded transaction to get the L1 gas for.
|
||||
/// @return Amount of L1 gas used to publish the transaction.
|
||||
function getL1GasUsed(bytes memory _data) public view returns (uint256) {
|
||||
uint256 _total = 0;
|
||||
uint256 _length = _data.length;
|
||||
unchecked {
|
||||
for (uint256 i = 0; i < _length; i++) {
|
||||
if (_data[i] == 0) {
|
||||
_total += 4;
|
||||
} else {
|
||||
_total += 16;
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Return the current l1 base fee.
|
||||
function l1BaseFee() public view returns (uint256) {
|
||||
return block.basefee;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2GasPriceOracle
|
||||
function estimateCrossDomainMessageFee(
|
||||
address,
|
||||
address,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external view override returns (uint256) {
|
||||
unchecked {
|
||||
uint256 _l1GasUsed = getL1GasUsed(_message);
|
||||
uint256 _rollupFee = (_l1GasUsed * l1BaseFee() * scalar) / PRECISION;
|
||||
uint256 _l2Fee = _gasLimit * l2BaseFee;
|
||||
return _l2Fee + _rollupFee;
|
||||
}
|
||||
}
|
||||
uint256 _unsigned = _total + overhead;
|
||||
return _unsigned + (68 * 16);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/// @notice Computes the amount of L1 gas used for a transaction. Adds the overhead which
|
||||
/// represents the per-transaction gas overhead of posting the transaction and state
|
||||
/// roots to L1. Adds 68 bytes of padding to account for the fact that the input does
|
||||
/// not have a signature.
|
||||
/// @param _data Unsigned fully RLP-encoded transaction to get the L1 gas for.
|
||||
/// @return Amount of L1 gas used to publish the transaction.
|
||||
function getL1GasUsed(bytes memory _data) public view returns (uint256) {
|
||||
uint256 _total = 0;
|
||||
uint256 _length = _data.length;
|
||||
unchecked {
|
||||
for (uint256 i = 0; i < _length; i++) {
|
||||
if (_data[i] == 0) {
|
||||
_total += 4;
|
||||
} else {
|
||||
_total += 16;
|
||||
}
|
||||
}
|
||||
uint256 _unsigned = _total + overhead;
|
||||
return _unsigned + (68 * 16);
|
||||
}
|
||||
}
|
||||
|
||||
/// @notice Allows the owner to modify the l2 base fee.
|
||||
/// @param _l2BaseFee The new l2 base fee.
|
||||
function setL2BaseFee(uint256 _l2BaseFee) external {
|
||||
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
l2BaseFee = _l2BaseFee;
|
||||
/// @notice Allows the owner to modify the l2 base fee.
|
||||
/// @param _l2BaseFee The new l2 base fee.
|
||||
function setL2BaseFee(uint256 _l2BaseFee) external {
|
||||
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
|
||||
|
||||
emit L2BaseFeeUpdated(_l2BaseFee);
|
||||
}
|
||||
l2BaseFee = _l2BaseFee;
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
emit L2BaseFeeUpdated(_l2BaseFee);
|
||||
}
|
||||
|
||||
/// @notice Allows the owner to modify the overhead.
|
||||
/// @param _overhead New overhead
|
||||
function setOverhead(uint256 _overhead) external onlyOwner {
|
||||
require(_overhead <= MAX_OVERHEAD, "exceed maximum overhead");
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
overhead = _overhead;
|
||||
emit OverheadUpdated(_overhead);
|
||||
}
|
||||
/// @notice Allows the owner to modify the overhead.
|
||||
/// @param _overhead New overhead
|
||||
function setOverhead(uint256 _overhead) external onlyOwner {
|
||||
require(_overhead <= MAX_OVERHEAD, "exceed maximum overhead");
|
||||
|
||||
/// Allows the owner to modify the scalar.
|
||||
/// @param _scalar The new scalar
|
||||
function setScalar(uint256 _scalar) external onlyOwner {
|
||||
require(_scalar <= MAX_SCALE, "exceed maximum scale");
|
||||
overhead = _overhead;
|
||||
emit OverheadUpdated(_overhead);
|
||||
}
|
||||
|
||||
scalar = _scalar;
|
||||
emit ScalarUpdated(_scalar);
|
||||
}
|
||||
/// Allows the owner to modify the scalar.
|
||||
/// @param _scalar The new scalar
|
||||
function setScalar(uint256 _scalar) external onlyOwner {
|
||||
require(_scalar <= MAX_SCALE, "exceed maximum scale");
|
||||
|
||||
/// @notice Update whitelist contract.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
function updateWhitelist(address _newWhitelist) external onlyOwner {
|
||||
address _oldWhitelist = address(whitelist);
|
||||
scalar = _scalar;
|
||||
emit ScalarUpdated(_scalar);
|
||||
}
|
||||
|
||||
whitelist = IWhitelist(_newWhitelist);
|
||||
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
|
||||
}
|
||||
/// @notice Update whitelist contract.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
function updateWhitelist(address _newWhitelist) external onlyOwner {
|
||||
address _oldWhitelist = address(whitelist);
|
||||
|
||||
whitelist = IWhitelist(_newWhitelist);
|
||||
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
|
||||
import { IL1MessageQueue } from "./IL1MessageQueue.sol";
|
||||
import { IScrollChain } from "./IScrollChain.sol";
|
||||
import { RollupVerifier } from "../../libraries/verifier/RollupVerifier.sol";
|
||||
import {IL1MessageQueue} from "./IL1MessageQueue.sol";
|
||||
import {IScrollChain} from "./IScrollChain.sol";
|
||||
import {RollupVerifier} from "../../libraries/verifier/RollupVerifier.sol";
|
||||
|
||||
// solhint-disable reason-string
|
||||
|
||||
@@ -18,402 +18,405 @@ import { RollupVerifier } from "../../libraries/verifier/RollupVerifier.sol";
|
||||
///
|
||||
/// @dev the message queue is not used yet, the offline relayer only use events in `L1ScrollMessenger`.
|
||||
contract ScrollChain is OwnableUpgradeable, IScrollChain {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when owner updates the status of sequencer.
|
||||
/// @param account The address of account updated.
|
||||
/// @param status The status of the account updated.
|
||||
event UpdateSequencer(address indexed account, bool status);
|
||||
/// @notice Emitted when owner updates the status of sequencer.
|
||||
/// @param account The address of account updated.
|
||||
/// @param status The status of the account updated.
|
||||
event UpdateSequencer(address indexed account, bool status);
|
||||
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
|
||||
/// @dev The maximum number of transaction in on batch.
|
||||
uint256 public immutable maxNumTxInBatch;
|
||||
/// @dev The maximum number of transaction in on batch.
|
||||
uint256 public immutable maxNumTxInBatch;
|
||||
|
||||
/// @dev The hash used for padding public inputs.
|
||||
bytes32 public immutable paddingTxHash;
|
||||
/// @dev The hash used for padding public inputs.
|
||||
bytes32 public immutable paddingTxHash;
|
||||
|
||||
/// @notice The chain id of the corresponding layer 2 chain.
|
||||
uint256 public immutable layer2ChainId;
|
||||
/// @notice The chain id of the corresponding layer 2 chain.
|
||||
uint256 public immutable layer2ChainId;
|
||||
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
|
||||
// subject to change
|
||||
struct BatchStored {
|
||||
// The state root of the last block in this batch.
|
||||
bytes32 newStateRoot;
|
||||
// The withdraw trie root of the last block in this batch.
|
||||
bytes32 withdrawTrieRoot;
|
||||
// The parent batch hash.
|
||||
bytes32 parentBatchHash;
|
||||
// The index of the batch.
|
||||
uint64 batchIndex;
|
||||
// The timestamp of the last block in this batch.
|
||||
uint64 timestamp;
|
||||
// The number of transactions in this batch, both L1 & L2 txs.
|
||||
uint64 numTransactions;
|
||||
// The total number of L1 messages included after this batch.
|
||||
uint64 totalL1Messages;
|
||||
// Whether the batch is finalized.
|
||||
bool finalized;
|
||||
}
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice The address of L1MessageQueue.
|
||||
address public messageQueue;
|
||||
|
||||
/// @notice Whether an account is a sequencer.
|
||||
mapping(address => bool) public isSequencer;
|
||||
|
||||
/// @notice The latest finalized batch hash.
|
||||
bytes32 public lastFinalizedBatchHash;
|
||||
|
||||
/// @notice Mapping from batch id to batch struct.
|
||||
mapping(bytes32 => BatchStored) public batches;
|
||||
|
||||
/// @notice Mapping from batch index to finalized batch hash.
|
||||
mapping(uint256 => bytes32) public finalizedBatches;
|
||||
|
||||
/**********************
|
||||
* Function Modifiers *
|
||||
**********************/
|
||||
|
||||
modifier OnlySequencer() {
|
||||
// @todo In the decentralize mode, it should be only called by a list of validator.
|
||||
require(isSequencer[msg.sender], "caller not sequencer");
|
||||
_;
|
||||
}
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
constructor(
|
||||
uint256 _chainId,
|
||||
uint256 _maxNumTxInBatch,
|
||||
bytes32 _paddingTxHash
|
||||
) {
|
||||
layer2ChainId = _chainId;
|
||||
maxNumTxInBatch = _maxNumTxInBatch;
|
||||
paddingTxHash = _paddingTxHash;
|
||||
}
|
||||
|
||||
function initialize(address _messageQueue) public initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
|
||||
messageQueue = _messageQueue;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function isBatchFinalized(bytes32 _batchHash) external view override returns (bool) {
|
||||
BatchStored storage _batch = batches[_batchHash];
|
||||
if (_batch.newStateRoot == bytes32(0)) {
|
||||
return false;
|
||||
}
|
||||
return batches[lastFinalizedBatchHash].batchIndex >= _batch.batchIndex;
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function getL2MessageRoot(bytes32 _batchHash) external view override returns (bytes32) {
|
||||
return batches[_batchHash].withdrawTrieRoot;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @notice Import layer 2 genesis block
|
||||
function importGenesisBatch(Batch memory _genesisBatch) external {
|
||||
require(lastFinalizedBatchHash == bytes32(0), "Genesis batch imported");
|
||||
require(_genesisBatch.blocks.length == 1, "Not exact one block in genesis");
|
||||
require(_genesisBatch.prevStateRoot == bytes32(0), "Nonzero prevStateRoot");
|
||||
|
||||
BlockContext memory _genesisBlock = _genesisBatch.blocks[0];
|
||||
|
||||
require(_genesisBlock.blockHash != bytes32(0), "Block hash is zero");
|
||||
require(_genesisBlock.blockNumber == 0, "Block is not genesis");
|
||||
require(_genesisBlock.parentHash == bytes32(0), "Parent hash not empty");
|
||||
|
||||
bytes32 _batchHash = _commitBatch(_genesisBatch);
|
||||
|
||||
lastFinalizedBatchHash = _batchHash;
|
||||
finalizedBatches[0] = _batchHash;
|
||||
batches[_batchHash].finalized = true;
|
||||
|
||||
emit FinalizeBatch(_batchHash);
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function commitBatch(Batch memory _batch) public override OnlySequencer {
|
||||
_commitBatch(_batch);
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function commitBatches(Batch[] memory _batches) public override OnlySequencer {
|
||||
for (uint256 i = 0; i < _batches.length; i++) {
|
||||
_commitBatch(_batches[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function revertBatch(bytes32 _batchHash) external override OnlySequencer {
|
||||
BatchStored storage _batch = batches[_batchHash];
|
||||
|
||||
require(_batch.newStateRoot != bytes32(0), "No such batch");
|
||||
require(!_batch.finalized, "Unable to revert finalized batch");
|
||||
|
||||
// delete committed batch
|
||||
delete batches[_batchHash];
|
||||
|
||||
emit RevertBatch(_batchHash);
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function finalizeBatchWithProof(
|
||||
bytes32 _batchHash,
|
||||
uint256[] memory _proof,
|
||||
uint256[] memory _instances
|
||||
) external override OnlySequencer {
|
||||
BatchStored storage _batch = batches[_batchHash];
|
||||
require(_batch.newStateRoot != bytes32(0), "No such batch");
|
||||
require(!_batch.finalized, "Batch is already finalized");
|
||||
|
||||
// @note skip parent check for now, since we may not prove blocks in order.
|
||||
// bytes32 _parentHash = _block.header.parentHash;
|
||||
// require(lastFinalizedBlockHash == _parentHash, "parent not latest finalized");
|
||||
// this check below is not needed, just incase
|
||||
// require(blocks[_parentHash].verified, "parent not verified");
|
||||
|
||||
// @todo add verification logic
|
||||
RollupVerifier.verify(_proof, _instances);
|
||||
|
||||
uint256 _batchIndex = _batch.batchIndex;
|
||||
finalizedBatches[_batchIndex] = _batchHash;
|
||||
_batch.finalized = true;
|
||||
|
||||
BatchStored storage _finalizedBatch = batches[lastFinalizedBatchHash];
|
||||
if (_batchIndex > _finalizedBatch.batchIndex) {
|
||||
lastFinalizedBatchHash = _batchHash;
|
||||
// subject to change
|
||||
struct BatchStored {
|
||||
// The state root of the last block in this batch.
|
||||
bytes32 newStateRoot;
|
||||
// The withdraw trie root of the last block in this batch.
|
||||
bytes32 withdrawTrieRoot;
|
||||
// The parent batch hash.
|
||||
bytes32 parentBatchHash;
|
||||
// The index of the batch.
|
||||
uint64 batchIndex;
|
||||
// The timestamp of the last block in this batch.
|
||||
uint64 timestamp;
|
||||
// The number of transactions in this batch, both L1 & L2 txs.
|
||||
uint64 numTransactions;
|
||||
// The total number of L1 messages included after this batch.
|
||||
uint64 totalL1Messages;
|
||||
// Whether the batch is finalized.
|
||||
bool finalized;
|
||||
}
|
||||
|
||||
emit FinalizeBatch(_batchHash);
|
||||
}
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
/// @notice The address of L1MessageQueue.
|
||||
address public messageQueue;
|
||||
|
||||
/// @notice Update the status of sequencer.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _account The address of account to update.
|
||||
/// @param _status The status of the account to update.
|
||||
function updateSequencer(address _account, bool _status) external onlyOwner {
|
||||
isSequencer[_account] = _status;
|
||||
/// @notice Whether an account is a sequencer.
|
||||
mapping(address => bool) public isSequencer;
|
||||
|
||||
emit UpdateSequencer(_account, _status);
|
||||
}
|
||||
/// @notice The latest finalized batch hash.
|
||||
bytes32 public lastFinalizedBatchHash;
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
/// @notice Mapping from batch id to batch struct.
|
||||
mapping(bytes32 => BatchStored) public batches;
|
||||
|
||||
/// @dev Internal function to commit a batch.
|
||||
/// @param _batch The batch to commit.
|
||||
function _commitBatch(Batch memory _batch) internal returns (bytes32) {
|
||||
// check whether the batch is empty
|
||||
require(_batch.blocks.length > 0, "Batch is empty");
|
||||
/// @notice Mapping from batch index to finalized batch hash.
|
||||
mapping(uint256 => bytes32) public finalizedBatches;
|
||||
|
||||
BatchStored storage _parentBatch = batches[_batch.parentBatchHash];
|
||||
require(_parentBatch.newStateRoot == _batch.prevStateRoot, "prevStateRoot is different from newStateRoot in the parent batch");
|
||||
uint64 accTotalL1Messages = _parentBatch.totalL1Messages;
|
||||
/**********************
|
||||
* Function Modifiers *
|
||||
**********************/
|
||||
|
||||
bytes32 publicInputHash;
|
||||
uint64 numTransactionsInBatch;
|
||||
uint64 lastBlockTimestamp;
|
||||
(publicInputHash, numTransactionsInBatch, accTotalL1Messages, lastBlockTimestamp) = _computePublicInputHash(
|
||||
accTotalL1Messages,
|
||||
_batch
|
||||
);
|
||||
modifier OnlySequencer() {
|
||||
// @todo In the decentralize mode, it should be only called by a list of validator.
|
||||
require(isSequencer[msg.sender], "caller not sequencer");
|
||||
_;
|
||||
}
|
||||
|
||||
BatchStored storage _batchInStorage = batches[publicInputHash];
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
require(_batchInStorage.newStateRoot == bytes32(0), "Batch already commited");
|
||||
_batchInStorage.newStateRoot = _batch.newStateRoot;
|
||||
_batchInStorage.withdrawTrieRoot = _batch.withdrawTrieRoot;
|
||||
_batchInStorage.batchIndex = _batch.batchIndex;
|
||||
_batchInStorage.parentBatchHash = _batch.parentBatchHash;
|
||||
_batchInStorage.timestamp = lastBlockTimestamp;
|
||||
_batchInStorage.numTransactions = numTransactionsInBatch;
|
||||
_batchInStorage.totalL1Messages = accTotalL1Messages;
|
||||
constructor(
|
||||
uint256 _chainId,
|
||||
uint256 _maxNumTxInBatch,
|
||||
bytes32 _paddingTxHash
|
||||
) {
|
||||
layer2ChainId = _chainId;
|
||||
maxNumTxInBatch = _maxNumTxInBatch;
|
||||
paddingTxHash = _paddingTxHash;
|
||||
}
|
||||
|
||||
emit CommitBatch(publicInputHash);
|
||||
function initialize(address _messageQueue) public initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
|
||||
return publicInputHash;
|
||||
}
|
||||
messageQueue = _messageQueue;
|
||||
}
|
||||
|
||||
/// @dev Internal function to compute the public input hash.
|
||||
/// @param accTotalL1Messages The number of total L1 messages in previous batch.
|
||||
/// @param batch The batch to compute.
|
||||
function _computePublicInputHash(uint64 accTotalL1Messages, Batch memory batch)
|
||||
internal
|
||||
view
|
||||
returns (
|
||||
bytes32,
|
||||
uint64,
|
||||
uint64,
|
||||
uint64
|
||||
)
|
||||
{
|
||||
uint256 publicInputsPtr;
|
||||
// 1. append prevStateRoot, newStateRoot and withdrawTrieRoot to public inputs
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function isBatchFinalized(bytes32 _batchHash) external view override returns (bool) {
|
||||
BatchStored storage _batch = batches[_batchHash];
|
||||
if (_batch.newStateRoot == bytes32(0)) {
|
||||
return false;
|
||||
}
|
||||
return batches[lastFinalizedBatchHash].batchIndex >= _batch.batchIndex;
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function getL2MessageRoot(bytes32 _batchHash) external view override returns (bytes32) {
|
||||
return batches[_batchHash].withdrawTrieRoot;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Import layer 2 genesis block
|
||||
function importGenesisBatch(Batch memory _genesisBatch) external {
|
||||
require(lastFinalizedBatchHash == bytes32(0), "Genesis batch imported");
|
||||
require(_genesisBatch.blocks.length == 1, "Not exact one block in genesis");
|
||||
require(_genesisBatch.prevStateRoot == bytes32(0), "Nonzero prevStateRoot");
|
||||
|
||||
BlockContext memory _genesisBlock = _genesisBatch.blocks[0];
|
||||
|
||||
require(_genesisBlock.blockHash != bytes32(0), "Block hash is zero");
|
||||
require(_genesisBlock.blockNumber == 0, "Block is not genesis");
|
||||
require(_genesisBlock.parentHash == bytes32(0), "Parent hash not empty");
|
||||
|
||||
bytes32 _batchHash = _commitBatch(_genesisBatch);
|
||||
|
||||
lastFinalizedBatchHash = _batchHash;
|
||||
finalizedBatches[0] = _batchHash;
|
||||
batches[_batchHash].finalized = true;
|
||||
|
||||
emit FinalizeBatch(_batchHash);
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function commitBatch(Batch memory _batch) public override OnlySequencer {
|
||||
_commitBatch(_batch);
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function commitBatches(Batch[] memory _batches) public override OnlySequencer {
|
||||
for (uint256 i = 0; i < _batches.length; i++) {
|
||||
_commitBatch(_batches[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function revertBatch(bytes32 _batchHash) external override OnlySequencer {
|
||||
BatchStored storage _batch = batches[_batchHash];
|
||||
|
||||
require(_batch.newStateRoot != bytes32(0), "No such batch");
|
||||
require(!_batch.finalized, "Unable to revert finalized batch");
|
||||
|
||||
// delete committed batch
|
||||
delete batches[_batchHash];
|
||||
|
||||
emit RevertBatch(_batchHash);
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
function finalizeBatchWithProof(
|
||||
bytes32 _batchHash,
|
||||
uint256[] memory _proof,
|
||||
uint256[] memory _instances
|
||||
) external override OnlySequencer {
|
||||
BatchStored storage _batch = batches[_batchHash];
|
||||
require(_batch.newStateRoot != bytes32(0), "No such batch");
|
||||
require(!_batch.finalized, "Batch is already finalized");
|
||||
|
||||
// @note skip parent check for now, since we may not prove blocks in order.
|
||||
// bytes32 _parentHash = _block.header.parentHash;
|
||||
// require(lastFinalizedBlockHash == _parentHash, "parent not latest finalized");
|
||||
// this check below is not needed, just incase
|
||||
// require(blocks[_parentHash].verified, "parent not verified");
|
||||
|
||||
// @todo add verification logic
|
||||
RollupVerifier.verify(_proof, _instances);
|
||||
|
||||
uint256 _batchIndex = _batch.batchIndex;
|
||||
finalizedBatches[_batchIndex] = _batchHash;
|
||||
_batch.finalized = true;
|
||||
|
||||
BatchStored storage _finalizedBatch = batches[lastFinalizedBatchHash];
|
||||
if (_batchIndex > _finalizedBatch.batchIndex) {
|
||||
lastFinalizedBatchHash = _batchHash;
|
||||
}
|
||||
|
||||
emit FinalizeBatch(_batchHash);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update the status of sequencer.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _account The address of account to update.
|
||||
/// @param _status The status of the account to update.
|
||||
function updateSequencer(address _account, bool _status) external onlyOwner {
|
||||
isSequencer[_account] = _status;
|
||||
|
||||
emit UpdateSequencer(_account, _status);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to commit a batch.
|
||||
/// @param _batch The batch to commit.
|
||||
function _commitBatch(Batch memory _batch) internal returns (bytes32) {
|
||||
// check whether the batch is empty
|
||||
require(_batch.blocks.length > 0, "Batch is empty");
|
||||
|
||||
BatchStored storage _parentBatch = batches[_batch.parentBatchHash];
|
||||
require(
|
||||
_parentBatch.newStateRoot == _batch.prevStateRoot,
|
||||
"prevStateRoot is different from newStateRoot in the parent batch"
|
||||
);
|
||||
uint64 accTotalL1Messages = _parentBatch.totalL1Messages;
|
||||
|
||||
bytes32 publicInputHash;
|
||||
uint64 numTransactionsInBatch;
|
||||
uint64 lastBlockTimestamp;
|
||||
(publicInputHash, numTransactionsInBatch, accTotalL1Messages, lastBlockTimestamp) = _computePublicInputHash(
|
||||
accTotalL1Messages,
|
||||
_batch
|
||||
);
|
||||
|
||||
BatchStored storage _batchInStorage = batches[publicInputHash];
|
||||
|
||||
require(_batchInStorage.newStateRoot == bytes32(0), "Batch already commited");
|
||||
_batchInStorage.newStateRoot = _batch.newStateRoot;
|
||||
_batchInStorage.withdrawTrieRoot = _batch.withdrawTrieRoot;
|
||||
_batchInStorage.batchIndex = _batch.batchIndex;
|
||||
_batchInStorage.parentBatchHash = _batch.parentBatchHash;
|
||||
_batchInStorage.timestamp = lastBlockTimestamp;
|
||||
_batchInStorage.numTransactions = numTransactionsInBatch;
|
||||
_batchInStorage.totalL1Messages = accTotalL1Messages;
|
||||
|
||||
emit CommitBatch(publicInputHash);
|
||||
|
||||
return publicInputHash;
|
||||
}
|
||||
|
||||
/// @dev Internal function to compute the public input hash.
|
||||
/// @param accTotalL1Messages The number of total L1 messages in previous batch.
|
||||
/// @param batch The batch to compute.
|
||||
function _computePublicInputHash(uint64 accTotalL1Messages, Batch memory batch)
|
||||
internal
|
||||
view
|
||||
returns (
|
||||
bytes32,
|
||||
uint64,
|
||||
uint64,
|
||||
uint64
|
||||
)
|
||||
{
|
||||
bytes32 prevStateRoot = batch.prevStateRoot;
|
||||
bytes32 newStateRoot = batch.newStateRoot;
|
||||
bytes32 withdrawTrieRoot = batch.withdrawTrieRoot;
|
||||
// number of bytes in public inputs: 32 * 3 + 124 * blocks + 32 * MAX_NUM_TXS
|
||||
uint256 publicInputsSize = 32 * 3 + batch.blocks.length * 124 + 32 * maxNumTxInBatch;
|
||||
assembly {
|
||||
publicInputsPtr := mload(0x40)
|
||||
mstore(0x40, add(publicInputsPtr, publicInputsSize))
|
||||
mstore(publicInputsPtr, prevStateRoot)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
mstore(publicInputsPtr, newStateRoot)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
mstore(publicInputsPtr, withdrawTrieRoot)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
}
|
||||
uint256 publicInputsPtr;
|
||||
// 1. append prevStateRoot, newStateRoot and withdrawTrieRoot to public inputs
|
||||
{
|
||||
bytes32 prevStateRoot = batch.prevStateRoot;
|
||||
bytes32 newStateRoot = batch.newStateRoot;
|
||||
bytes32 withdrawTrieRoot = batch.withdrawTrieRoot;
|
||||
// number of bytes in public inputs: 32 * 3 + 124 * blocks + 32 * MAX_NUM_TXS
|
||||
uint256 publicInputsSize = 32 * 3 + batch.blocks.length * 124 + 32 * maxNumTxInBatch;
|
||||
assembly {
|
||||
publicInputsPtr := mload(0x40)
|
||||
mstore(0x40, add(publicInputsPtr, publicInputsSize))
|
||||
mstore(publicInputsPtr, prevStateRoot)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
mstore(publicInputsPtr, newStateRoot)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
mstore(publicInputsPtr, withdrawTrieRoot)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
}
|
||||
|
||||
uint64 numTransactionsInBatch;
|
||||
BlockContext memory _block;
|
||||
// 2. append block information to public inputs.
|
||||
for (uint256 i = 0; i < batch.blocks.length; i++) {
|
||||
// validate blocks, we won't check first block against previous batch.
|
||||
{
|
||||
BlockContext memory _currentBlock = batch.blocks[i];
|
||||
if (i > 0) {
|
||||
require(_block.blockHash == _currentBlock.parentHash, "Parent hash mismatch");
|
||||
require(_block.blockNumber + 1 == _currentBlock.blockNumber, "Block number mismatch");
|
||||
}
|
||||
_block = _currentBlock;
|
||||
}
|
||||
uint64 numTransactionsInBatch;
|
||||
BlockContext memory _block;
|
||||
// 2. append block information to public inputs.
|
||||
for (uint256 i = 0; i < batch.blocks.length; i++) {
|
||||
// validate blocks, we won't check first block against previous batch.
|
||||
{
|
||||
BlockContext memory _currentBlock = batch.blocks[i];
|
||||
if (i > 0) {
|
||||
require(_block.blockHash == _currentBlock.parentHash, "Parent hash mismatch");
|
||||
require(_block.blockNumber + 1 == _currentBlock.blockNumber, "Block number mismatch");
|
||||
}
|
||||
_block = _currentBlock;
|
||||
}
|
||||
|
||||
// append blockHash and parentHash to public inputs
|
||||
{
|
||||
bytes32 blockHash = _block.blockHash;
|
||||
bytes32 parentHash = _block.parentHash;
|
||||
assembly {
|
||||
mstore(publicInputsPtr, blockHash)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
mstore(publicInputsPtr, parentHash)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
// append blockHash and parentHash to public inputs
|
||||
{
|
||||
bytes32 blockHash = _block.blockHash;
|
||||
bytes32 parentHash = _block.parentHash;
|
||||
assembly {
|
||||
mstore(publicInputsPtr, blockHash)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
mstore(publicInputsPtr, parentHash)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
}
|
||||
// append blockNumber and blockTimestamp to public inputs
|
||||
{
|
||||
uint256 blockNumber = _block.blockNumber;
|
||||
uint256 blockTimestamp = _block.timestamp;
|
||||
assembly {
|
||||
mstore(publicInputsPtr, shl(192, blockNumber))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x8)
|
||||
mstore(publicInputsPtr, shl(192, blockTimestamp))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x8)
|
||||
}
|
||||
}
|
||||
// append baseFee to public inputs
|
||||
{
|
||||
uint256 baseFee = _block.baseFee;
|
||||
assembly {
|
||||
mstore(publicInputsPtr, baseFee)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
}
|
||||
uint64 numTransactionsInBlock = _block.numTransactions;
|
||||
// gasLimit, numTransactions and numL1Messages to public inputs
|
||||
{
|
||||
uint256 gasLimit = _block.gasLimit;
|
||||
uint256 numL1MessagesInBlock = _block.numL1Messages;
|
||||
assembly {
|
||||
mstore(publicInputsPtr, shl(192, gasLimit))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x8)
|
||||
mstore(publicInputsPtr, shl(240, numTransactionsInBlock))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x2)
|
||||
mstore(publicInputsPtr, shl(240, numL1MessagesInBlock))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x2)
|
||||
}
|
||||
}
|
||||
numTransactionsInBatch += numTransactionsInBlock;
|
||||
}
|
||||
}
|
||||
// append blockNumber and blockTimestamp to public inputs
|
||||
{
|
||||
uint256 blockNumber = _block.blockNumber;
|
||||
uint256 blockTimestamp = _block.timestamp;
|
||||
assembly {
|
||||
mstore(publicInputsPtr, shl(192, blockNumber))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x8)
|
||||
mstore(publicInputsPtr, shl(192, blockTimestamp))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x8)
|
||||
}
|
||||
}
|
||||
// append baseFee to public inputs
|
||||
{
|
||||
uint256 baseFee = _block.baseFee;
|
||||
assembly {
|
||||
mstore(publicInputsPtr, baseFee)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
}
|
||||
uint64 numTransactionsInBlock = _block.numTransactions;
|
||||
// gasLimit, numTransactions and numL1Messages to public inputs
|
||||
{
|
||||
uint256 gasLimit = _block.gasLimit;
|
||||
uint256 numL1MessagesInBlock = _block.numL1Messages;
|
||||
assembly {
|
||||
mstore(publicInputsPtr, shl(192, gasLimit))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x8)
|
||||
mstore(publicInputsPtr, shl(240, numTransactionsInBlock))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x2)
|
||||
mstore(publicInputsPtr, shl(240, numL1MessagesInBlock))
|
||||
publicInputsPtr := add(publicInputsPtr, 0x2)
|
||||
}
|
||||
}
|
||||
numTransactionsInBatch += numTransactionsInBlock;
|
||||
}
|
||||
require(numTransactionsInBatch <= maxNumTxInBatch, "Too many transactions in batch");
|
||||
require(numTransactionsInBatch <= maxNumTxInBatch, "Too many transactions in batch");
|
||||
|
||||
// 3. append transaction hash to public inputs.
|
||||
address _messageQueue = messageQueue;
|
||||
uint256 _l2TxnPtr;
|
||||
{
|
||||
bytes memory l2Transactions = batch.l2Transactions;
|
||||
assembly {
|
||||
_l2TxnPtr := add(l2Transactions, 0x20)
|
||||
}
|
||||
}
|
||||
for (uint256 i = 0; i < batch.blocks.length; i++) {
|
||||
uint256 numL1MessagesInBlock = batch.blocks[i].numL1Messages;
|
||||
while (numL1MessagesInBlock > 0) {
|
||||
bytes32 hash = IL1MessageQueue(_messageQueue).getCrossDomainMessage(uint64(accTotalL1Messages));
|
||||
assembly {
|
||||
mstore(publicInputsPtr, hash)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
// 3. append transaction hash to public inputs.
|
||||
address _messageQueue = messageQueue;
|
||||
uint256 _l2TxnPtr;
|
||||
{
|
||||
bytes memory l2Transactions = batch.l2Transactions;
|
||||
assembly {
|
||||
_l2TxnPtr := add(l2Transactions, 0x20)
|
||||
}
|
||||
}
|
||||
unchecked {
|
||||
accTotalL1Messages += 1;
|
||||
numL1MessagesInBlock -= 1;
|
||||
for (uint256 i = 0; i < batch.blocks.length; i++) {
|
||||
uint256 numL1MessagesInBlock = batch.blocks[i].numL1Messages;
|
||||
while (numL1MessagesInBlock > 0) {
|
||||
bytes32 hash = IL1MessageQueue(_messageQueue).getCrossDomainMessage(uint64(accTotalL1Messages));
|
||||
assembly {
|
||||
mstore(publicInputsPtr, hash)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
unchecked {
|
||||
accTotalL1Messages += 1;
|
||||
numL1MessagesInBlock -= 1;
|
||||
}
|
||||
}
|
||||
numL1MessagesInBlock = batch.blocks[i].numL1Messages;
|
||||
uint256 numTransactionsInBlock = batch.blocks[i].numTransactions;
|
||||
for (uint256 j = numL1MessagesInBlock; j < numTransactionsInBlock; ++j) {
|
||||
bytes32 hash;
|
||||
assembly {
|
||||
let txPayloadLength := shr(224, mload(_l2TxnPtr))
|
||||
_l2TxnPtr := add(_l2TxnPtr, 4)
|
||||
_l2TxnPtr := add(_l2TxnPtr, txPayloadLength)
|
||||
hash := keccak256(sub(_l2TxnPtr, txPayloadLength), txPayloadLength)
|
||||
mstore(publicInputsPtr, hash)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
numL1MessagesInBlock = batch.blocks[i].numL1Messages;
|
||||
uint256 numTransactionsInBlock = batch.blocks[i].numTransactions;
|
||||
for (uint256 j = numL1MessagesInBlock; j < numTransactionsInBlock; ++j) {
|
||||
bytes32 hash;
|
||||
assembly {
|
||||
let txPayloadLength := shr(224, mload(_l2TxnPtr))
|
||||
_l2TxnPtr := add(_l2TxnPtr, 4)
|
||||
_l2TxnPtr := add(_l2TxnPtr, txPayloadLength)
|
||||
hash := keccak256(sub(_l2TxnPtr, txPayloadLength), txPayloadLength)
|
||||
mstore(publicInputsPtr, hash)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
|
||||
// 4. append padding transaction to public inputs.
|
||||
bytes32 txHashPadding = paddingTxHash;
|
||||
for (uint256 i = numTransactionsInBatch; i < maxNumTxInBatch; i++) {
|
||||
assembly {
|
||||
mstore(publicInputsPtr, txHashPadding)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. append padding transaction to public inputs.
|
||||
bytes32 txHashPadding = paddingTxHash;
|
||||
for (uint256 i = numTransactionsInBatch; i < maxNumTxInBatch; i++) {
|
||||
assembly {
|
||||
mstore(publicInputsPtr, txHashPadding)
|
||||
publicInputsPtr := add(publicInputsPtr, 0x20)
|
||||
}
|
||||
}
|
||||
// 5. compute public input hash
|
||||
bytes32 publicInputHash;
|
||||
{
|
||||
uint256 publicInputsSize = 32 * 3 + batch.blocks.length * 124 + 32 * maxNumTxInBatch;
|
||||
assembly {
|
||||
publicInputHash := keccak256(sub(publicInputsPtr, publicInputsSize), publicInputsSize)
|
||||
}
|
||||
}
|
||||
|
||||
// 5. compute public input hash
|
||||
bytes32 publicInputHash;
|
||||
{
|
||||
uint256 publicInputsSize = 32 * 3 + batch.blocks.length * 124 + 32 * maxNumTxInBatch;
|
||||
assembly {
|
||||
publicInputHash := keccak256(sub(publicInputsPtr, publicInputsSize), publicInputsSize)
|
||||
}
|
||||
return (publicInputHash, numTransactionsInBatch, accTotalL1Messages, _block.timestamp);
|
||||
}
|
||||
|
||||
return (publicInputHash, numTransactionsInBatch, accTotalL1Messages, _block.timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
59
contracts/src/L1/rollup/ScrollChainCommitmentVerifier.sol
Normal file
59
contracts/src/L1/rollup/ScrollChainCommitmentVerifier.sol
Normal file
@@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {ScrollChain} from "./ScrollChain.sol";
|
||||
import {ZkTrieVerifier} from "../../libraries/verifier/ZkTrieVerifier.sol";
|
||||
|
||||
contract ScrollChainCommitmentVerifier {
|
||||
/// @notice The address of poseidon hash contract
|
||||
address public immutable poseidon;
|
||||
|
||||
/// @notice The address of ScrollChain contract.
|
||||
address public immutable rollup;
|
||||
|
||||
constructor(address _poseidon, address _rollup) {
|
||||
poseidon = _poseidon;
|
||||
rollup = _rollup;
|
||||
}
|
||||
|
||||
/// @notice Validates a proof from eth_getProof in l2geth.
|
||||
/// @param account The address of the contract.
|
||||
/// @param storageKey The storage slot to verify.
|
||||
/// @param proof The rlp encoding result of eth_getProof.
|
||||
/// @return stateRoot The computed state root. Must be checked by the caller.
|
||||
/// @return storageValue The value of `storageKey`.
|
||||
///
|
||||
/// The encoding order of `proof` is
|
||||
/// ```text
|
||||
/// | 1 byte | ... | 1 byte | ... |
|
||||
/// | account proof length | account proof | storage proof length | storage proof |
|
||||
/// ```
|
||||
function verifyZkTrieProof(
|
||||
address account,
|
||||
bytes32 storageKey,
|
||||
bytes calldata proof
|
||||
) public view returns (bytes32 stateRoot, bytes32 storageValue) {
|
||||
return ZkTrieVerifier.verifyZkTrieProof(poseidon, account, storageKey, proof);
|
||||
}
|
||||
|
||||
/// @notice Verifies a batch inclusion proof.
|
||||
/// @param batchHash The hash of the batch.
|
||||
/// @param account The address of the contract in L2.
|
||||
/// @param storageKey The storage key inside the contract in L2.
|
||||
/// @param proof The rlp encoding result of eth_getProof.
|
||||
/// @return storageValue The value of `storageKey`.
|
||||
function verifyStateCommitment(
|
||||
bytes32 batchHash,
|
||||
address account,
|
||||
bytes32 storageKey,
|
||||
bytes calldata proof
|
||||
) external view returns (bytes32 storageValue) {
|
||||
require(ScrollChain(rollup).isBatchFinalized(batchHash), "Batch not finalized");
|
||||
|
||||
bytes32 computedStateRoot;
|
||||
(computedStateRoot, storageValue) = ZkTrieVerifier.verifyZkTrieProof(poseidon, account, storageKey, proof);
|
||||
(bytes32 expectedStateRoot, , , , , , , ) = ScrollChain(rollup).batches(batchHash);
|
||||
require(computedStateRoot == expectedStateRoot, "Invalid inclusion proof");
|
||||
}
|
||||
}
|
||||
@@ -2,50 +2,50 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { IScrollMessenger } from "../libraries/IScrollMessenger.sol";
|
||||
import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";
|
||||
|
||||
interface IL2ScrollMessenger is IScrollMessenger {
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
|
||||
struct L1MessageProof {
|
||||
bytes32 blockHash;
|
||||
bytes stateRootProof;
|
||||
}
|
||||
struct L1MessageProof {
|
||||
bytes32 blockHash;
|
||||
bytes stateRootProof;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice execute L1 => L2 message
|
||||
/// @dev Make sure this is only called by privileged accounts.
|
||||
/// @param from The address of the sender of the message.
|
||||
/// @param to The address of the recipient of the message.
|
||||
/// @param value The msg.value passed to the message call.
|
||||
/// @param nonce The nonce of the message to avoid replay attack.
|
||||
/// @param message The content of the message.
|
||||
function relayMessage(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value,
|
||||
uint256 nonce,
|
||||
bytes calldata message
|
||||
) external;
|
||||
/// @notice execute L1 => L2 message
|
||||
/// @dev Make sure this is only called by privileged accounts.
|
||||
/// @param from The address of the sender of the message.
|
||||
/// @param to The address of the recipient of the message.
|
||||
/// @param value The msg.value passed to the message call.
|
||||
/// @param nonce The nonce of the message to avoid replay attack.
|
||||
/// @param message The content of the message.
|
||||
function relayMessage(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value,
|
||||
uint256 nonce,
|
||||
bytes calldata message
|
||||
) external;
|
||||
|
||||
/// @notice execute L1 => L2 message with proof
|
||||
/// @param from The address of the sender of the message.
|
||||
/// @param to The address of the recipient of the message.
|
||||
/// @param value The msg.value passed to the message call.
|
||||
/// @param nonce The nonce of the message to avoid replay attack.
|
||||
/// @param message The content of the message.
|
||||
/// @param proof The message proof.
|
||||
function retryMessageWithProof(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value,
|
||||
uint256 nonce,
|
||||
bytes calldata message,
|
||||
L1MessageProof calldata proof
|
||||
) external;
|
||||
/// @notice execute L1 => L2 message with proof
|
||||
/// @param from The address of the sender of the message.
|
||||
/// @param to The address of the recipient of the message.
|
||||
/// @param value The msg.value passed to the message call.
|
||||
/// @param nonce The nonce of the message to avoid replay attack.
|
||||
/// @param message The content of the message.
|
||||
/// @param proof The message proof.
|
||||
function retryMessageWithProof(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value,
|
||||
uint256 nonce,
|
||||
bytes calldata message,
|
||||
L1MessageProof calldata proof
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
||||
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
||||
|
||||
import { IL2ScrollMessenger } from "./IL2ScrollMessenger.sol";
|
||||
import { L2MessageQueue } from "./predeploys/L2MessageQueue.sol";
|
||||
import { IL1BlockContainer } from "./predeploys/IL1BlockContainer.sol";
|
||||
import { IL1GasPriceOracle } from "./predeploys/IL1GasPriceOracle.sol";
|
||||
import {IL2ScrollMessenger} from "./IL2ScrollMessenger.sol";
|
||||
import {L2MessageQueue} from "./predeploys/L2MessageQueue.sol";
|
||||
import {IL1BlockContainer} from "./predeploys/IL1BlockContainer.sol";
|
||||
import {IL1GasPriceOracle} from "./predeploys/IL1GasPriceOracle.sol";
|
||||
|
||||
import { PatriciaMerkleTrieVerifier } from "../libraries/verifier/PatriciaMerkleTrieVerifier.sol";
|
||||
import { ScrollConstants } from "../libraries/constants/ScrollConstants.sol";
|
||||
import { IScrollMessenger } from "../libraries/IScrollMessenger.sol";
|
||||
import { ScrollMessengerBase } from "../libraries/ScrollMessengerBase.sol";
|
||||
import {PatriciaMerkleTrieVerifier} from "../libraries/verifier/PatriciaMerkleTrieVerifier.sol";
|
||||
import {ScrollConstants} from "../libraries/constants/ScrollConstants.sol";
|
||||
import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";
|
||||
import {ScrollMessengerBase} from "../libraries/ScrollMessengerBase.sol";
|
||||
|
||||
/// @title L2ScrollMessenger
|
||||
/// @notice The `L2ScrollMessenger` contract can:
|
||||
@@ -24,265 +24,327 @@ import { ScrollMessengerBase } from "../libraries/ScrollMessengerBase.sol";
|
||||
/// @dev It should be a predeployed contract in layer 2 and should hold infinite amount
|
||||
/// of Ether (Specifically, `uint256(-1)`), which can be initialized in Genesis Block.
|
||||
contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2ScrollMessenger {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when the maximum number of times each message can fail in L2 is updated.
|
||||
/// @param maxFailedExecutionTimes The new maximum number of times each message can fail in L2.
|
||||
event UpdateMaxFailedExecutionTimes(uint256 maxFailedExecutionTimes);
|
||||
/// @notice Emitted when the maximum number of times each message can fail in L2 is updated.
|
||||
/// @param maxFailedExecutionTimes The new maximum number of times each message can fail in L2.
|
||||
event UpdateMaxFailedExecutionTimes(uint256 maxFailedExecutionTimes);
|
||||
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
|
||||
uint256 private constant MIN_GAS_LIMIT = 21000;
|
||||
uint256 private constant MIN_GAS_LIMIT = 21000;
|
||||
|
||||
/// @notice The contract contains the list of L1 blocks.
|
||||
address public immutable blockContainer;
|
||||
/// @notice The contract contains the list of L1 blocks.
|
||||
address public immutable blockContainer;
|
||||
|
||||
/// @notice The address of L2MessageQueue.
|
||||
address public immutable gasOracle;
|
||||
/// @notice The address of L2MessageQueue.
|
||||
address public immutable gasOracle;
|
||||
|
||||
/// @notice The address of L2MessageQueue.
|
||||
address public immutable messageQueue;
|
||||
/// @notice The address of L2MessageQueue.
|
||||
address public immutable messageQueue;
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from L2 message hash to sent status.
|
||||
mapping(bytes32 => bool) public isL2MessageSent;
|
||||
/// @notice Mapping from L2 message hash to sent status.
|
||||
mapping(bytes32 => bool) public isL2MessageSent;
|
||||
|
||||
/// @notice Mapping from L1 message hash to a boolean value indicating if the message has been successfully executed.
|
||||
mapping(bytes32 => bool) public isL1MessageExecuted;
|
||||
/// @notice Mapping from L1 message hash to a boolean value indicating if the message has been successfully executed.
|
||||
mapping(bytes32 => bool) public isL1MessageExecuted;
|
||||
|
||||
/// @notice Mapping from L1 message hash to the number of failure times.
|
||||
mapping(bytes32 => uint256) public l1MessageFailedTimes;
|
||||
/// @notice Mapping from L1 message hash to the number of failure times.
|
||||
mapping(bytes32 => uint256) public l1MessageFailedTimes;
|
||||
|
||||
/// @notice The maximum number of times each L1 message can fail on L2.
|
||||
uint256 public maxFailedExecutionTimes;
|
||||
/// @notice The maximum number of times each L1 message can fail on L2.
|
||||
uint256 public maxFailedExecutionTimes;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
// @note move to ScrollMessengerBase in next big refactor
|
||||
/// @dev The status of for non-reentrant check.
|
||||
uint256 private _lock_status;
|
||||
|
||||
constructor(
|
||||
address _blockContainer,
|
||||
address _gasOracle,
|
||||
address _messageQueue
|
||||
) {
|
||||
blockContainer = _blockContainer;
|
||||
gasOracle = _gasOracle;
|
||||
messageQueue = _messageQueue;
|
||||
}
|
||||
/**********************
|
||||
* Function Modifiers *
|
||||
**********************/
|
||||
|
||||
function initialize(address _counterpart, address _feeVault) external initializer {
|
||||
PausableUpgradeable.__Pausable_init();
|
||||
ScrollMessengerBase._initialize(_counterpart, _feeVault);
|
||||
modifier nonReentrant() {
|
||||
// On the first call to nonReentrant, _notEntered will be true
|
||||
require(_lock_status != _ENTERED, "ReentrancyGuard: reentrant call");
|
||||
|
||||
maxFailedExecutionTimes = 3;
|
||||
// Any calls to nonReentrant after this point will fail
|
||||
_lock_status = _ENTERED;
|
||||
|
||||
// initialize to a nonzero value
|
||||
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
|
||||
}
|
||||
_;
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Check whether the l1 message is included in the corresponding L1 block.
|
||||
/// @param _blockHash The block hash where the message should in.
|
||||
/// @param _msgHash The hash of the message to check.
|
||||
/// @param _proof The encoded storage proof from eth_getProof.
|
||||
/// @return bool Return true is the message is included in L1, otherwise return false.
|
||||
function verifyMessageInclusionStatus(
|
||||
bytes32 _blockHash,
|
||||
bytes32 _msgHash,
|
||||
bytes calldata _proof
|
||||
) public view returns (bool) {
|
||||
bytes32 _expectedStateRoot = IL1BlockContainer(blockContainer).getStateRoot(_blockHash);
|
||||
require(_expectedStateRoot != bytes32(0), "Block is not imported");
|
||||
|
||||
// @todo fix the actual slot later.
|
||||
bytes32 _storageKey;
|
||||
// `mapping(bytes32 => bool) public isL1MessageSent` is the 105-nd slot of contract `L1ScrollMessenger`.
|
||||
assembly {
|
||||
mstore(0x00, _msgHash)
|
||||
mstore(0x20, 105)
|
||||
_storageKey := keccak256(0x00, 0x40)
|
||||
// By storing the original value once again, a refund is triggered (see
|
||||
// https://eips.ethereum.org/EIPS/eip-2200)
|
||||
_lock_status = _NOT_ENTERED;
|
||||
}
|
||||
|
||||
(bytes32 _computedStateRoot, bytes32 _storageValue) = PatriciaMerkleTrieVerifier.verifyPatriciaProof(
|
||||
counterpart,
|
||||
_storageKey,
|
||||
_proof
|
||||
);
|
||||
require(_computedStateRoot == _expectedStateRoot, "State roots mismatch");
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
return uint256(_storageValue) == 1;
|
||||
}
|
||||
|
||||
/// @notice Check whether the message is executed in the corresponding L1 block.
|
||||
/// @param _blockHash The block hash where the message should in.
|
||||
/// @param _msgHash The hash of the message to check.
|
||||
/// @param _proof The encoded storage proof from eth_getProof.
|
||||
/// @return bool Return true is the message is executed in L1, otherwise return false.
|
||||
function verifyMessageExecutionStatus(
|
||||
bytes32 _blockHash,
|
||||
bytes32 _msgHash,
|
||||
bytes calldata _proof
|
||||
) external view returns (bool) {
|
||||
bytes32 _expectedStateRoot = IL1BlockContainer(blockContainer).getStateRoot(_blockHash);
|
||||
require(_expectedStateRoot != bytes32(0), "Block not imported");
|
||||
|
||||
// @todo fix the actual slot later.
|
||||
bytes32 _storageKey;
|
||||
// `mapping(bytes32 => bool) public isL2MessageExecuted` is the 106-th slot of contract `L1ScrollMessenger`.
|
||||
assembly {
|
||||
mstore(0x00, _msgHash)
|
||||
mstore(0x20, 106)
|
||||
_storageKey := keccak256(0x00, 0x40)
|
||||
constructor(
|
||||
address _blockContainer,
|
||||
address _gasOracle,
|
||||
address _messageQueue
|
||||
) {
|
||||
blockContainer = _blockContainer;
|
||||
gasOracle = _gasOracle;
|
||||
messageQueue = _messageQueue;
|
||||
}
|
||||
|
||||
(bytes32 _computedStateRoot, bytes32 _storageValue) = PatriciaMerkleTrieVerifier.verifyPatriciaProof(
|
||||
counterpart,
|
||||
_storageKey,
|
||||
_proof
|
||||
);
|
||||
require(_computedStateRoot == _expectedStateRoot, "State root mismatch");
|
||||
function initialize(address _counterpart, address _feeVault) external initializer {
|
||||
PausableUpgradeable.__Pausable_init();
|
||||
ScrollMessengerBase._initialize(_counterpart, _feeVault);
|
||||
|
||||
return uint256(_storageValue) == 1;
|
||||
}
|
||||
maxFailedExecutionTimes = 3;
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IScrollMessenger
|
||||
function sendMessage(
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external payable override whenNotPaused {
|
||||
// by pass fee vault relay
|
||||
if (feeVault != msg.sender) {
|
||||
require(_gasLimit >= MIN_GAS_LIMIT, "gas limit too small");
|
||||
// initialize to a nonzero value
|
||||
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
|
||||
}
|
||||
|
||||
// compute and deduct the messaging fee to fee vault.
|
||||
uint256 _fee = _gasLimit * IL1GasPriceOracle(gasOracle).l1BaseFee();
|
||||
require(msg.value >= _value + _fee, "Insufficient msg.value");
|
||||
if (_fee > 0) {
|
||||
(bool _success, ) = feeVault.call{ value: msg.value - _value }("");
|
||||
require(_success, "Failed to deduct the fee");
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Check whether the l1 message is included in the corresponding L1 block.
|
||||
/// @param _blockHash The block hash where the message should in.
|
||||
/// @param _msgHash The hash of the message to check.
|
||||
/// @param _proof The encoded storage proof from eth_getProof.
|
||||
/// @return bool Return true is the message is included in L1, otherwise return false.
|
||||
function verifyMessageInclusionStatus(
|
||||
bytes32 _blockHash,
|
||||
bytes32 _msgHash,
|
||||
bytes calldata _proof
|
||||
) public view returns (bool) {
|
||||
bytes32 _expectedStateRoot = IL1BlockContainer(blockContainer).getStateRoot(_blockHash);
|
||||
require(_expectedStateRoot != bytes32(0), "Block is not imported");
|
||||
|
||||
// @todo fix the actual slot later.
|
||||
bytes32 _storageKey;
|
||||
// `mapping(bytes32 => bool) public isL1MessageSent` is the 105-nd slot of contract `L1ScrollMessenger`.
|
||||
assembly {
|
||||
mstore(0x00, _msgHash)
|
||||
mstore(0x20, 105)
|
||||
_storageKey := keccak256(0x00, 0x40)
|
||||
}
|
||||
|
||||
(bytes32 _computedStateRoot, bytes32 _storageValue) = PatriciaMerkleTrieVerifier.verifyPatriciaProof(
|
||||
counterpart,
|
||||
_storageKey,
|
||||
_proof
|
||||
);
|
||||
require(_computedStateRoot == _expectedStateRoot, "State roots mismatch");
|
||||
|
||||
return uint256(_storageValue) == 1;
|
||||
}
|
||||
|
||||
uint256 _nonce = L2MessageQueue(messageQueue).nextMessageIndex();
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(msg.sender, _to, _value, _nonce, _message));
|
||||
/// @notice Check whether the message is executed in the corresponding L1 block.
|
||||
/// @param _blockHash The block hash where the message should in.
|
||||
/// @param _msgHash The hash of the message to check.
|
||||
/// @param _proof The encoded storage proof from eth_getProof.
|
||||
/// @return bool Return true is the message is executed in L1, otherwise return false.
|
||||
function verifyMessageExecutionStatus(
|
||||
bytes32 _blockHash,
|
||||
bytes32 _msgHash,
|
||||
bytes calldata _proof
|
||||
) external view returns (bool) {
|
||||
bytes32 _expectedStateRoot = IL1BlockContainer(blockContainer).getStateRoot(_blockHash);
|
||||
require(_expectedStateRoot != bytes32(0), "Block not imported");
|
||||
|
||||
require(!isL2MessageSent[_xDomainCalldataHash], "Duplicated message");
|
||||
isL2MessageSent[_xDomainCalldataHash] = true;
|
||||
// @todo fix the actual slot later.
|
||||
bytes32 _storageKey;
|
||||
// `mapping(bytes32 => bool) public isL2MessageExecuted` is the 106-th slot of contract `L1ScrollMessenger`.
|
||||
assembly {
|
||||
mstore(0x00, _msgHash)
|
||||
mstore(0x20, 106)
|
||||
_storageKey := keccak256(0x00, 0x40)
|
||||
}
|
||||
|
||||
L2MessageQueue(messageQueue).appendMessage(_xDomainCalldataHash);
|
||||
(bytes32 _computedStateRoot, bytes32 _storageValue) = PatriciaMerkleTrieVerifier.verifyPatriciaProof(
|
||||
counterpart,
|
||||
_storageKey,
|
||||
_proof
|
||||
);
|
||||
require(_computedStateRoot == _expectedStateRoot, "State root mismatch");
|
||||
|
||||
emit SentMessage(msg.sender, _to, _value, _nonce, _gasLimit, _message);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ScrollMessenger
|
||||
function relayMessage(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
uint256 _nonce,
|
||||
bytes memory _message
|
||||
) external override whenNotPaused onlyWhitelistedSender(msg.sender) {
|
||||
// anti reentrance
|
||||
require(xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER, "Message is already in execution");
|
||||
|
||||
// @todo address unalis to check sender is L1ScrollMessenger
|
||||
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
|
||||
|
||||
require(!isL1MessageExecuted[_xDomainCalldataHash], "Message was already successfully executed");
|
||||
|
||||
_executeMessage(_from, _to, _value, _message, _xDomainCalldataHash);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ScrollMessenger
|
||||
function retryMessageWithProof(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
uint256 _nonce,
|
||||
bytes memory _message,
|
||||
L1MessageProof calldata _proof
|
||||
) external override whenNotPaused {
|
||||
// anti reentrance
|
||||
require(xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER, "Already in execution");
|
||||
|
||||
// check message status
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
|
||||
require(!isL1MessageExecuted[_xDomainCalldataHash], "Message successfully executed");
|
||||
require(l1MessageFailedTimes[_xDomainCalldataHash] > 0, "Message not relayed before");
|
||||
|
||||
require(
|
||||
verifyMessageInclusionStatus(_proof.blockHash, _xDomainCalldataHash, _proof.stateRootProof),
|
||||
"Message not included"
|
||||
);
|
||||
|
||||
_executeMessage(_from, _to, _value, _message, _xDomainCalldataHash);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Pause the contract
|
||||
/// @dev This function can only called by contract owner.
|
||||
function pause() external onlyOwner {
|
||||
_pause();
|
||||
}
|
||||
|
||||
function updateMaxFailedExecutionTimes(uint256 _maxFailedExecutionTimes) external onlyOwner {
|
||||
maxFailedExecutionTimes = _maxFailedExecutionTimes;
|
||||
|
||||
emit UpdateMaxFailedExecutionTimes(_maxFailedExecutionTimes);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
function _executeMessage(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes memory _message,
|
||||
bytes32 _xDomainCalldataHash
|
||||
) internal {
|
||||
// @todo check `_to` address to avoid attack.
|
||||
|
||||
// @note This usually will never happen, just in case.
|
||||
require(_from != xDomainMessageSender, "Invalid message sender");
|
||||
|
||||
xDomainMessageSender = _from;
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool success, ) = _to.call{ value: _value }(_message);
|
||||
// reset value to refund gas.
|
||||
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
|
||||
|
||||
if (success) {
|
||||
isL1MessageExecuted[_xDomainCalldataHash] = true;
|
||||
emit RelayedMessage(_xDomainCalldataHash);
|
||||
} else {
|
||||
unchecked {
|
||||
uint256 _failedTimes = l1MessageFailedTimes[_xDomainCalldataHash] + 1;
|
||||
require(_failedTimes <= maxFailedExecutionTimes, "Exceed maximum failure times");
|
||||
l1MessageFailedTimes[_xDomainCalldataHash] = _failedTimes;
|
||||
}
|
||||
emit FailedRelayedMessage(_xDomainCalldataHash);
|
||||
return uint256(_storageValue) == 1;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
/// @inheritdoc IScrollMessenger
|
||||
function sendMessage(
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit
|
||||
) external payable override whenNotPaused {
|
||||
_sendMessage(_to, _value, _message, _gasLimit, tx.origin);
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollMessenger
|
||||
function sendMessage(
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes calldata _message,
|
||||
uint256 _gasLimit,
|
||||
address _refundAddress
|
||||
) external payable override whenNotPaused {
|
||||
_sendMessage(_to, _value, _message, _gasLimit, _refundAddress);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ScrollMessenger
|
||||
function relayMessage(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
uint256 _nonce,
|
||||
bytes memory _message
|
||||
) external override whenNotPaused onlyWhitelistedSender(msg.sender) {
|
||||
// anti reentrance
|
||||
require(
|
||||
xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER,
|
||||
"Message is already in execution"
|
||||
);
|
||||
|
||||
// @todo address unalis to check sender is L1ScrollMessenger
|
||||
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
|
||||
|
||||
require(!isL1MessageExecuted[_xDomainCalldataHash], "Message was already successfully executed");
|
||||
|
||||
_executeMessage(_from, _to, _value, _message, _xDomainCalldataHash);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ScrollMessenger
|
||||
function retryMessageWithProof(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
uint256 _nonce,
|
||||
bytes memory _message,
|
||||
L1MessageProof calldata _proof
|
||||
) external override whenNotPaused {
|
||||
// anti reentrance
|
||||
require(xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER, "Already in execution");
|
||||
|
||||
// check message status
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
|
||||
require(!isL1MessageExecuted[_xDomainCalldataHash], "Message successfully executed");
|
||||
require(l1MessageFailedTimes[_xDomainCalldataHash] > 0, "Message not relayed before");
|
||||
|
||||
require(
|
||||
verifyMessageInclusionStatus(_proof.blockHash, _xDomainCalldataHash, _proof.stateRootProof),
|
||||
"Message not included"
|
||||
);
|
||||
|
||||
_executeMessage(_from, _to, _value, _message, _xDomainCalldataHash);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Pause the contract
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _status The pause status to update.
|
||||
function setPause(bool _status) external onlyOwner {
|
||||
if (_status) {
|
||||
_pause();
|
||||
} else {
|
||||
_unpause();
|
||||
}
|
||||
}
|
||||
|
||||
function updateMaxFailedExecutionTimes(uint256 _maxFailedExecutionTimes) external onlyOwner {
|
||||
maxFailedExecutionTimes = _maxFailedExecutionTimes;
|
||||
|
||||
emit UpdateMaxFailedExecutionTimes(_maxFailedExecutionTimes);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
function _sendMessage(
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes memory _message,
|
||||
uint256 _gasLimit,
|
||||
address _refundAddress
|
||||
) internal nonReentrant {
|
||||
// by pass fee vault relay
|
||||
if (feeVault != msg.sender) {
|
||||
require(_gasLimit >= MIN_GAS_LIMIT, "gas limit too small");
|
||||
}
|
||||
|
||||
// compute and deduct the messaging fee to fee vault.
|
||||
uint256 _fee = _gasLimit * IL1GasPriceOracle(gasOracle).l1BaseFee();
|
||||
require(msg.value >= _value + _fee, "Insufficient msg.value");
|
||||
if (_fee > 0) {
|
||||
(bool _success, ) = feeVault.call{value: _fee}("");
|
||||
require(_success, "Failed to deduct the fee");
|
||||
}
|
||||
|
||||
uint256 _nonce = L2MessageQueue(messageQueue).nextMessageIndex();
|
||||
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(msg.sender, _to, _value, _nonce, _message));
|
||||
|
||||
// normally this won't happen, since each message has different nonce, but just in case.
|
||||
require(!isL2MessageSent[_xDomainCalldataHash], "Duplicated message");
|
||||
isL2MessageSent[_xDomainCalldataHash] = true;
|
||||
|
||||
L2MessageQueue(messageQueue).appendMessage(_xDomainCalldataHash);
|
||||
|
||||
emit SentMessage(msg.sender, _to, _value, _nonce, _gasLimit, _message);
|
||||
|
||||
// refund fee to tx.origin
|
||||
unchecked {
|
||||
uint256 _refund = msg.value - _fee - _value;
|
||||
if (_refund > 0) {
|
||||
(bool _success, ) = _refundAddress.call{value: _refund}("");
|
||||
require(_success, "Failed to refund the fee");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _executeMessage(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes memory _message,
|
||||
bytes32 _xDomainCalldataHash
|
||||
) internal {
|
||||
// @todo check more `_to` address to avoid attack.
|
||||
require(_to != messageQueue, "Forbid to call message queue");
|
||||
require(_to != address(this), "Forbid to call self");
|
||||
|
||||
// @note This usually will never happen, just in case.
|
||||
require(_from != xDomainMessageSender, "Invalid message sender");
|
||||
|
||||
xDomainMessageSender = _from;
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool success, ) = _to.call{value: _value}(_message);
|
||||
// reset value to refund gas.
|
||||
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
|
||||
|
||||
if (success) {
|
||||
isL1MessageExecuted[_xDomainCalldataHash] = true;
|
||||
emit RelayedMessage(_xDomainCalldataHash);
|
||||
} else {
|
||||
unchecked {
|
||||
uint256 _failedTimes = l1MessageFailedTimes[_xDomainCalldataHash] + 1;
|
||||
require(_failedTimes <= maxFailedExecutionTimes, "Exceed maximum failure times");
|
||||
l1MessageFailedTimes[_xDomainCalldataHash] = _failedTimes;
|
||||
}
|
||||
emit FailedRelayedMessage(_xDomainCalldataHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,165 +4,165 @@ pragma solidity ^0.8.0;
|
||||
|
||||
/// @title The interface for the ERC1155 cross chain gateway in layer 2.
|
||||
interface IL2ERC1155Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when the ERC1155 NFT is transfered to recipient in layer 2.
|
||||
/// @param l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 1.
|
||||
/// @param to The address of recipient in layer 2.
|
||||
/// @param tokenId The token id of the ERC1155 NFT deposited in layer 1.
|
||||
/// @param amount The amount of token deposited.
|
||||
event FinalizeDepositERC1155(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 amount
|
||||
);
|
||||
/// @notice Emitted when the ERC1155 NFT is transfered to recipient in layer 2.
|
||||
/// @param l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 1.
|
||||
/// @param to The address of recipient in layer 2.
|
||||
/// @param tokenId The token id of the ERC1155 NFT deposited in layer 1.
|
||||
/// @param amount The amount of token deposited.
|
||||
event FinalizeDepositERC1155(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC1155 NFT is batch transfered to recipient in layer 2.
|
||||
/// @param l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 1.
|
||||
/// @param to The address of recipient in layer 2.
|
||||
/// @param tokenIds The list of token ids of the ERC1155 NFT deposited in layer 1.
|
||||
/// @param amounts The list of corresponding amounts deposited.
|
||||
event FinalizeBatchDepositERC1155(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256[] tokenIds,
|
||||
uint256[] amounts
|
||||
);
|
||||
/// @notice Emitted when the ERC1155 NFT is batch transfered to recipient in layer 2.
|
||||
/// @param l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 1.
|
||||
/// @param to The address of recipient in layer 2.
|
||||
/// @param tokenIds The list of token ids of the ERC1155 NFT deposited in layer 1.
|
||||
/// @param amounts The list of corresponding amounts deposited.
|
||||
event FinalizeBatchDepositERC1155(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256[] tokenIds,
|
||||
uint256[] amounts
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC1155 NFT is transfered to gateway in layer 2.
|
||||
/// @param l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenId The token id of the ERC1155 NFT to withdraw in layer 2.
|
||||
/// @param amount The amount of token to withdraw.
|
||||
event WithdrawERC1155(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 amount
|
||||
);
|
||||
/// @notice Emitted when the ERC1155 NFT is transfered to gateway in layer 2.
|
||||
/// @param l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenId The token id of the ERC1155 NFT to withdraw in layer 2.
|
||||
/// @param amount The amount of token to withdraw.
|
||||
event WithdrawERC1155(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC1155 NFT is batch transfered to gateway in layer 2.
|
||||
/// @param l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenIds The list of token ids of the ERC1155 NFT to withdraw in layer 2.
|
||||
/// @param amounts The list of corresponding amounts to withdraw.
|
||||
event BatchWithdrawERC1155(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256[] tokenIds,
|
||||
uint256[] amounts
|
||||
);
|
||||
/// @notice Emitted when the ERC1155 NFT is batch transfered to gateway in layer 2.
|
||||
/// @param l1Token The address of ERC1155 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC1155 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenIds The list of token ids of the ERC1155 NFT to withdraw in layer 2.
|
||||
/// @param amounts The list of corresponding amounts to withdraw.
|
||||
event BatchWithdrawERC1155(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256[] tokenIds,
|
||||
uint256[] amounts
|
||||
);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Withdraw some ERC1155 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC1155 NFT in layer 2.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
/// @param amount The amount of token to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC1155(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
/// @notice Withdraw some ERC1155 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC1155 NFT in layer 2.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
/// @param amount The amount of token to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC1155(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
|
||||
/// @notice Withdraw some ERC1155 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC1155 NFT in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
/// @param amount The amount of token to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC1155(
|
||||
address token,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
/// @notice Withdraw some ERC1155 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC1155 NFT in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
/// @param amount The amount of token to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC1155(
|
||||
address token,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
|
||||
/// @notice Batch withdraw a list of ERC1155 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC1155 NFT in layer 2.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
/// @param amounts The list of corresponding amounts to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function batchWithdrawERC1155(
|
||||
address token,
|
||||
uint256[] memory tokenIds,
|
||||
uint256[] memory amounts,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
/// @notice Batch withdraw a list of ERC1155 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC1155 NFT in layer 2.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
/// @param amounts The list of corresponding amounts to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function batchWithdrawERC1155(
|
||||
address token,
|
||||
uint256[] memory tokenIds,
|
||||
uint256[] memory amounts,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
|
||||
/// @notice Batch withdraw a list of ERC1155 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC1155 NFT in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
/// @param amounts The list of corresponding amounts to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function batchWithdrawERC1155(
|
||||
address token,
|
||||
address to,
|
||||
uint256[] memory tokenIds,
|
||||
uint256[] memory amounts,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
/// @notice Batch withdraw a list of ERC1155 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC1155 NFT in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
/// @param amounts The list of corresponding amounts to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function batchWithdrawERC1155(
|
||||
address token,
|
||||
address to,
|
||||
uint256[] memory tokenIds,
|
||||
uint256[] memory amounts,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
|
||||
/// @notice Complete ERC1155 deposit from layer 1 to layer 2 and send NFT to recipient's account in layer 2.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L2ScrollMessenger.
|
||||
/// - The function should also only be called by L1ERC1155Gateway in layer 1.
|
||||
/// @param l1Token The address of corresponding layer 1 token.
|
||||
/// @param l2Token The address of corresponding layer 2 token.
|
||||
/// @param from The address of account who deposits the token in layer 1.
|
||||
/// @param to The address of recipient in layer 2 to receive the token.
|
||||
/// @param tokenId The token id to deposit.
|
||||
/// @param amount The amount of token to deposit.
|
||||
function finalizeDepositERC1155(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 amount
|
||||
) external;
|
||||
/// @notice Complete ERC1155 deposit from layer 1 to layer 2 and send NFT to recipient's account in layer 2.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L2ScrollMessenger.
|
||||
/// - The function should also only be called by L1ERC1155Gateway in layer 1.
|
||||
/// @param l1Token The address of corresponding layer 1 token.
|
||||
/// @param l2Token The address of corresponding layer 2 token.
|
||||
/// @param from The address of account who deposits the token in layer 1.
|
||||
/// @param to The address of recipient in layer 2 to receive the token.
|
||||
/// @param tokenId The token id to deposit.
|
||||
/// @param amount The amount of token to deposit.
|
||||
function finalizeDepositERC1155(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 amount
|
||||
) external;
|
||||
|
||||
/// @notice Complete ERC1155 deposit from layer 1 to layer 2 and send NFT to recipient's account in layer 2.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L2ScrollMessenger.
|
||||
/// - The function should also only be called by L1ERC1155Gateway in layer 1.
|
||||
/// @param l1Token The address of corresponding layer 1 token.
|
||||
/// @param l2Token The address of corresponding layer 2 token.
|
||||
/// @param from The address of account who deposits the token in layer 1.
|
||||
/// @param to The address of recipient in layer 2 to receive the token.
|
||||
/// @param tokenIds The list of token ids to deposit.
|
||||
/// @param amounts The list of corresponding amounts to deposit.
|
||||
function finalizeBatchDepositERC1155(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata tokenIds,
|
||||
uint256[] calldata amounts
|
||||
) external;
|
||||
/// @notice Complete ERC1155 deposit from layer 1 to layer 2 and send NFT to recipient's account in layer 2.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L2ScrollMessenger.
|
||||
/// - The function should also only be called by L1ERC1155Gateway in layer 1.
|
||||
/// @param l1Token The address of corresponding layer 1 token.
|
||||
/// @param l2Token The address of corresponding layer 2 token.
|
||||
/// @param from The address of account who deposits the token in layer 1.
|
||||
/// @param to The address of recipient in layer 2 to receive the token.
|
||||
/// @param tokenIds The list of token ids to deposit.
|
||||
/// @param amounts The list of corresponding amounts to deposit.
|
||||
function finalizeBatchDepositERC1155(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata tokenIds,
|
||||
uint256[] calldata amounts
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -3,113 +3,113 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IL2ERC20Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when ERC20 token is deposited from L1 to L2 and transfer to recipient.
|
||||
/// @param l1Token The address of the token in L1.
|
||||
/// @param l2Token The address of the token in L2.
|
||||
/// @param from The address of sender in L1.
|
||||
/// @param to The address of recipient in L2.
|
||||
/// @param amount The amount of token withdrawn from L1 to L2.
|
||||
/// @param data The optional calldata passed to recipient in L2.
|
||||
event FinalizeDepositERC20(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
/// @notice Emitted when ERC20 token is deposited from L1 to L2 and transfer to recipient.
|
||||
/// @param l1Token The address of the token in L1.
|
||||
/// @param l2Token The address of the token in L2.
|
||||
/// @param from The address of sender in L1.
|
||||
/// @param to The address of recipient in L2.
|
||||
/// @param amount The amount of token withdrawn from L1 to L2.
|
||||
/// @param data The optional calldata passed to recipient in L2.
|
||||
event FinalizeDepositERC20(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/// @notice Emitted when someone withdraw ERC20 token from L2 to L1.
|
||||
/// @param l1Token The address of the token in L1.
|
||||
/// @param l2Token The address of the token in L2.
|
||||
/// @param from The address of sender in L2.
|
||||
/// @param to The address of recipient in L1.
|
||||
/// @param amount The amount of token will be deposited from L2 to L1.
|
||||
/// @param data The optional calldata passed to recipient in L1.
|
||||
event WithdrawERC20(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
/// @notice Emitted when someone withdraw ERC20 token from L2 to L1.
|
||||
/// @param l1Token The address of the token in L1.
|
||||
/// @param l2Token The address of the token in L2.
|
||||
/// @param from The address of sender in L2.
|
||||
/// @param to The address of recipient in L1.
|
||||
/// @param amount The amount of token will be deposited from L2 to L1.
|
||||
/// @param data The optional calldata passed to recipient in L1.
|
||||
event WithdrawERC20(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Return the corresponding l1 token address given l2 token address.
|
||||
/// @param l2Token The address of l2 token.
|
||||
function getL1ERC20Address(address l2Token) external view returns (address);
|
||||
/// @notice Return the corresponding l1 token address given l2 token address.
|
||||
/// @param l2Token The address of l2 token.
|
||||
function getL1ERC20Address(address l2Token) external view returns (address);
|
||||
|
||||
/// @notice Return the corresponding l2 token address given l1 token address.
|
||||
/// @param l1Token The address of l1 token.
|
||||
function getL2ERC20Address(address l1Token) external view returns (address);
|
||||
/// @notice Return the corresponding l2 token address given l1 token address.
|
||||
/// @param l1Token The address of l1 token.
|
||||
function getL2ERC20Address(address l1Token) external view returns (address);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Withdraw of some token to a caller's account on L1.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param token The address of token in L2.
|
||||
/// @param amount The amount of token to transfer.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC20(
|
||||
address token,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
/// @notice Withdraw of some token to a caller's account on L1.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param token The address of token in L2.
|
||||
/// @param amount The amount of token to transfer.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC20(
|
||||
address token,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Withdraw of some token to a recipient's account on L1.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param token The address of token in L2.
|
||||
/// @param to The address of recipient's account on L1.
|
||||
/// @param amount The amount of token to transfer.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC20(
|
||||
address token,
|
||||
address to,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
/// @notice Withdraw of some token to a recipient's account on L1.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param token The address of token in L2.
|
||||
/// @param to The address of recipient's account on L1.
|
||||
/// @param amount The amount of token to transfer.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC20(
|
||||
address token,
|
||||
address to,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Withdraw of some token to a recipient's account on L1 and call.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param token The address of token in L2.
|
||||
/// @param to The address of recipient's account on L1.
|
||||
/// @param amount The amount of token to transfer.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC20AndCall(
|
||||
address token,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
/// @notice Withdraw of some token to a recipient's account on L1 and call.
|
||||
/// @dev Make this function payable to send relayer fee in Ether.
|
||||
/// @param token The address of token in L2.
|
||||
/// @param to The address of recipient's account on L1.
|
||||
/// @param amount The amount of token to transfer.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC20AndCall(
|
||||
address token,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Complete a deposit from L1 to L2 and send fund to recipient's account in L2.
|
||||
/// @dev Make this function payable to handle WETH deposit/withdraw.
|
||||
/// The function should only be called by L2ScrollMessenger.
|
||||
/// The function should also only be called by L1ERC20Gateway in L1.
|
||||
/// @param l1Token The address of corresponding L1 token.
|
||||
/// @param l2Token The address of corresponding L2 token.
|
||||
/// @param from The address of account who deposits the token in L1.
|
||||
/// @param to The address of recipient in L2 to receive the token.
|
||||
/// @param amount The amount of the token to deposit.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
function finalizeDepositERC20(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data
|
||||
) external payable;
|
||||
/// @notice Complete a deposit from L1 to L2 and send fund to recipient's account in L2.
|
||||
/// @dev Make this function payable to handle WETH deposit/withdraw.
|
||||
/// The function should only be called by L2ScrollMessenger.
|
||||
/// The function should also only be called by L1ERC20Gateway in L1.
|
||||
/// @param l1Token The address of corresponding L1 token.
|
||||
/// @param l2Token The address of corresponding L2 token.
|
||||
/// @param from The address of account who deposits the token in L1.
|
||||
/// @param to The address of recipient in L2 to receive the token.
|
||||
/// @param amount The amount of the token to deposit.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
function finalizeDepositERC20(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data
|
||||
) external payable;
|
||||
}
|
||||
|
||||
@@ -4,145 +4,145 @@ pragma solidity ^0.8.0;
|
||||
|
||||
/// @title The interface for the ERC721 cross chain gateway in layer 2.
|
||||
interface IL2ERC721Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when the ERC721 NFT is transfered to recipient in layer 2.
|
||||
/// @param l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 1.
|
||||
/// @param to The address of recipient in layer 2.
|
||||
/// @param tokenId The token id of the ERC721 NFT deposited in layer 1.
|
||||
event FinalizeDepositERC721(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 tokenId
|
||||
);
|
||||
/// @notice Emitted when the ERC721 NFT is transfered to recipient in layer 2.
|
||||
/// @param l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 1.
|
||||
/// @param to The address of recipient in layer 2.
|
||||
/// @param tokenId The token id of the ERC721 NFT deposited in layer 1.
|
||||
event FinalizeDepositERC721(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 tokenId
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC721 NFT is batch transfered to recipient in layer 2.
|
||||
/// @param l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 1.
|
||||
/// @param to The address of recipient in layer 2.
|
||||
/// @param tokenIds The list of token ids of the ERC721 NFT deposited in layer 1.
|
||||
event FinalizeBatchDepositERC721(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256[] tokenIds
|
||||
);
|
||||
/// @notice Emitted when the ERC721 NFT is batch transfered to recipient in layer 2.
|
||||
/// @param l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 1.
|
||||
/// @param to The address of recipient in layer 2.
|
||||
/// @param tokenIds The list of token ids of the ERC721 NFT deposited in layer 1.
|
||||
event FinalizeBatchDepositERC721(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256[] tokenIds
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC721 NFT is transfered to gateway in layer 2.
|
||||
/// @param l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenId The token id of the ERC721 NFT to withdraw in layer 2.
|
||||
event WithdrawERC721(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 tokenId
|
||||
);
|
||||
/// @notice Emitted when the ERC721 NFT is transfered to gateway in layer 2.
|
||||
/// @param l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenId The token id of the ERC721 NFT to withdraw in layer 2.
|
||||
event WithdrawERC721(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256 tokenId
|
||||
);
|
||||
|
||||
/// @notice Emitted when the ERC721 NFT is batch transfered to gateway in layer 2.
|
||||
/// @param l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenIds The list of token ids of the ERC721 NFT to withdraw in layer 2.
|
||||
event BatchWithdrawERC721(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256[] tokenIds
|
||||
);
|
||||
/// @notice Emitted when the ERC721 NFT is batch transfered to gateway in layer 2.
|
||||
/// @param l1Token The address of ERC721 NFT in layer 1.
|
||||
/// @param l2Token The address of ERC721 NFT in layer 2.
|
||||
/// @param from The address of sender in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenIds The list of token ids of the ERC721 NFT to withdraw in layer 2.
|
||||
event BatchWithdrawERC721(
|
||||
address indexed l1Token,
|
||||
address indexed l2Token,
|
||||
address indexed from,
|
||||
address to,
|
||||
uint256[] tokenIds
|
||||
);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Withdraw some ERC721 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC721 NFT in layer 2.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC721(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
/// @notice Withdraw some ERC721 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC721 NFT in layer 2.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC721(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
|
||||
/// @notice Withdraw some ERC721 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC721 NFT in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC721(
|
||||
address token,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
/// @notice Withdraw some ERC721 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC721 NFT in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function withdrawERC721(
|
||||
address token,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
|
||||
/// @notice Batch withdraw a list of ERC721 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC721 NFT in layer 2.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function batchWithdrawERC721(
|
||||
address token,
|
||||
uint256[] memory tokenIds,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
/// @notice Batch withdraw a list of ERC721 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC721 NFT in layer 2.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function batchWithdrawERC721(
|
||||
address token,
|
||||
uint256[] memory tokenIds,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
|
||||
/// @notice Batch withdraw a list of ERC721 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC721 NFT in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function batchWithdrawERC721(
|
||||
address token,
|
||||
address to,
|
||||
uint256[] memory tokenIds,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
/// @notice Batch withdraw a list of ERC721 NFT to caller's account on layer 1.
|
||||
/// @param token The address of ERC721 NFT in layer 2.
|
||||
/// @param to The address of recipient in layer 1.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
/// @param gasLimit Unused, but included for potential forward compatibility considerations.
|
||||
function batchWithdrawERC721(
|
||||
address token,
|
||||
address to,
|
||||
uint256[] memory tokenIds,
|
||||
uint256 gasLimit
|
||||
) external;
|
||||
|
||||
/// @notice Complete ERC721 deposit from layer 1 to layer 2 and send NFT to recipient's account in layer 2.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L2ScrollMessenger.
|
||||
/// - The function should also only be called by L1ERC721Gateway in layer 1.
|
||||
/// @param l1Token The address of corresponding layer 1 token.
|
||||
/// @param l2Token The address of corresponding layer 2 token.
|
||||
/// @param from The address of account who withdraw the token in layer 1.
|
||||
/// @param to The address of recipient in layer 2 to receive the token.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
function finalizeDepositERC721(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 tokenId
|
||||
) external;
|
||||
/// @notice Complete ERC721 deposit from layer 1 to layer 2 and send NFT to recipient's account in layer 2.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L2ScrollMessenger.
|
||||
/// - The function should also only be called by L1ERC721Gateway in layer 1.
|
||||
/// @param l1Token The address of corresponding layer 1 token.
|
||||
/// @param l2Token The address of corresponding layer 2 token.
|
||||
/// @param from The address of account who withdraw the token in layer 1.
|
||||
/// @param to The address of recipient in layer 2 to receive the token.
|
||||
/// @param tokenId The token id to withdraw.
|
||||
function finalizeDepositERC721(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 tokenId
|
||||
) external;
|
||||
|
||||
/// @notice Complete ERC721 deposit from layer 1 to layer 2 and send NFT to recipient's account in layer 2.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L2ScrollMessenger.
|
||||
/// - The function should also only be called by L1ERC721Gateway in layer 1.
|
||||
/// @param l1Token The address of corresponding layer 1 token.
|
||||
/// @param l2Token The address of corresponding layer 2 token.
|
||||
/// @param from The address of account who withdraw the token in layer 1.
|
||||
/// @param to The address of recipient in layer 2 to receive the token.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
function finalizeBatchDepositERC721(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata tokenIds
|
||||
) external;
|
||||
/// @notice Complete ERC721 deposit from layer 1 to layer 2 and send NFT to recipient's account in layer 2.
|
||||
/// @dev Requirements:
|
||||
/// - The function should only be called by L2ScrollMessenger.
|
||||
/// - The function should also only be called by L1ERC721Gateway in layer 1.
|
||||
/// @param l1Token The address of corresponding layer 1 token.
|
||||
/// @param l2Token The address of corresponding layer 2 token.
|
||||
/// @param from The address of account who withdraw the token in layer 1.
|
||||
/// @param to The address of recipient in layer 2 to receive the token.
|
||||
/// @param tokenIds The list of token ids to withdraw.
|
||||
function finalizeBatchDepositERC721(
|
||||
address l1Token,
|
||||
address l2Token,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata tokenIds
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -3,66 +3,66 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IL2ETHGateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when someone withdraw ETH from L2 to L1.
|
||||
/// @param from The address of sender in L2.
|
||||
/// @param to The address of recipient in L1.
|
||||
/// @param amount The amount of ETH will be deposited from L2 to L1.
|
||||
/// @param data The optional calldata passed to recipient in L1.
|
||||
event WithdrawETH(address indexed from, address indexed to, uint256 amount, bytes data);
|
||||
/// @notice Emitted when someone withdraw ETH from L2 to L1.
|
||||
/// @param from The address of sender in L2.
|
||||
/// @param to The address of recipient in L1.
|
||||
/// @param amount The amount of ETH will be deposited from L2 to L1.
|
||||
/// @param data The optional calldata passed to recipient in L1.
|
||||
event WithdrawETH(address indexed from, address indexed to, uint256 amount, bytes data);
|
||||
|
||||
/// @notice Emitted when ETH is deposited from L1 to L2 and transfer to recipient.
|
||||
/// @param from The address of sender in L1.
|
||||
/// @param to The address of recipient in L2.
|
||||
/// @param amount The amount of ETH deposited from L1 to L2.
|
||||
/// @param data The optional calldata passed to recipient in L2.
|
||||
event FinalizeDepositETH(address indexed from, address indexed to, uint256 amount, bytes data);
|
||||
/// @notice Emitted when ETH is deposited from L1 to L2 and transfer to recipient.
|
||||
/// @param from The address of sender in L1.
|
||||
/// @param to The address of recipient in L2.
|
||||
/// @param amount The amount of ETH deposited from L1 to L2.
|
||||
/// @param data The optional calldata passed to recipient in L2.
|
||||
event FinalizeDepositETH(address indexed from, address indexed to, uint256 amount, bytes data);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Withdraw ETH to caller's account in L1.
|
||||
/// @param amount The amount of ETH to be withdrawn.
|
||||
/// @param gasLimit Optional, gas limit used to complete the withdraw on L1.
|
||||
function withdrawETH(uint256 amount, uint256 gasLimit) external payable;
|
||||
/// @notice Withdraw ETH to caller's account in L1.
|
||||
/// @param amount The amount of ETH to be withdrawn.
|
||||
/// @param gasLimit Optional, gas limit used to complete the withdraw on L1.
|
||||
function withdrawETH(uint256 amount, uint256 gasLimit) external payable;
|
||||
|
||||
/// @notice Withdraw ETH to caller's account in L1.
|
||||
/// @param to The address of recipient's account on L1.
|
||||
/// @param amount The amount of ETH to be withdrawn.
|
||||
/// @param gasLimit Optional, gas limit used to complete the withdraw on L1.
|
||||
function withdrawETH(
|
||||
address to,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
/// @notice Withdraw ETH to caller's account in L1.
|
||||
/// @param to The address of recipient's account on L1.
|
||||
/// @param amount The amount of ETH to be withdrawn.
|
||||
/// @param gasLimit Optional, gas limit used to complete the withdraw on L1.
|
||||
function withdrawETH(
|
||||
address to,
|
||||
uint256 amount,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Withdraw ETH to caller's account in L1.
|
||||
/// @param to The address of recipient's account on L1.
|
||||
/// @param amount The amount of ETH to be withdrawn.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
/// @param gasLimit Optional, gas limit used to complete the withdraw on L1.
|
||||
function withdrawETHAndCall(
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
/// @notice Withdraw ETH to caller's account in L1.
|
||||
/// @param to The address of recipient's account on L1.
|
||||
/// @param amount The amount of ETH to be withdrawn.
|
||||
/// @param data Optional data to forward to recipient's account.
|
||||
/// @param gasLimit Optional, gas limit used to complete the withdraw on L1.
|
||||
function withdrawETHAndCall(
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata data,
|
||||
uint256 gasLimit
|
||||
) external payable;
|
||||
|
||||
/// @notice Complete ETH deposit from L1 to L2 and send fund to recipient's account in L2.
|
||||
/// @dev This function should only be called by L2ScrollMessenger.
|
||||
/// This function should also only be called by L1GatewayRouter in L1.
|
||||
/// @param _from The address of account who deposit ETH in L1.
|
||||
/// @param _to The address of recipient in L2 to receive ETH.
|
||||
/// @param _amount The amount of ETH to deposit.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
function finalizeDepositETH(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable;
|
||||
/// @notice Complete ETH deposit from L1 to L2 and send fund to recipient's account in L2.
|
||||
/// @dev This function should only be called by L2ScrollMessenger.
|
||||
/// This function should also only be called by L1GatewayRouter in L1.
|
||||
/// @param _from The address of account who deposit ETH in L1.
|
||||
/// @param _to The address of recipient in L2 to receive ETH.
|
||||
/// @param _amount The amount of ETH to deposit.
|
||||
/// @param _data Optional data to forward to recipient's account.
|
||||
function finalizeDepositETH(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable;
|
||||
}
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { IL2ETHGateway } from "./IL2ETHGateway.sol";
|
||||
import { IL2ERC20Gateway } from "./IL2ERC20Gateway.sol";
|
||||
import {IL2ETHGateway} from "./IL2ETHGateway.sol";
|
||||
import {IL2ERC20Gateway} from "./IL2ERC20Gateway.sol";
|
||||
|
||||
interface IL2GatewayRouter is IL2ETHGateway, IL2ERC20Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when the address of ETH Gateway is updated.
|
||||
/// @param ethGateway The address of new ETH Gateway.
|
||||
event SetETHGateway(address indexed ethGateway);
|
||||
/// @notice Emitted when the address of ETH Gateway is updated.
|
||||
/// @param ethGateway The address of new ETH Gateway.
|
||||
event SetETHGateway(address indexed ethGateway);
|
||||
|
||||
/// @notice Emitted when the address of default ERC20 Gateway is updated.
|
||||
/// @param defaultERC20Gateway The address of new default ERC20 Gateway.
|
||||
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway);
|
||||
/// @notice Emitted when the address of default ERC20 Gateway is updated.
|
||||
/// @param defaultERC20Gateway The address of new default ERC20 Gateway.
|
||||
event SetDefaultERC20Gateway(address indexed defaultERC20Gateway);
|
||||
|
||||
/// @notice Emitted when the `gateway` for `token` is updated.
|
||||
/// @param token The address of token updated.
|
||||
/// @param gateway The corresponding address of gateway updated.
|
||||
event SetERC20Gateway(address indexed token, address indexed gateway);
|
||||
/// @notice Emitted when the `gateway` for `token` is updated.
|
||||
/// @param token The address of token updated.
|
||||
/// @param gateway The corresponding address of gateway updated.
|
||||
event SetERC20Gateway(address indexed token, address indexed gateway);
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
||||
|
||||
import { IL2ERC20Gateway, L2ERC20Gateway } from "./L2ERC20Gateway.sol";
|
||||
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
|
||||
import { IL1ERC20Gateway } from "../../L1/gateways/IL1ERC20Gateway.sol";
|
||||
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20.sol";
|
||||
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
|
||||
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
|
||||
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
|
||||
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {IScrollStandardERC20} from "../../libraries/token/IScrollStandardERC20.sol";
|
||||
|
||||
/// @title L2ERC20Gateway
|
||||
/// @notice The `L2ERC20Gateway` is used to withdraw custom ERC20 compatible tokens in layer 2 and
|
||||
@@ -17,130 +17,130 @@ import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20
|
||||
/// @dev The withdrawn tokens tokens will be burned directly. On finalizing deposit, the corresponding
|
||||
/// tokens will be minted and transfered to the recipient.
|
||||
contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when token mapping for ERC20 token is updated.
|
||||
/// @param _l2Token The address of corresponding ERC20 token in layer 2.
|
||||
/// @param _l1Token The address of ERC20 token in layer 1.
|
||||
event UpdateTokenMapping(address _l2Token, address _l1Token);
|
||||
/// @notice Emitted when token mapping for ERC20 token is updated.
|
||||
/// @param _l2Token The address of corresponding ERC20 token in layer 2.
|
||||
/// @param _l1Token The address of ERC20 token in layer 1.
|
||||
event UpdateTokenMapping(address _l2Token, address _l1Token);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from layer 2 token address to layer 1 token address for ERC20 token.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public tokenMapping;
|
||||
/// @notice Mapping from layer 2 token address to layer 1 token address for ERC20 token.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public tokenMapping;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL1ERC20Address(address _l2Token) external view override returns (address) {
|
||||
return tokenMapping[_l2Token];
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL2ERC20Address(address) public pure override returns (address) {
|
||||
revert("unimplemented");
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function finalizeDepositERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(msg.value == 0, "nonzero msg.value");
|
||||
require(_l1Token == tokenMapping[_l2Token], "l1 token mismatch");
|
||||
|
||||
// @todo forward `_callData` to `_to` using transferAndCall in the near future
|
||||
|
||||
IScrollStandardERC20(_l2Token).mint(_to, _amount);
|
||||
|
||||
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 1 token mapping.
|
||||
/// @param _l2Token The address of corresponding ERC20 token in layer 2.
|
||||
/// @param _l1Token The address of ERC20 token in layer 1.
|
||||
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
|
||||
require(_l1Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l2Token] = _l1Token;
|
||||
|
||||
emit UpdateTokenMapping(_l2Token, _l1Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L2ERC20Gateway
|
||||
function _withdraw(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override {
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
|
||||
// 1. Extract real sender if this call is from L2GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
// 2. Burn token.
|
||||
IScrollStandardERC20(_token).burn(_from, _amount);
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
// 3. Generate message passed to L1StandardERC20Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL1ERC20Address(address _l2Token) external view override returns (address) {
|
||||
return tokenMapping[_l2Token];
|
||||
}
|
||||
|
||||
// 4. send message to L2ScrollMessenger
|
||||
IL2ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, 0, _message, _gasLimit);
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL2ERC20Address(address) public pure override returns (address) {
|
||||
revert("unimplemented");
|
||||
}
|
||||
|
||||
emit WithdrawERC20(_l1Token, _token, _from, _to, _amount, _data);
|
||||
}
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function finalizeDepositERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(msg.value == 0, "nonzero msg.value");
|
||||
require(_l1Token == tokenMapping[_l2Token], "l1 token mismatch");
|
||||
|
||||
// @todo forward `_callData` to `_to` using transferAndCall in the near future
|
||||
|
||||
IScrollStandardERC20(_l2Token).mint(_to, _amount);
|
||||
|
||||
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 1 token mapping.
|
||||
/// @param _l2Token The address of corresponding ERC20 token in layer 2.
|
||||
/// @param _l1Token The address of ERC20 token in layer 1.
|
||||
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
|
||||
require(_l1Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l2Token] = _l1Token;
|
||||
|
||||
emit UpdateTokenMapping(_l2Token, _l1Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L2ERC20Gateway
|
||||
function _withdraw(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override {
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
|
||||
// 1. Extract real sender if this call is from L2GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// 2. Burn token.
|
||||
IScrollStandardERC20(_token).burn(_from, _amount);
|
||||
|
||||
// 3. Generate message passed to L1StandardERC20Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
|
||||
// 4. send message to L2ScrollMessenger
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit WithdrawERC20(_l1Token, _token, _from, _to, _amount, _data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import { IERC1155Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
|
||||
import { ERC1155HolderUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {IERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
|
||||
import {ERC1155HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
|
||||
|
||||
import { IL2ERC1155Gateway } from "./IL2ERC1155Gateway.sol";
|
||||
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
|
||||
import { IL1ERC1155Gateway } from "../../L1/gateways/IL1ERC1155Gateway.sol";
|
||||
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import { IScrollERC1155 } from "../../libraries/token/IScrollERC1155.sol";
|
||||
import {IL2ERC1155Gateway} from "./IL2ERC1155Gateway.sol";
|
||||
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
|
||||
import {IL1ERC1155Gateway} from "../../L1/gateways/IL1ERC1155Gateway.sol";
|
||||
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {IScrollERC1155} from "../../libraries/token/IScrollERC1155.sol";
|
||||
|
||||
/// @title L2ERC1155Gateway
|
||||
/// @notice The `L2ERC1155Gateway` is used to withdraw ERC1155 compatible NFTs in layer 2 and
|
||||
@@ -21,203 +21,203 @@ import { IScrollERC1155 } from "../../libraries/token/IScrollERC1155.sol";
|
||||
/// This will be changed if we have more specific scenarios.
|
||||
// @todo Current implementation doesn't support calling from `L2GatewayRouter`.
|
||||
contract L2ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC1155Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when token mapping for ERC1155 token is updated.
|
||||
/// @param _l1Token The address of corresponding ERC1155 token in layer 2.
|
||||
/// @param _l1Token The address of ERC1155 token in layer 1.
|
||||
event UpdateTokenMapping(address _l2Token, address _l1Token);
|
||||
/// @notice Emitted when token mapping for ERC1155 token is updated.
|
||||
/// @param _l1Token The address of corresponding ERC1155 token in layer 2.
|
||||
/// @param _l1Token The address of ERC1155 token in layer 1.
|
||||
event UpdateTokenMapping(address _l2Token, address _l1Token);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from layer 2 token address to layer 1 token address for ERC1155 NFT.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public tokenMapping;
|
||||
/// @notice Mapping from layer 2 token address to layer 1 token address for ERC1155 NFT.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public tokenMapping;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
function initialize(address _counterpart, address _messenger) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function withdrawERC1155(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_withdrawERC1155(_token, msg.sender, _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function withdrawERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_withdrawERC1155(_token, _to, _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function batchWithdrawERC1155(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_batchWithdrawERC1155(_token, msg.sender, _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function batchWithdrawERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_batchWithdrawERC1155(_token, _to, _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function finalizeDepositERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
IScrollERC1155(_l2Token).mint(_to, _tokenId, _amount, "");
|
||||
|
||||
emit FinalizeDepositERC1155(_l1Token, _l2Token, _from, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function finalizeBatchDepositERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
IScrollERC1155(_l2Token).batchMint(_to, _tokenIds, _amounts, "");
|
||||
|
||||
emit FinalizeBatchDepositERC1155(_l1Token, _l2Token, _from, _to, _tokenIds, _amounts);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 1 token mapping.
|
||||
/// @param _l1Token The address of corresponding ERC1155 token in layer 2.
|
||||
/// @param _l1Token The address of ERC1155 token in layer 1.
|
||||
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
|
||||
require(_l1Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l2Token] = _l1Token;
|
||||
|
||||
emit UpdateTokenMapping(_l2Token, _l1Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to withdraw ERC1155 NFT to layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to withdraw.
|
||||
/// @param _amount The amount of token to withdraw.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the withdraw on layer 2.
|
||||
function _withdrawERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "token not supported");
|
||||
|
||||
// 1. burn token
|
||||
IScrollERC1155(_token).burn(msg.sender, _tokenId, _amount);
|
||||
|
||||
// 2. Generate message passed to L1ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC1155Gateway.finalizeWithdrawERC1155.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenId,
|
||||
_amount
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage(counterpart, msg.value, _message, _gasLimit);
|
||||
|
||||
emit WithdrawERC1155(_l1Token, _token, msg.sender, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch withdraw ERC1155 NFT to layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to withdraw.
|
||||
/// @param _amounts The list of corresponding number of token to withdraw.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the withdraw on layer 1.
|
||||
function _batchWithdrawERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_tokenIds.length > 0, "no token to withdraw");
|
||||
require(_tokenIds.length == _amounts.length, "length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _amounts.length; i++) {
|
||||
require(_amounts[i] > 0, "withdraw zero amount");
|
||||
function initialize(address _counterpart, address _messenger) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
|
||||
}
|
||||
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "token not supported");
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IScrollERC1155(_token).batchBurn(msg.sender, _tokenIds, _amounts);
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function withdrawERC1155(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_withdrawERC1155(_token, msg.sender, _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L1ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC1155Gateway.finalizeBatchWithdrawERC1155.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenIds,
|
||||
_amounts
|
||||
);
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function withdrawERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_withdrawERC1155(_token, _to, _tokenId, _amount, _gasLimit);
|
||||
}
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, msg.value, _message, _gasLimit);
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function batchWithdrawERC1155(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_batchWithdrawERC1155(_token, msg.sender, _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
emit BatchWithdrawERC1155(_l1Token, _token, msg.sender, _to, _tokenIds, _amounts);
|
||||
}
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function batchWithdrawERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_batchWithdrawERC1155(_token, _to, _tokenIds, _amounts, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function finalizeDepositERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
IScrollERC1155(_l2Token).mint(_to, _tokenId, _amount, "");
|
||||
|
||||
emit FinalizeDepositERC1155(_l1Token, _l2Token, _from, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC1155Gateway
|
||||
function finalizeBatchDepositERC1155(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
IScrollERC1155(_l2Token).batchMint(_to, _tokenIds, _amounts, "");
|
||||
|
||||
emit FinalizeBatchDepositERC1155(_l1Token, _l2Token, _from, _to, _tokenIds, _amounts);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 1 token mapping.
|
||||
/// @param _l1Token The address of corresponding ERC1155 token in layer 2.
|
||||
/// @param _l1Token The address of ERC1155 token in layer 1.
|
||||
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
|
||||
require(_l1Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l2Token] = _l1Token;
|
||||
|
||||
emit UpdateTokenMapping(_l2Token, _l1Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to withdraw ERC1155 NFT to layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenId The token id to withdraw.
|
||||
/// @param _amount The amount of token to withdraw.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the withdraw on layer 2.
|
||||
function _withdrawERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "token not supported");
|
||||
|
||||
// 1. burn token
|
||||
IScrollERC1155(_token).burn(msg.sender, _tokenId, _amount);
|
||||
|
||||
// 2. Generate message passed to L1ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC1155Gateway.finalizeWithdrawERC1155.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenId,
|
||||
_amount
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage(counterpart, msg.value, _message, _gasLimit);
|
||||
|
||||
emit WithdrawERC1155(_l1Token, _token, msg.sender, _to, _tokenId, _amount);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch withdraw ERC1155 NFT to layer 2.
|
||||
/// @param _token The address of ERC1155 NFT in layer 1.
|
||||
/// @param _to The address of recipient in layer 2.
|
||||
/// @param _tokenIds The list of token ids to withdraw.
|
||||
/// @param _amounts The list of corresponding number of token to withdraw.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the withdraw on layer 1.
|
||||
function _batchWithdrawERC1155(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256[] calldata _amounts,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_tokenIds.length > 0, "no token to withdraw");
|
||||
require(_tokenIds.length == _amounts.length, "length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _amounts.length; i++) {
|
||||
require(_amounts[i] > 0, "withdraw zero amount");
|
||||
}
|
||||
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
IScrollERC1155(_token).batchBurn(msg.sender, _tokenIds, _amounts);
|
||||
|
||||
// 2. Generate message passed to L1ERC1155Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC1155Gateway.finalizeBatchWithdrawERC1155.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenIds,
|
||||
_amounts
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, msg.value, _message, _gasLimit);
|
||||
|
||||
emit BatchWithdrawERC1155(_l1Token, _token, msg.sender, _to, _tokenIds, _amounts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,54 +2,54 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { IL2ERC20Gateway } from "./IL2ERC20Gateway.sol";
|
||||
import {IL2ERC20Gateway} from "./IL2ERC20Gateway.sol";
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
|
||||
abstract contract L2ERC20Gateway is IL2ERC20Gateway {
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdraw(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdraw(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdraw(_token, _to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdraw(_token, _to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdraw(_token, _to, _amount, _data, _gasLimit);
|
||||
}
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
_withdraw(_token, _to, _amount, _data, _gasLimit);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
function _withdraw(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual;
|
||||
function _withdraw(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import { IERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
|
||||
import { ERC721HolderUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
|
||||
import {ERC721HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
|
||||
|
||||
import { IL2ERC721Gateway } from "./IL2ERC721Gateway.sol";
|
||||
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
|
||||
import { IL1ERC721Gateway } from "../../L1/gateways/IL1ERC721Gateway.sol";
|
||||
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import { IScrollERC721 } from "../../libraries/token/IScrollERC721.sol";
|
||||
import {IL2ERC721Gateway} from "./IL2ERC721Gateway.sol";
|
||||
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
|
||||
import {IL1ERC721Gateway} from "../../L1/gateways/IL1ERC721Gateway.sol";
|
||||
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {IScrollERC721} from "../../libraries/token/IScrollERC721.sol";
|
||||
|
||||
/// @title L2ERC721Gateway
|
||||
/// @notice The `L2ERC721Gateway` is used to withdraw ERC721 compatible NFTs in layer 2 and
|
||||
@@ -21,192 +21,192 @@ import { IScrollERC721 } from "../../libraries/token/IScrollERC721.sol";
|
||||
/// This will be changed if we have more specific scenarios.
|
||||
// @todo Current implementation doesn't support calling from `L2GatewayRouter`.
|
||||
contract L2ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC721Gateway {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when token mapping for ERC721 token is updated.
|
||||
/// @param _l1Token The address of corresponding ERC721 token in layer 2.
|
||||
/// @param _l1Token The address of ERC721 token in layer 1.
|
||||
event UpdateTokenMapping(address _l2Token, address _l1Token);
|
||||
/// @notice Emitted when token mapping for ERC721 token is updated.
|
||||
/// @param _l1Token The address of corresponding ERC721 token in layer 2.
|
||||
/// @param _l1Token The address of ERC721 token in layer 1.
|
||||
event UpdateTokenMapping(address _l2Token, address _l1Token);
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from layer 2 token address to layer 1 token address for ERC721 NFT.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public tokenMapping;
|
||||
/// @notice Mapping from layer 2 token address to layer 1 token address for ERC721 NFT.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public tokenMapping;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
function initialize(address _counterpart, address _messenger) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function withdrawERC721(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_withdrawERC721(_token, msg.sender, _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function withdrawERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_withdrawERC721(_token, _to, _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function batchWithdrawERC721(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_batchWithdrawERC721(_token, msg.sender, _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function batchWithdrawERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_batchWithdrawERC721(_token, _to, _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function finalizeDepositERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
IScrollERC721(_l2Token).mint(_to, _tokenId);
|
||||
|
||||
emit FinalizeDepositERC721(_l1Token, _l2Token, _from, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function finalizeBatchDepositERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
IScrollERC721(_l2Token).mint(_to, _tokenIds[i]);
|
||||
function initialize(address _counterpart, address _messenger) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);
|
||||
}
|
||||
|
||||
emit FinalizeBatchDepositERC721(_l1Token, _l2Token, _from, _to, _tokenIds);
|
||||
}
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 1 token mapping.
|
||||
/// @param _l1Token The address of corresponding ERC721 token in layer 2.
|
||||
/// @param _l1Token The address of ERC721 token in layer 1.
|
||||
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
|
||||
require(_l1Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l2Token] = _l1Token;
|
||||
|
||||
emit UpdateTokenMapping(_l2Token, _l1Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to withdraw ERC721 NFT to layer 1.
|
||||
/// @param _token The address of ERC721 NFT in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenId The token id to withdraw.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the withdraw on layer 1.
|
||||
function _withdrawERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "token not supported");
|
||||
|
||||
// 1. burn token
|
||||
// @note in case the token has given too much power to the gateway, we check owner here.
|
||||
require(IScrollERC721(_token).ownerOf(_tokenId) == msg.sender, "token not owned");
|
||||
IScrollERC721(_token).burn(_tokenId);
|
||||
|
||||
// 2. Generate message passed to L1ERC721Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC721Gateway.finalizeWithdrawERC721.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenId
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage(counterpart, msg.value, _message, _gasLimit);
|
||||
|
||||
emit WithdrawERC721(_l1Token, _token, msg.sender, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch withdraw ERC721 NFT to layer 1.
|
||||
/// @param _token The address of ERC721 NFT in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenIds The list of token ids to withdraw.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the withdraw on layer 1.
|
||||
function _batchWithdrawERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_tokenIds.length > 0, "no token to withdraw");
|
||||
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
// @note in case the token has given too much power to the gateway, we check owner here.
|
||||
require(IScrollERC721(_token).ownerOf(_tokenIds[i]) == msg.sender, "token not owned");
|
||||
IScrollERC721(_token).burn(_tokenIds[i]);
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function withdrawERC721(
|
||||
address _token,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_withdrawERC721(_token, msg.sender, _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L1ERC721Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC721Gateway.finalizeBatchWithdrawERC721.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenIds
|
||||
);
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function withdrawERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_withdrawERC721(_token, _to, _tokenId, _gasLimit);
|
||||
}
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, msg.value, _message, _gasLimit);
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function batchWithdrawERC721(
|
||||
address _token,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_batchWithdrawERC721(_token, msg.sender, _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
emit BatchWithdrawERC721(_l1Token, _token, msg.sender, _to, _tokenIds);
|
||||
}
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function batchWithdrawERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) external override {
|
||||
_batchWithdrawERC721(_token, _to, _tokenIds, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function finalizeDepositERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _tokenId
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
IScrollERC721(_l2Token).mint(_to, _tokenId);
|
||||
|
||||
emit FinalizeDepositERC721(_l1Token, _l2Token, _from, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC721Gateway
|
||||
function finalizeBatchDepositERC721(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds
|
||||
) external override nonReentrant onlyCallByCounterpart {
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
IScrollERC721(_l2Token).mint(_to, _tokenIds[i]);
|
||||
}
|
||||
|
||||
emit FinalizeBatchDepositERC721(_l1Token, _l2Token, _from, _to, _tokenIds);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update layer 2 to layer 1 token mapping.
|
||||
/// @param _l1Token The address of corresponding ERC721 token in layer 2.
|
||||
/// @param _l1Token The address of ERC721 token in layer 1.
|
||||
function updateTokenMapping(address _l2Token, address _l1Token) external onlyOwner {
|
||||
require(_l1Token != address(0), "map to zero address");
|
||||
|
||||
tokenMapping[_l2Token] = _l1Token;
|
||||
|
||||
emit UpdateTokenMapping(_l2Token, _l1Token);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @dev Internal function to withdraw ERC721 NFT to layer 1.
|
||||
/// @param _token The address of ERC721 NFT in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenId The token id to withdraw.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the withdraw on layer 1.
|
||||
function _withdrawERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _tokenId,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "token not supported");
|
||||
|
||||
// 1. burn token
|
||||
// @note in case the token has given too much power to the gateway, we check owner here.
|
||||
require(IScrollERC721(_token).ownerOf(_tokenId) == msg.sender, "token not owned");
|
||||
IScrollERC721(_token).burn(_tokenId);
|
||||
|
||||
// 2. Generate message passed to L1ERC721Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC721Gateway.finalizeWithdrawERC721.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenId
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage(counterpart, msg.value, _message, _gasLimit);
|
||||
|
||||
emit WithdrawERC721(_l1Token, _token, msg.sender, _to, _tokenId);
|
||||
}
|
||||
|
||||
/// @dev Internal function to batch withdraw ERC721 NFT to layer 1.
|
||||
/// @param _token The address of ERC721 NFT in layer 2.
|
||||
/// @param _to The address of recipient in layer 1.
|
||||
/// @param _tokenIds The list of token ids to withdraw.
|
||||
/// @param _gasLimit Estimated gas limit required to complete the withdraw on layer 1.
|
||||
function _batchWithdrawERC721(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256[] calldata _tokenIds,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(_tokenIds.length > 0, "no token to withdraw");
|
||||
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "token not supported");
|
||||
|
||||
// 1. transfer token to this contract
|
||||
for (uint256 i = 0; i < _tokenIds.length; i++) {
|
||||
// @note in case the token has given too much power to the gateway, we check owner here.
|
||||
require(IScrollERC721(_token).ownerOf(_tokenIds[i]) == msg.sender, "token not owned");
|
||||
IScrollERC721(_token).burn(_tokenIds[i]);
|
||||
}
|
||||
|
||||
// 2. Generate message passed to L1ERC721Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC721Gateway.finalizeBatchWithdrawERC721.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
msg.sender,
|
||||
_to,
|
||||
_tokenIds
|
||||
);
|
||||
|
||||
// 3. Send message to L2ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, msg.value, _message, _gasLimit);
|
||||
|
||||
emit BatchWithdrawERC721(_l1Token, _token, msg.sender, _to, _tokenIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
|
||||
import { IL1ETHGateway } from "../../L1/gateways/IL1ETHGateway.sol";
|
||||
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
|
||||
import { IL2ETHGateway } from "./IL2ETHGateway.sol";
|
||||
import {IL1ETHGateway} from "../../L1/gateways/IL1ETHGateway.sol";
|
||||
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
|
||||
import {IL2ETHGateway} from "./IL2ETHGateway.sol";
|
||||
|
||||
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
|
||||
/// @title L2ETHGateway
|
||||
/// @notice The `L2ETHGateway` contract is used to withdraw ETH token in layer 2 and
|
||||
@@ -16,94 +16,94 @@ import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol
|
||||
/// @dev The ETH are not held in the gateway. The ETH will be sent to the `L2ScrollMessenger` contract.
|
||||
/// On finalizing deposit, the Ether will be transfered from `L2ScrollMessenger`, then transfer to recipient.
|
||||
contract L2ETHGateway is Initializable, ScrollGatewayBase, IL2ETHGateway {
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
/// @notice Initialize the storage of L2ETHGateway.
|
||||
/// @param _counterpart The address of L1ETHGateway in L2.
|
||||
/// @param _router The address of L2GatewayRouter.
|
||||
/// @param _messenger The address of L2ScrollMessenger.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
_withdraw(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
_withdraw(_to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETHAndCall(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
_withdraw(_to, _amount, _data, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function finalizeDepositETH(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool _success, ) = _to.call{ value: _amount }("");
|
||||
require(_success, "ETH transfer failed");
|
||||
|
||||
// @todo farward _data to `_to` in near future.
|
||||
|
||||
emit FinalizeDepositETH(_from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
function _withdraw(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(msg.value > 0, "withdraw zero eth");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
/// @notice Initialize the storage of L2ETHGateway.
|
||||
/// @param _counterpart The address of L1ETHGateway in L2.
|
||||
/// @param _router The address of L2GatewayRouter.
|
||||
/// @param _messenger The address of L2ScrollMessenger.
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ETHGateway.finalizeWithdrawETH.selector,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
IL2ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, _amount, _message, _gasLimit);
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
emit WithdrawETH(_from, _to, _amount, _data);
|
||||
}
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
_withdraw(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
_withdraw(_to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETHAndCall(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
_withdraw(_to, _amount, _data, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function finalizeDepositETH(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool _success, ) = _to.call{value: _amount}("");
|
||||
require(_success, "ETH transfer failed");
|
||||
|
||||
// @todo farward _data to `_to` in near future.
|
||||
|
||||
emit FinalizeDepositETH(_from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
function _withdraw(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal nonReentrant {
|
||||
require(msg.value > 0, "withdraw zero eth");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ETHGateway.finalizeWithdrawETH.selector,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, _amount, _message, _gasLimit);
|
||||
|
||||
emit WithdrawETH(_from, _to, _amount, _data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
|
||||
import { IL2GatewayRouter } from "./IL2GatewayRouter.sol";
|
||||
import { IL2ETHGateway } from "./IL2ETHGateway.sol";
|
||||
import { IL2ERC20Gateway } from "./IL2ERC20Gateway.sol";
|
||||
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
|
||||
import { IL1ETHGateway } from "../../L1/gateways/IL1ETHGateway.sol";
|
||||
import { IScrollGateway } from "../../libraries/gateway/IScrollGateway.sol";
|
||||
import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20.sol";
|
||||
import {IL2GatewayRouter} from "./IL2GatewayRouter.sol";
|
||||
import {IL2ETHGateway} from "./IL2ETHGateway.sol";
|
||||
import {IL2ERC20Gateway} from "./IL2ERC20Gateway.sol";
|
||||
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
|
||||
import {IL1ETHGateway} from "../../L1/gateways/IL1ETHGateway.sol";
|
||||
import {IScrollGateway} from "../../libraries/gateway/IScrollGateway.sol";
|
||||
import {IScrollStandardERC20} from "../../libraries/token/IScrollStandardERC20.sol";
|
||||
|
||||
/// @title L2GatewayRouter
|
||||
/// @notice The `L2GatewayRouter` is the main entry for withdrawing Ether and ERC20 tokens.
|
||||
@@ -18,195 +18,195 @@ import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20
|
||||
/// @dev One can also use this contract to query L1/L2 token address mapping.
|
||||
/// In the future, ERC-721 and ERC-1155 tokens will be added to the router too.
|
||||
contract L2GatewayRouter is OwnableUpgradeable, IL2GatewayRouter {
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice The address of L2ETHGateway.
|
||||
address public ethGateway;
|
||||
/// @notice The address of L2ETHGateway.
|
||||
address public ethGateway;
|
||||
|
||||
/// @notice The addess of default L2 ERC20 gateway, normally the L2StandardERC20Gateway contract.
|
||||
address public defaultERC20Gateway;
|
||||
/// @notice The addess of default L2 ERC20 gateway, normally the L2StandardERC20Gateway contract.
|
||||
address public defaultERC20Gateway;
|
||||
|
||||
/// @notice Mapping from L2 ERC20 token address to corresponding L2ERC20Gateway.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public ERC20Gateway;
|
||||
/// @notice Mapping from L2 ERC20 token address to corresponding L2ERC20Gateway.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
mapping(address => address) public ERC20Gateway;
|
||||
|
||||
// @todo: add ERC721/ERC1155 Gateway mapping.
|
||||
// @todo: add ERC721/ERC1155 Gateway mapping.
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
function initialize(address _ethGateway, address _defaultERC20Gateway) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
function initialize(address _ethGateway, address _defaultERC20Gateway) external initializer {
|
||||
OwnableUpgradeable.__Ownable_init();
|
||||
|
||||
// it can be zero during initialization
|
||||
if (_defaultERC20Gateway != address(0)) {
|
||||
defaultERC20Gateway = _defaultERC20Gateway;
|
||||
// it can be zero during initialization
|
||||
if (_defaultERC20Gateway != address(0)) {
|
||||
defaultERC20Gateway = _defaultERC20Gateway;
|
||||
}
|
||||
|
||||
// it can be zero during initialization
|
||||
if (_ethGateway != address(0)) {
|
||||
ethGateway = _ethGateway;
|
||||
emit SetETHGateway(_ethGateway);
|
||||
}
|
||||
}
|
||||
|
||||
// it can be zero during initialization
|
||||
if (_ethGateway != address(0)) {
|
||||
ethGateway = _ethGateway;
|
||||
emit SetETHGateway(_ethGateway);
|
||||
}
|
||||
}
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL2ERC20Address(address) external pure override returns (address) {
|
||||
revert("unsupported");
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL1ERC20Address(address _l2Address) external view override returns (address) {
|
||||
address _gateway = getERC20Gateway(_l2Address);
|
||||
if (_gateway == address(0)) {
|
||||
return address(0);
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL2ERC20Address(address) external pure override returns (address) {
|
||||
revert("unsupported");
|
||||
}
|
||||
|
||||
return IL2ERC20Gateway(_gateway).getL1ERC20Address(_l2Address);
|
||||
}
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL1ERC20Address(address _l2Address) external view override returns (address) {
|
||||
address _gateway = getERC20Gateway(_l2Address);
|
||||
if (_gateway == address(0)) {
|
||||
return address(0);
|
||||
}
|
||||
|
||||
/// @notice Return the corresponding gateway address for given token address.
|
||||
/// @param _token The address of token to query.
|
||||
function getERC20Gateway(address _token) public view returns (address) {
|
||||
address _gateway = ERC20Gateway[_token];
|
||||
if (_gateway == address(0)) {
|
||||
_gateway = defaultERC20Gateway;
|
||||
return IL2ERC20Gateway(_gateway).getL1ERC20Address(_l2Address);
|
||||
}
|
||||
return _gateway;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
withdrawERC20AndCall(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
withdrawERC20AndCall(_token, _to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
address _gateway = getERC20Gateway(_token);
|
||||
require(_gateway != address(0), "no gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
|
||||
IL2ERC20Gateway(_gateway).withdrawERC20AndCall{ value: msg.value }(_token, _to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
withdrawETHAndCall(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
withdrawETHAndCall(_to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETHAndCall(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
address _gateway = ethGateway;
|
||||
require(_gateway != address(0), "eth gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
|
||||
IL2ETHGateway(_gateway).withdrawETHAndCall{ value: msg.value }(_to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function finalizeDepositETH(
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external payable virtual override {
|
||||
revert("should never be called");
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function finalizeDepositERC20(
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external payable virtual override {
|
||||
revert("should never be called");
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update the address of ETH gateway contract.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _ethGateway The address to update.
|
||||
function setETHGateway(address _ethGateway) external onlyOwner {
|
||||
ethGateway = _ethGateway;
|
||||
|
||||
emit SetETHGateway(_ethGateway);
|
||||
}
|
||||
|
||||
/// @notice Update the address of default ERC20 gateway contract.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _defaultERC20Gateway The address to update.
|
||||
function setDefaultERC20Gateway(address _defaultERC20Gateway) external onlyOwner {
|
||||
defaultERC20Gateway = _defaultERC20Gateway;
|
||||
|
||||
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
|
||||
}
|
||||
|
||||
/// @notice Update the mapping from token address to gateway address.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _tokens The list of addresses of tokens to update.
|
||||
/// @param _gateways The list of addresses of gateways to update.
|
||||
function setERC20Gateway(address[] memory _tokens, address[] memory _gateways) external onlyOwner {
|
||||
require(_tokens.length == _gateways.length, "length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
||||
ERC20Gateway[_tokens[i]] = _gateways[i];
|
||||
|
||||
emit SetERC20Gateway(_tokens[i], _gateways[i]);
|
||||
/// @notice Return the corresponding gateway address for given token address.
|
||||
/// @param _token The address of token to query.
|
||||
function getERC20Gateway(address _token) public view returns (address) {
|
||||
address _gateway = ERC20Gateway[_token];
|
||||
if (_gateway == address(0)) {
|
||||
_gateway = defaultERC20Gateway;
|
||||
}
|
||||
return _gateway;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
withdrawERC20AndCall(_token, msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
withdrawERC20AndCall(_token, _to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function withdrawERC20AndCall(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
address _gateway = getERC20Gateway(_token);
|
||||
require(_gateway != address(0), "no gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
|
||||
IL2ERC20Gateway(_gateway).withdrawERC20AndCall{value: msg.value}(_token, _to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(uint256 _amount, uint256 _gasLimit) external payable override {
|
||||
withdrawETHAndCall(msg.sender, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETH(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
uint256 _gasLimit
|
||||
) external payable override {
|
||||
withdrawETHAndCall(_to, _amount, new bytes(0), _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function withdrawETHAndCall(
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) public payable override {
|
||||
address _gateway = ethGateway;
|
||||
require(_gateway != address(0), "eth gateway available");
|
||||
|
||||
// encode msg.sender with _data
|
||||
bytes memory _routerData = abi.encode(msg.sender, _data);
|
||||
|
||||
IL2ETHGateway(_gateway).withdrawETHAndCall{value: msg.value}(_to, _amount, _routerData, _gasLimit);
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ETHGateway
|
||||
function finalizeDepositETH(
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external payable virtual override {
|
||||
revert("should never be called");
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function finalizeDepositERC20(
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
uint256,
|
||||
bytes calldata
|
||||
) external payable virtual override {
|
||||
revert("should never be called");
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update the address of ETH gateway contract.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _ethGateway The address to update.
|
||||
function setETHGateway(address _ethGateway) external onlyOwner {
|
||||
ethGateway = _ethGateway;
|
||||
|
||||
emit SetETHGateway(_ethGateway);
|
||||
}
|
||||
|
||||
/// @notice Update the address of default ERC20 gateway contract.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _defaultERC20Gateway The address to update.
|
||||
function setDefaultERC20Gateway(address _defaultERC20Gateway) external onlyOwner {
|
||||
defaultERC20Gateway = _defaultERC20Gateway;
|
||||
|
||||
emit SetDefaultERC20Gateway(_defaultERC20Gateway);
|
||||
}
|
||||
|
||||
/// @notice Update the mapping from token address to gateway address.
|
||||
/// @dev This function should only be called by contract owner.
|
||||
/// @param _tokens The list of addresses of tokens to update.
|
||||
/// @param _gateways The list of addresses of gateways to update.
|
||||
function setERC20Gateway(address[] memory _tokens, address[] memory _gateways) external onlyOwner {
|
||||
require(_tokens.length == _gateways.length, "length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
||||
ERC20Gateway[_tokens[i]] = _gateways[i];
|
||||
|
||||
emit SetERC20Gateway(_tokens[i], _gateways[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
|
||||
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
|
||||
|
||||
import { IL2ERC20Gateway, L2ERC20Gateway } from "./L2ERC20Gateway.sol";
|
||||
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
|
||||
import { IL1ERC20Gateway } from "../../L1/gateways/IL1ERC20Gateway.sol";
|
||||
import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20.sol";
|
||||
import { ScrollStandardERC20 } from "../../libraries/token/ScrollStandardERC20.sol";
|
||||
import { IScrollStandardERC20Factory } from "../../libraries/token/IScrollStandardERC20Factory.sol";
|
||||
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
|
||||
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
|
||||
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
|
||||
import {IScrollStandardERC20} from "../../libraries/token/IScrollStandardERC20.sol";
|
||||
import {ScrollStandardERC20} from "../../libraries/token/ScrollStandardERC20.sol";
|
||||
import {IScrollStandardERC20Factory} from "../../libraries/token/IScrollStandardERC20Factory.sol";
|
||||
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
|
||||
/// @title L2StandardERC20Gateway
|
||||
/// @notice The `L2StandardERC20Gateway` is used to withdraw standard ERC20 tokens in layer 2 and
|
||||
@@ -22,142 +22,145 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
|
||||
/// token will be minted and transfered to the recipient. Any ERC20 that requires non-standard functionality
|
||||
/// should use a separate gateway.
|
||||
contract L2StandardERC20Gateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
|
||||
using SafeERC20 for IERC20;
|
||||
using Address for address;
|
||||
using SafeERC20 for IERC20;
|
||||
using Address for address;
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from l2 token address to l1 token address.
|
||||
mapping(address => address) private tokenMapping;
|
||||
/// @notice Mapping from l2 token address to l1 token address.
|
||||
mapping(address => address) private tokenMapping;
|
||||
|
||||
/// @notice The address of ScrollStandardERC20Factory.
|
||||
address public tokenFactory;
|
||||
/// @notice The address of ScrollStandardERC20Factory.
|
||||
address public tokenFactory;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger,
|
||||
address _tokenFactory
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger,
|
||||
address _tokenFactory
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
|
||||
require(_tokenFactory != address(0), "zero token factory");
|
||||
tokenFactory = _tokenFactory;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL1ERC20Address(address _l2Token) external view override returns (address) {
|
||||
return tokenMapping[_l2Token];
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL2ERC20Address(address _l1Token) public view override returns (address) {
|
||||
return IScrollStandardERC20Factory(tokenFactory).computeL2TokenAddress(address(this), _l1Token);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function finalizeDepositERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(msg.value == 0, "nonzero msg.value");
|
||||
|
||||
{
|
||||
// avoid stack too deep
|
||||
address _expectedL2Token = IScrollStandardERC20Factory(tokenFactory).computeL2TokenAddress(
|
||||
address(this),
|
||||
_l1Token
|
||||
);
|
||||
require(_l2Token == _expectedL2Token, "l2 token mismatch");
|
||||
require(_tokenFactory != address(0), "zero token factory");
|
||||
tokenFactory = _tokenFactory;
|
||||
}
|
||||
|
||||
bytes memory _deployData;
|
||||
bytes memory _callData;
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
if (tokenMapping[_l2Token] == address(0)) {
|
||||
// first deposit, update mapping
|
||||
tokenMapping[_l2Token] = _l1Token;
|
||||
(_callData, _deployData) = abi.decode(_data, (bytes, bytes));
|
||||
} else {
|
||||
_callData = _data;
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL1ERC20Address(address _l2Token) external view override returns (address) {
|
||||
return tokenMapping[_l2Token];
|
||||
}
|
||||
|
||||
if (!_l2Token.isContract()) {
|
||||
_deployL2Token(_deployData, _l1Token);
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL2ERC20Address(address _l1Token) public view override returns (address) {
|
||||
return IScrollStandardERC20Factory(tokenFactory).computeL2TokenAddress(address(this), _l1Token);
|
||||
}
|
||||
|
||||
// @todo forward `_callData` to `_to` using transferAndCall in the near future
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
IScrollStandardERC20(_l2Token).mint(_to, _amount);
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function finalizeDepositERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(msg.value == 0, "nonzero msg.value");
|
||||
|
||||
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _callData);
|
||||
}
|
||||
{
|
||||
// avoid stack too deep
|
||||
address _expectedL2Token = IScrollStandardERC20Factory(tokenFactory).computeL2TokenAddress(
|
||||
address(this),
|
||||
_l1Token
|
||||
);
|
||||
require(_l2Token == _expectedL2Token, "l2 token mismatch");
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
bytes memory _deployData;
|
||||
bytes memory _callData;
|
||||
|
||||
/// @inheritdoc L2ERC20Gateway
|
||||
function _withdraw(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override {
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
if (tokenMapping[_l2Token] == address(0)) {
|
||||
// first deposit, update mapping
|
||||
tokenMapping[_l2Token] = _l1Token;
|
||||
(_callData, _deployData) = abi.decode(_data, (bytes, bytes));
|
||||
} else {
|
||||
_callData = _data;
|
||||
}
|
||||
|
||||
// 1. Extract real sender if this call is from L2GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
if (!_l2Token.isContract()) {
|
||||
_deployL2Token(_deployData, _l1Token);
|
||||
}
|
||||
|
||||
// @todo forward `_callData` to `_to` using transferAndCall in the near future
|
||||
|
||||
IScrollStandardERC20(_l2Token).mint(_to, _amount);
|
||||
|
||||
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _callData);
|
||||
}
|
||||
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
// 2. Burn token.
|
||||
IScrollStandardERC20(_token).burn(_from, _amount);
|
||||
/// @inheritdoc L2ERC20Gateway
|
||||
function _withdraw(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override {
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
|
||||
// 3. Generate message passed to L1StandardERC20Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
// 1. Extract real sender if this call is from L2GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// 4. send message to L2ScrollMessenger
|
||||
IL2ScrollMessenger(messenger).sendMessage{ value: msg.value }(counterpart, 0, _message, _gasLimit);
|
||||
address _l1Token = tokenMapping[_token];
|
||||
require(_l1Token != address(0), "no corresponding l1 token");
|
||||
|
||||
emit WithdrawERC20(_l1Token, _token, _from, _to, _amount, _data);
|
||||
}
|
||||
// 2. Burn token.
|
||||
IScrollStandardERC20(_token).burn(_from, _amount);
|
||||
|
||||
function _deployL2Token(bytes memory _deployData, address _l1Token) internal {
|
||||
address _l2Token = IScrollStandardERC20Factory(tokenFactory).deployL2Token(address(this), _l1Token);
|
||||
(string memory _symbol, string memory _name, uint8 _decimals) = abi.decode(_deployData, (string, string, uint8));
|
||||
ScrollStandardERC20(_l2Token).initialize(_name, _symbol, _decimals, address(this), _l1Token);
|
||||
}
|
||||
// 3. Generate message passed to L1StandardERC20Gateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
_l1Token,
|
||||
_token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
|
||||
// 4. send message to L2ScrollMessenger
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: msg.value}(counterpart, 0, _message, _gasLimit);
|
||||
|
||||
emit WithdrawERC20(_l1Token, _token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
function _deployL2Token(bytes memory _deployData, address _l1Token) internal {
|
||||
address _l2Token = IScrollStandardERC20Factory(tokenFactory).deployL2Token(address(this), _l1Token);
|
||||
(string memory _symbol, string memory _name, uint8 _decimals) = abi.decode(
|
||||
_deployData,
|
||||
(string, string, uint8)
|
||||
);
|
||||
ScrollStandardERC20(_l2Token).initialize(_name, _symbol, _decimals, address(this), _l1Token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
|
||||
import { IL2ERC20Gateway, L2ERC20Gateway } from "./L2ERC20Gateway.sol";
|
||||
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
|
||||
import { IWETH } from "../../interfaces/IWETH.sol";
|
||||
import { IL1ERC20Gateway } from "../../L1/gateways/IL1ERC20Gateway.sol";
|
||||
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
|
||||
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
|
||||
import {IWETH} from "../../interfaces/IWETH.sol";
|
||||
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
|
||||
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
|
||||
|
||||
/// @title L2WETHGateway
|
||||
/// @notice The `L2WETHGateway` contract is used to withdraw `WETH` token in layer 2 and
|
||||
@@ -20,121 +20,126 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
|
||||
/// On finalizing deposit, the Ether will be transfered from `L2ScrollMessenger`, then
|
||||
/// wrapped as WETH and finally transfer to recipient.
|
||||
contract L2WETHGateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
|
||||
using SafeERC20 for IERC20;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
|
||||
/// @notice The address of L1 WETH address.
|
||||
address public immutable l1WETH;
|
||||
/// @notice The address of L1 WETH address.
|
||||
address public immutable l1WETH;
|
||||
|
||||
/// @notice The address of L2 WETH address.
|
||||
// @todo It should be predeployed in L2 and make it a constant.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
address public immutable WETH;
|
||||
/// @notice The address of L2 WETH address.
|
||||
// @todo It should be predeployed in L2 and make it a constant.
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
address public immutable WETH;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
constructor(address _WETH, address _l1WETH) {
|
||||
WETH = _WETH;
|
||||
l1WETH = _l1WETH;
|
||||
}
|
||||
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
receive() external payable {
|
||||
require(msg.sender == WETH, "only WETH");
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL1ERC20Address(address) external view override returns (address) {
|
||||
return l1WETH;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL2ERC20Address(address) public view override returns (address) {
|
||||
return WETH;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function finalizeDepositERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(_l1Token == l1WETH, "l1 token not WETH");
|
||||
require(_l2Token == WETH, "l2 token not WETH");
|
||||
require(_amount == msg.value, "msg.value mismatch");
|
||||
|
||||
IWETH(_l2Token).deposit{ value: _amount }();
|
||||
IERC20(_l2Token).safeTransfer(_to, _amount);
|
||||
|
||||
// @todo forward `_data` to `_to` in near future
|
||||
|
||||
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L2ERC20Gateway
|
||||
function _withdraw(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override {
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
require(_token == WETH, "only WETH is allowed");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
constructor(address _WETH, address _l1WETH) {
|
||||
WETH = _WETH;
|
||||
l1WETH = _l1WETH;
|
||||
}
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
IWETH(_token).withdraw(_amount);
|
||||
function initialize(
|
||||
address _counterpart,
|
||||
address _router,
|
||||
address _messenger
|
||||
) external initializer {
|
||||
require(_router != address(0), "zero router address");
|
||||
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
|
||||
}
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
address _l1WETH = l1WETH;
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
_l1WETH,
|
||||
_token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
receive() external payable {
|
||||
require(msg.sender == WETH, "only WETH");
|
||||
}
|
||||
|
||||
// 4. Send message to L1ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{ value: _amount + msg.value }(counterpart, _amount, _message, _gasLimit);
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
emit WithdrawERC20(_l1WETH, _token, _from, _to, _amount, _data);
|
||||
}
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL1ERC20Address(address) external view override returns (address) {
|
||||
return l1WETH;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function getL2ERC20Address(address) public view override returns (address) {
|
||||
return WETH;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @inheritdoc IL2ERC20Gateway
|
||||
function finalizeDepositERC20(
|
||||
address _l1Token,
|
||||
address _l2Token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes calldata _data
|
||||
) external payable override onlyCallByCounterpart {
|
||||
require(_l1Token == l1WETH, "l1 token not WETH");
|
||||
require(_l2Token == WETH, "l2 token not WETH");
|
||||
require(_amount == msg.value, "msg.value mismatch");
|
||||
|
||||
IWETH(_l2Token).deposit{value: _amount}();
|
||||
IERC20(_l2Token).safeTransfer(_to, _amount);
|
||||
|
||||
// @todo forward `_data` to `_to` in near future
|
||||
|
||||
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Internal Functions *
|
||||
**********************/
|
||||
|
||||
/// @inheritdoc L2ERC20Gateway
|
||||
function _withdraw(
|
||||
address _token,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes memory _data,
|
||||
uint256 _gasLimit
|
||||
) internal virtual override {
|
||||
require(_amount > 0, "withdraw zero amount");
|
||||
require(_token == WETH, "only WETH is allowed");
|
||||
|
||||
// 1. Extract real sender if this call is from L1GatewayRouter.
|
||||
address _from = msg.sender;
|
||||
if (router == msg.sender) {
|
||||
(_from, _data) = abi.decode(_data, (address, bytes));
|
||||
}
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
IWETH(_token).withdraw(_amount);
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
address _l1WETH = l1WETH;
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
_l1WETH,
|
||||
_token,
|
||||
_from,
|
||||
_to,
|
||||
_amount,
|
||||
_data
|
||||
);
|
||||
|
||||
// 4. Send message to L1ScrollMessenger.
|
||||
IL2ScrollMessenger(messenger).sendMessage{value: _amount + msg.value}(
|
||||
counterpart,
|
||||
_amount,
|
||||
_message,
|
||||
_gasLimit
|
||||
);
|
||||
|
||||
emit WithdrawERC20(_l1WETH, _token, _from, _to, _amount, _data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,61 +3,61 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IL1BlockContainer {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when a block is imported.
|
||||
/// @param blockHash The hash of the imported block.
|
||||
/// @param blockHeight The height of the imported block.
|
||||
/// @param blockTimestamp The timestamp of the imported block.
|
||||
/// @param baseFee The base fee of the imported block.
|
||||
/// @param stateRoot The state root of the imported block.
|
||||
event ImportBlock(
|
||||
bytes32 indexed blockHash,
|
||||
uint256 blockHeight,
|
||||
uint256 blockTimestamp,
|
||||
uint256 baseFee,
|
||||
bytes32 stateRoot
|
||||
);
|
||||
/// @notice Emitted when a block is imported.
|
||||
/// @param blockHash The hash of the imported block.
|
||||
/// @param blockHeight The height of the imported block.
|
||||
/// @param blockTimestamp The timestamp of the imported block.
|
||||
/// @param baseFee The base fee of the imported block.
|
||||
/// @param stateRoot The state root of the imported block.
|
||||
event ImportBlock(
|
||||
bytes32 indexed blockHash,
|
||||
uint256 blockHeight,
|
||||
uint256 blockTimestamp,
|
||||
uint256 baseFee,
|
||||
bytes32 stateRoot
|
||||
);
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Return the latest imported block hash
|
||||
function latestBlockHash() external view returns (bytes32);
|
||||
/// @notice Return the latest imported block hash
|
||||
function latestBlockHash() external view returns (bytes32);
|
||||
|
||||
/// @notice Return the latest imported L1 base fee
|
||||
function latestBaseFee() external view returns (uint256);
|
||||
/// @notice Return the latest imported L1 base fee
|
||||
function latestBaseFee() external view returns (uint256);
|
||||
|
||||
/// @notice Return the latest imported block number
|
||||
function latestBlockNumber() external view returns (uint256);
|
||||
/// @notice Return the latest imported block number
|
||||
function latestBlockNumber() external view returns (uint256);
|
||||
|
||||
/// @notice Return the latest imported block timestamp
|
||||
function latestBlockTimestamp() external view returns (uint256);
|
||||
/// @notice Return the latest imported block timestamp
|
||||
function latestBlockTimestamp() external view returns (uint256);
|
||||
|
||||
/// @notice Return the state root of given block.
|
||||
/// @param blockHash The block hash to query.
|
||||
/// @return stateRoot The state root of the block.
|
||||
function getStateRoot(bytes32 blockHash) external view returns (bytes32 stateRoot);
|
||||
/// @notice Return the state root of given block.
|
||||
/// @param blockHash The block hash to query.
|
||||
/// @return stateRoot The state root of the block.
|
||||
function getStateRoot(bytes32 blockHash) external view returns (bytes32 stateRoot);
|
||||
|
||||
/// @notice Return the block timestamp of given block.
|
||||
/// @param blockHash The block hash to query.
|
||||
/// @return timestamp The corresponding block timestamp.
|
||||
function getBlockTimestamp(bytes32 blockHash) external view returns (uint256 timestamp);
|
||||
/// @notice Return the block timestamp of given block.
|
||||
/// @param blockHash The block hash to query.
|
||||
/// @return timestamp The corresponding block timestamp.
|
||||
function getBlockTimestamp(bytes32 blockHash) external view returns (uint256 timestamp);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Import L1 block header to this contract.
|
||||
/// @param blockHash The hash of block.
|
||||
/// @param blockHeaderRLP The RLP encoding of L1 block.
|
||||
/// @param updateGasPriceOracle Whether to update gas price oracle.
|
||||
function importBlockHeader(
|
||||
bytes32 blockHash,
|
||||
bytes calldata blockHeaderRLP,
|
||||
bool updateGasPriceOracle
|
||||
) external;
|
||||
/// @notice Import L1 block header to this contract.
|
||||
/// @param blockHash The hash of block.
|
||||
/// @param blockHeaderRLP The RLP encoding of L1 block.
|
||||
/// @param updateGasPriceOracle Whether to update gas price oracle.
|
||||
function importBlockHeader(
|
||||
bytes32 blockHash,
|
||||
bytes calldata blockHeaderRLP,
|
||||
bool updateGasPriceOracle
|
||||
) external;
|
||||
}
|
||||
|
||||
@@ -3,54 +3,54 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
interface IL1GasPriceOracle {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when current fee overhead is updated.
|
||||
/// @param overhead The current fee overhead updated.
|
||||
event OverheadUpdated(uint256 overhead);
|
||||
/// @notice Emitted when current fee overhead is updated.
|
||||
/// @param overhead The current fee overhead updated.
|
||||
event OverheadUpdated(uint256 overhead);
|
||||
|
||||
/// @notice Emitted when current fee scalar is updated.
|
||||
/// @param scalar The current fee scalar updated.
|
||||
event ScalarUpdated(uint256 scalar);
|
||||
/// @notice Emitted when current fee scalar is updated.
|
||||
/// @param scalar The current fee scalar updated.
|
||||
event ScalarUpdated(uint256 scalar);
|
||||
|
||||
/// @notice Emitted when current l1 base fee is updated.
|
||||
/// @param l1BaseFee The current l1 base fee updated.
|
||||
event L1BaseFeeUpdated(uint256 l1BaseFee);
|
||||
/// @notice Emitted when current l1 base fee is updated.
|
||||
/// @param l1BaseFee The current l1 base fee updated.
|
||||
event L1BaseFeeUpdated(uint256 l1BaseFee);
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Return the current l1 fee overhead.
|
||||
function overhead() external view returns (uint256);
|
||||
/// @notice Return the current l1 fee overhead.
|
||||
function overhead() external view returns (uint256);
|
||||
|
||||
/// @notice Return the current l1 fee scalar.
|
||||
function scalar() external view returns (uint256);
|
||||
/// @notice Return the current l1 fee scalar.
|
||||
function scalar() external view returns (uint256);
|
||||
|
||||
/// @notice Return the latest known l1 base fee.
|
||||
function l1BaseFee() external view returns (uint256);
|
||||
/// @notice Return the latest known l1 base fee.
|
||||
function l1BaseFee() external view returns (uint256);
|
||||
|
||||
/// @notice Computes the L1 portion of the fee based on the size of the rlp encoded input
|
||||
/// transaction, the current L1 base fee, and the various dynamic parameters.
|
||||
/// @param data Unsigned fully RLP-encoded transaction to get the L1 fee for.
|
||||
/// @return L1 fee that should be paid for the tx
|
||||
function getL1Fee(bytes memory data) external view returns (uint256);
|
||||
/// @notice Computes the L1 portion of the fee based on the size of the rlp encoded input
|
||||
/// transaction, the current L1 base fee, and the various dynamic parameters.
|
||||
/// @param data Unsigned fully RLP-encoded transaction to get the L1 fee for.
|
||||
/// @return L1 fee that should be paid for the tx
|
||||
function getL1Fee(bytes memory data) external view returns (uint256);
|
||||
|
||||
/// @notice Computes the amount of L1 gas used for a transaction. Adds the overhead which
|
||||
/// represents the per-transaction gas overhead of posting the transaction and state
|
||||
/// roots to L1. Adds 68 bytes of padding to account for the fact that the input does
|
||||
/// not have a signature.
|
||||
/// @param data Unsigned fully RLP-encoded transaction to get the L1 gas for.
|
||||
/// @return Amount of L1 gas used to publish the transaction.
|
||||
function getL1GasUsed(bytes memory data) external view returns (uint256);
|
||||
/// @notice Computes the amount of L1 gas used for a transaction. Adds the overhead which
|
||||
/// represents the per-transaction gas overhead of posting the transaction and state
|
||||
/// roots to L1. Adds 68 bytes of padding to account for the fact that the input does
|
||||
/// not have a signature.
|
||||
/// @param data Unsigned fully RLP-encoded transaction to get the L1 gas for.
|
||||
/// @return Amount of L1 gas used to publish the transaction.
|
||||
function getL1GasUsed(bytes memory data) external view returns (uint256);
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @notice Allows whitelisted caller to modify the l1 base fee.
|
||||
/// @param _l1BaseFee New l1 base fee.
|
||||
function setL1BaseFee(uint256 _l1BaseFee) external;
|
||||
/// @notice Allows whitelisted caller to modify the l1 base fee.
|
||||
/// @param _l1BaseFee New l1 base fee.
|
||||
function setL1BaseFee(uint256 _l1BaseFee) external;
|
||||
}
|
||||
|
||||
@@ -2,302 +2,313 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { IL1BlockContainer } from "./IL1BlockContainer.sol";
|
||||
import { IL1GasPriceOracle } from "./IL1GasPriceOracle.sol";
|
||||
import {IL1BlockContainer} from "./IL1BlockContainer.sol";
|
||||
import {IL1GasPriceOracle} from "./IL1GasPriceOracle.sol";
|
||||
|
||||
import { OwnableBase } from "../../libraries/common/OwnableBase.sol";
|
||||
import { IWhitelist } from "../../libraries/common/IWhitelist.sol";
|
||||
import { ScrollPredeploy } from "../../libraries/constants/ScrollPredeploy.sol";
|
||||
import {OwnableBase} from "../../libraries/common/OwnableBase.sol";
|
||||
import {IWhitelist} from "../../libraries/common/IWhitelist.sol";
|
||||
import {ScrollPredeploy} from "../../libraries/constants/ScrollPredeploy.sol";
|
||||
|
||||
/// @title L1BlockContainer
|
||||
/// @notice This contract will maintain the list of blocks proposed in L1.
|
||||
contract L1BlockContainer is OwnableBase, IL1BlockContainer {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when owner updates whitelist contract.
|
||||
/// @param _oldWhitelist The address of old whitelist contract.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
event UpdateWhitelist(address _oldWhitelist, address _newWhitelist);
|
||||
/// @notice Emitted when owner updates whitelist contract.
|
||||
/// @param _oldWhitelist The address of old whitelist contract.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
event UpdateWhitelist(address _oldWhitelist, address _newWhitelist);
|
||||
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
/***********
|
||||
* Structs *
|
||||
***********/
|
||||
|
||||
/// @dev Compiler will pack this into single `uint256`.
|
||||
struct BlockMetadata {
|
||||
// The block height.
|
||||
uint64 height;
|
||||
// The block timestamp.
|
||||
uint64 timestamp;
|
||||
// The base fee in the block.
|
||||
uint128 baseFee;
|
||||
}
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice The address of whitelist contract.
|
||||
IWhitelist public whitelist;
|
||||
|
||||
// @todo change to ring buffer to save gas usage.
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
bytes32 public override latestBlockHash;
|
||||
|
||||
/// @notice Mapping from block hash to corresponding state root.
|
||||
mapping(bytes32 => bytes32) public stateRoot;
|
||||
|
||||
/// @notice Mapping from block hash to corresponding block metadata,
|
||||
/// including timestamp and height.
|
||||
mapping(bytes32 => BlockMetadata) public metadata;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
constructor(address _owner) {
|
||||
_transferOwnership(_owner);
|
||||
}
|
||||
|
||||
function initialize(
|
||||
bytes32 _startBlockHash,
|
||||
uint64 _startBlockHeight,
|
||||
uint64 _startBlockTimestamp,
|
||||
uint128 _startBlockBaseFee,
|
||||
bytes32 _startStateRoot
|
||||
) external onlyOwner {
|
||||
require(latestBlockHash == bytes32(0), "already initialized");
|
||||
|
||||
latestBlockHash = _startBlockHash;
|
||||
stateRoot[_startBlockHash] = _startStateRoot;
|
||||
metadata[_startBlockHash] = BlockMetadata(_startBlockHeight, _startBlockTimestamp, _startBlockBaseFee);
|
||||
|
||||
emit ImportBlock(_startBlockHash, _startBlockHeight, _startBlockTimestamp, _startBlockBaseFee, _startStateRoot);
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function latestBaseFee() external view override returns (uint256) {
|
||||
return metadata[latestBlockHash].baseFee;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function latestBlockNumber() external view override returns (uint256) {
|
||||
return metadata[latestBlockHash].height;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function latestBlockTimestamp() external view override returns (uint256) {
|
||||
return metadata[latestBlockHash].timestamp;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function getStateRoot(bytes32 _blockHash) external view returns (bytes32) {
|
||||
return stateRoot[_blockHash];
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function getBlockTimestamp(bytes32 _blockHash) external view returns (uint256) {
|
||||
return metadata[_blockHash].timestamp;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function importBlockHeader(
|
||||
bytes32 _blockHash,
|
||||
bytes calldata _blockHeaderRLP,
|
||||
bool _updateGasPriceOracle
|
||||
) external {
|
||||
// @todo remove this when ETH 2.0 signature verification is ready.
|
||||
{
|
||||
IWhitelist _whitelist = whitelist;
|
||||
require(address(_whitelist) == address(0) || _whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
|
||||
/// @dev Compiler will pack this into single `uint256`.
|
||||
struct BlockMetadata {
|
||||
// The block height.
|
||||
uint64 height;
|
||||
// The block timestamp.
|
||||
uint64 timestamp;
|
||||
// The base fee in the block.
|
||||
uint128 baseFee;
|
||||
}
|
||||
|
||||
// The encoding order in block header is
|
||||
// 1. ParentHash: 32 bytes
|
||||
// 2. UncleHash: 32 bytes
|
||||
// 3. Coinbase: 20 bytes
|
||||
// 4. StateRoot: 32 bytes
|
||||
// 5. TransactionsRoot: 32 bytes
|
||||
// 6. ReceiptsRoot: 32 bytes
|
||||
// 7. LogsBloom: 256 bytes
|
||||
// 8. Difficulty: uint
|
||||
// 9. BlockHeight: uint
|
||||
// 10. GasLimit: uint64
|
||||
// 11. GasUsed: uint64
|
||||
// 12. BlockTimestamp: uint64
|
||||
// 13. ExtraData: several bytes
|
||||
// 14. MixHash: 32 bytes
|
||||
// 15. BlockNonce: 8 bytes
|
||||
// 16. BaseFee: uint // optional
|
||||
bytes32 _parentHash;
|
||||
bytes32 _stateRoot;
|
||||
uint64 _height;
|
||||
uint64 _timestamp;
|
||||
uint128 _baseFee;
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
assembly {
|
||||
// reverts with error `msg`.
|
||||
// make sure the length of error string <= 32
|
||||
function revertWith(msg) {
|
||||
// keccak("Error(string)")
|
||||
mstore(0x00, shl(224, 0x08c379a0))
|
||||
mstore(0x04, 0x20) // str.offset
|
||||
mstore(0x44, msg)
|
||||
let msgLen
|
||||
for {} msg {} {
|
||||
msg := shl(8, msg)
|
||||
msgLen := add(msgLen, 1)
|
||||
}
|
||||
mstore(0x24, msgLen) // str.length
|
||||
revert(0x00, 0x64)
|
||||
}
|
||||
// reverts with `msg` when condition is not matched.
|
||||
// make sure the length of error string <= 32
|
||||
function require(cond, msg) {
|
||||
if iszero(cond) {
|
||||
revertWith(msg)
|
||||
}
|
||||
}
|
||||
// returns the calldata offset of the value and the length in bytes
|
||||
// for the RLP encoded data item at `ptr`. used in `decodeFlat`
|
||||
function decodeValue(ptr) -> dataLen, valueOffset {
|
||||
let b0 := byte(0, calldataload(ptr))
|
||||
/// @notice The address of whitelist contract.
|
||||
IWhitelist public whitelist;
|
||||
|
||||
// 0x00 - 0x7f, single byte
|
||||
if lt(b0, 0x80) {
|
||||
// for a single byte whose value is in the [0x00, 0x7f] range,
|
||||
// that byte is its own RLP encoding.
|
||||
dataLen := 1
|
||||
valueOffset := ptr
|
||||
leave
|
||||
}
|
||||
// @todo change to ring buffer to save gas usage.
|
||||
|
||||
// 0x80 - 0xb7, short string/bytes, length <= 55
|
||||
if lt(b0, 0xb8) {
|
||||
// the RLP encoding consists of a single byte with value 0x80
|
||||
// plus the length of the string followed by the string.
|
||||
dataLen := sub(b0, 0x80)
|
||||
valueOffset := add(ptr, 1)
|
||||
leave
|
||||
}
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
bytes32 public override latestBlockHash;
|
||||
|
||||
// 0xb8 - 0xbf, long string/bytes, length > 55
|
||||
if lt(b0, 0xc0) {
|
||||
// the RLP encoding consists of a single byte with value 0xb7
|
||||
// plus the length in bytes of the length of the string in binary form,
|
||||
// followed by the length of the string, followed by the string.
|
||||
let lengthBytes := sub(b0, 0xb7)
|
||||
if gt(lengthBytes, 4) {
|
||||
invalid()
|
||||
}
|
||||
/// @notice Mapping from block hash to corresponding state root.
|
||||
mapping(bytes32 => bytes32) public stateRoot;
|
||||
|
||||
// load the extended length
|
||||
valueOffset := add(ptr, 1)
|
||||
let extendedLen := calldataload(valueOffset)
|
||||
let bits := sub(256, mul(lengthBytes, 8))
|
||||
extendedLen := shr(bits, extendedLen)
|
||||
/// @notice Mapping from block hash to corresponding block metadata,
|
||||
/// including timestamp and height.
|
||||
mapping(bytes32 => BlockMetadata) public metadata;
|
||||
|
||||
dataLen := extendedLen
|
||||
valueOffset := add(valueOffset, lengthBytes)
|
||||
leave
|
||||
}
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
revertWith("Not value")
|
||||
}
|
||||
|
||||
let ptr := _blockHeaderRLP.offset
|
||||
let headerPayloadLength
|
||||
{
|
||||
let b0 := byte(0, calldataload(ptr))
|
||||
// the input should be a long list
|
||||
if lt(b0, 0xf8) {
|
||||
invalid()
|
||||
}
|
||||
let lengthBytes := sub(b0, 0xf7)
|
||||
if gt(lengthBytes, 32) {
|
||||
invalid()
|
||||
}
|
||||
// load the extended length
|
||||
ptr := add(ptr, 1)
|
||||
headerPayloadLength := calldataload(ptr)
|
||||
let bits := sub(256, mul(lengthBytes, 8))
|
||||
// compute payload length: extended length + length bytes + 1
|
||||
headerPayloadLength := shr(bits, headerPayloadLength)
|
||||
headerPayloadLength := add(headerPayloadLength, lengthBytes)
|
||||
headerPayloadLength := add(headerPayloadLength, 1)
|
||||
ptr := add(ptr, lengthBytes)
|
||||
}
|
||||
|
||||
let memPtr := mload(0x40)
|
||||
calldatacopy(memPtr, _blockHeaderRLP.offset, headerPayloadLength)
|
||||
let _computedBlockHash := keccak256(memPtr, headerPayloadLength)
|
||||
require(eq(_blockHash, _computedBlockHash), "Block hash mismatch")
|
||||
|
||||
// load 16 vaules
|
||||
for { let i := 0 } lt(i, 16) { i := add(i, 1) } {
|
||||
let len, offset := decodeValue(ptr)
|
||||
// the value we care must have at most 32 bytes
|
||||
if lt(len, 33) {
|
||||
let bits := mul( sub(32, len), 8)
|
||||
let value := calldataload(offset)
|
||||
value := shr(bits, value)
|
||||
mstore(memPtr, value)
|
||||
}
|
||||
memPtr := add(memPtr, 0x20)
|
||||
ptr := add(len, offset)
|
||||
}
|
||||
require(eq(ptr, add(_blockHeaderRLP.offset, _blockHeaderRLP.length)), "Header RLP length mismatch")
|
||||
|
||||
memPtr := mload(0x40)
|
||||
// load parent hash, 1-st entry
|
||||
_parentHash := mload(memPtr)
|
||||
// load state root, 4-th entry
|
||||
_stateRoot := mload(add(memPtr, 0x60))
|
||||
// load block height, 9-th entry
|
||||
_height := mload(add(memPtr, 0x100))
|
||||
// load block timestamp, 12-th entry
|
||||
_timestamp := mload(add(memPtr, 0x160))
|
||||
// load base fee, 16-th entry
|
||||
_baseFee := mload(add(memPtr, 0x1e0))
|
||||
constructor(address _owner) {
|
||||
_transferOwnership(_owner);
|
||||
}
|
||||
require(stateRoot[_parentHash] != bytes32(0), "Parent not imported");
|
||||
BlockMetadata memory _parentMetadata = metadata[_parentHash];
|
||||
require(_parentMetadata.height + 1 == _height, "Block height mismatch");
|
||||
require(_parentMetadata.timestamp <= _timestamp, "Parent block has larger timestamp");
|
||||
|
||||
latestBlockHash = _blockHash;
|
||||
stateRoot[_blockHash] = _stateRoot;
|
||||
metadata[_blockHash] = BlockMetadata(_height, _timestamp, _baseFee);
|
||||
function initialize(
|
||||
bytes32 _startBlockHash,
|
||||
uint64 _startBlockHeight,
|
||||
uint64 _startBlockTimestamp,
|
||||
uint128 _startBlockBaseFee,
|
||||
bytes32 _startStateRoot
|
||||
) external onlyOwner {
|
||||
require(latestBlockHash == bytes32(0), "already initialized");
|
||||
|
||||
emit ImportBlock(_blockHash, _height, _timestamp, _baseFee, _stateRoot);
|
||||
latestBlockHash = _startBlockHash;
|
||||
stateRoot[_startBlockHash] = _startStateRoot;
|
||||
metadata[_startBlockHash] = BlockMetadata(_startBlockHeight, _startBlockTimestamp, _startBlockBaseFee);
|
||||
|
||||
if (_updateGasPriceOracle) {
|
||||
IL1GasPriceOracle(ScrollPredeploy.L1_GAS_PRICE_ORACLE).setL1BaseFee(_baseFee);
|
||||
emit ImportBlock(_startBlockHash, _startBlockHeight, _startBlockTimestamp, _startBlockBaseFee, _startStateRoot);
|
||||
}
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @notice Update whitelist contract.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
function updateWhitelist(address _newWhitelist) external onlyOwner {
|
||||
address _oldWhitelist = address(whitelist);
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function latestBaseFee() external view override returns (uint256) {
|
||||
return metadata[latestBlockHash].baseFee;
|
||||
}
|
||||
|
||||
whitelist = IWhitelist(_newWhitelist);
|
||||
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
|
||||
}
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function latestBlockNumber() external view override returns (uint256) {
|
||||
return metadata[latestBlockHash].height;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function latestBlockTimestamp() external view override returns (uint256) {
|
||||
return metadata[latestBlockHash].timestamp;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function getStateRoot(bytes32 _blockHash) external view returns (bytes32) {
|
||||
return stateRoot[_blockHash];
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function getBlockTimestamp(bytes32 _blockHash) external view returns (uint256) {
|
||||
return metadata[_blockHash].timestamp;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/// @inheritdoc IL1BlockContainer
|
||||
function importBlockHeader(
|
||||
bytes32 _blockHash,
|
||||
bytes calldata _blockHeaderRLP,
|
||||
bool _updateGasPriceOracle
|
||||
) external {
|
||||
// @todo remove this when ETH 2.0 signature verification is ready.
|
||||
{
|
||||
IWhitelist _whitelist = whitelist;
|
||||
require(
|
||||
address(_whitelist) == address(0) || _whitelist.isSenderAllowed(msg.sender),
|
||||
"Not whitelisted sender"
|
||||
);
|
||||
}
|
||||
|
||||
// The encoding order in block header is
|
||||
// 1. ParentHash: 32 bytes
|
||||
// 2. UncleHash: 32 bytes
|
||||
// 3. Coinbase: 20 bytes
|
||||
// 4. StateRoot: 32 bytes
|
||||
// 5. TransactionsRoot: 32 bytes
|
||||
// 6. ReceiptsRoot: 32 bytes
|
||||
// 7. LogsBloom: 256 bytes
|
||||
// 8. Difficulty: uint
|
||||
// 9. BlockHeight: uint
|
||||
// 10. GasLimit: uint64
|
||||
// 11. GasUsed: uint64
|
||||
// 12. BlockTimestamp: uint64
|
||||
// 13. ExtraData: several bytes
|
||||
// 14. MixHash: 32 bytes
|
||||
// 15. BlockNonce: 8 bytes
|
||||
// 16. BaseFee: uint // optional
|
||||
bytes32 _parentHash;
|
||||
bytes32 _stateRoot;
|
||||
uint64 _height;
|
||||
uint64 _timestamp;
|
||||
uint128 _baseFee;
|
||||
|
||||
assembly {
|
||||
// reverts with error `msg`.
|
||||
// make sure the length of error string <= 32
|
||||
function revertWith(msg) {
|
||||
// keccak("Error(string)")
|
||||
mstore(0x00, shl(224, 0x08c379a0))
|
||||
mstore(0x04, 0x20) // str.offset
|
||||
mstore(0x44, msg)
|
||||
let msgLen
|
||||
for {
|
||||
|
||||
} msg {
|
||||
|
||||
} {
|
||||
msg := shl(8, msg)
|
||||
msgLen := add(msgLen, 1)
|
||||
}
|
||||
mstore(0x24, msgLen) // str.length
|
||||
revert(0x00, 0x64)
|
||||
}
|
||||
// reverts with `msg` when condition is not matched.
|
||||
// make sure the length of error string <= 32
|
||||
function require(cond, msg) {
|
||||
if iszero(cond) {
|
||||
revertWith(msg)
|
||||
}
|
||||
}
|
||||
// returns the calldata offset of the value and the length in bytes
|
||||
// for the RLP encoded data item at `ptr`. used in `decodeFlat`
|
||||
function decodeValue(ptr) -> dataLen, valueOffset {
|
||||
let b0 := byte(0, calldataload(ptr))
|
||||
|
||||
// 0x00 - 0x7f, single byte
|
||||
if lt(b0, 0x80) {
|
||||
// for a single byte whose value is in the [0x00, 0x7f] range,
|
||||
// that byte is its own RLP encoding.
|
||||
dataLen := 1
|
||||
valueOffset := ptr
|
||||
leave
|
||||
}
|
||||
|
||||
// 0x80 - 0xb7, short string/bytes, length <= 55
|
||||
if lt(b0, 0xb8) {
|
||||
// the RLP encoding consists of a single byte with value 0x80
|
||||
// plus the length of the string followed by the string.
|
||||
dataLen := sub(b0, 0x80)
|
||||
valueOffset := add(ptr, 1)
|
||||
leave
|
||||
}
|
||||
|
||||
// 0xb8 - 0xbf, long string/bytes, length > 55
|
||||
if lt(b0, 0xc0) {
|
||||
// the RLP encoding consists of a single byte with value 0xb7
|
||||
// plus the length in bytes of the length of the string in binary form,
|
||||
// followed by the length of the string, followed by the string.
|
||||
let lengthBytes := sub(b0, 0xb7)
|
||||
if gt(lengthBytes, 4) {
|
||||
invalid()
|
||||
}
|
||||
|
||||
// load the extended length
|
||||
valueOffset := add(ptr, 1)
|
||||
let extendedLen := calldataload(valueOffset)
|
||||
let bits := sub(256, mul(lengthBytes, 8))
|
||||
extendedLen := shr(bits, extendedLen)
|
||||
|
||||
dataLen := extendedLen
|
||||
valueOffset := add(valueOffset, lengthBytes)
|
||||
leave
|
||||
}
|
||||
|
||||
revertWith("Not value")
|
||||
}
|
||||
|
||||
let ptr := _blockHeaderRLP.offset
|
||||
let headerPayloadLength
|
||||
{
|
||||
let b0 := byte(0, calldataload(ptr))
|
||||
// the input should be a long list
|
||||
if lt(b0, 0xf8) {
|
||||
invalid()
|
||||
}
|
||||
let lengthBytes := sub(b0, 0xf7)
|
||||
if gt(lengthBytes, 32) {
|
||||
invalid()
|
||||
}
|
||||
// load the extended length
|
||||
ptr := add(ptr, 1)
|
||||
headerPayloadLength := calldataload(ptr)
|
||||
let bits := sub(256, mul(lengthBytes, 8))
|
||||
// compute payload length: extended length + length bytes + 1
|
||||
headerPayloadLength := shr(bits, headerPayloadLength)
|
||||
headerPayloadLength := add(headerPayloadLength, lengthBytes)
|
||||
headerPayloadLength := add(headerPayloadLength, 1)
|
||||
ptr := add(ptr, lengthBytes)
|
||||
}
|
||||
|
||||
let memPtr := mload(0x40)
|
||||
calldatacopy(memPtr, _blockHeaderRLP.offset, headerPayloadLength)
|
||||
let _computedBlockHash := keccak256(memPtr, headerPayloadLength)
|
||||
require(eq(_blockHash, _computedBlockHash), "Block hash mismatch")
|
||||
|
||||
// load 16 vaules
|
||||
for {
|
||||
let i := 0
|
||||
} lt(i, 16) {
|
||||
i := add(i, 1)
|
||||
} {
|
||||
let len, offset := decodeValue(ptr)
|
||||
// the value we care must have at most 32 bytes
|
||||
if lt(len, 33) {
|
||||
let bits := mul(sub(32, len), 8)
|
||||
let value := calldataload(offset)
|
||||
value := shr(bits, value)
|
||||
mstore(memPtr, value)
|
||||
}
|
||||
memPtr := add(memPtr, 0x20)
|
||||
ptr := add(len, offset)
|
||||
}
|
||||
require(eq(ptr, add(_blockHeaderRLP.offset, _blockHeaderRLP.length)), "Header RLP length mismatch")
|
||||
|
||||
memPtr := mload(0x40)
|
||||
// load parent hash, 1-st entry
|
||||
_parentHash := mload(memPtr)
|
||||
// load state root, 4-th entry
|
||||
_stateRoot := mload(add(memPtr, 0x60))
|
||||
// load block height, 9-th entry
|
||||
_height := mload(add(memPtr, 0x100))
|
||||
// load block timestamp, 12-th entry
|
||||
_timestamp := mload(add(memPtr, 0x160))
|
||||
// load base fee, 16-th entry
|
||||
_baseFee := mload(add(memPtr, 0x1e0))
|
||||
}
|
||||
require(stateRoot[_parentHash] != bytes32(0), "Parent not imported");
|
||||
BlockMetadata memory _parentMetadata = metadata[_parentHash];
|
||||
require(_parentMetadata.height + 1 == _height, "Block height mismatch");
|
||||
require(_parentMetadata.timestamp <= _timestamp, "Parent block has larger timestamp");
|
||||
|
||||
latestBlockHash = _blockHash;
|
||||
stateRoot[_blockHash] = _stateRoot;
|
||||
metadata[_blockHash] = BlockMetadata(_height, _timestamp, _baseFee);
|
||||
|
||||
emit ImportBlock(_blockHash, _height, _timestamp, _baseFee, _stateRoot);
|
||||
|
||||
if (_updateGasPriceOracle) {
|
||||
IL1GasPriceOracle(ScrollPredeploy.L1_GAS_PRICE_ORACLE).setL1BaseFee(_baseFee);
|
||||
}
|
||||
}
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
/// @notice Update whitelist contract.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
function updateWhitelist(address _newWhitelist) external onlyOwner {
|
||||
address _oldWhitelist = address(whitelist);
|
||||
|
||||
whitelist = IWhitelist(_newWhitelist);
|
||||
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,133 +2,133 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { OwnableBase } from "../../libraries/common/OwnableBase.sol";
|
||||
import { IWhitelist } from "../../libraries/common/IWhitelist.sol";
|
||||
import {OwnableBase} from "../../libraries/common/OwnableBase.sol";
|
||||
import {IWhitelist} from "../../libraries/common/IWhitelist.sol";
|
||||
|
||||
import { IL1BlockContainer } from "./IL1BlockContainer.sol";
|
||||
import { IL1GasPriceOracle } from "./IL1GasPriceOracle.sol";
|
||||
import {IL1BlockContainer} from "./IL1BlockContainer.sol";
|
||||
import {IL1GasPriceOracle} from "./IL1GasPriceOracle.sol";
|
||||
|
||||
contract L1GasPriceOracle is OwnableBase, IL1GasPriceOracle {
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
/**********
|
||||
* Events *
|
||||
**********/
|
||||
|
||||
/// @notice Emitted when owner updates whitelist contract.
|
||||
/// @param _oldWhitelist The address of old whitelist contract.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
event UpdateWhitelist(address _oldWhitelist, address _newWhitelist);
|
||||
/// @notice Emitted when owner updates whitelist contract.
|
||||
/// @param _oldWhitelist The address of old whitelist contract.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
event UpdateWhitelist(address _oldWhitelist, address _newWhitelist);
|
||||
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
/*************
|
||||
* Constants *
|
||||
*************/
|
||||
|
||||
/// @dev The precision used in the scalar.
|
||||
uint256 private constant PRECISION = 1e9;
|
||||
/// @dev The precision used in the scalar.
|
||||
uint256 private constant PRECISION = 1e9;
|
||||
|
||||
/// @dev The maximum possible l1 fee overhead.
|
||||
/// Computed based on current l1 block gas limit.
|
||||
uint256 private constant MAX_OVERHEAD = 30000000 / 16;
|
||||
/// @dev The maximum possible l1 fee overhead.
|
||||
/// Computed based on current l1 block gas limit.
|
||||
uint256 private constant MAX_OVERHEAD = 30000000 / 16;
|
||||
|
||||
/// @dev The maximum possible l1 fee scale.
|
||||
/// x1000 should be enough.
|
||||
uint256 private constant MAX_SCALE = 1000 * PRECISION;
|
||||
/// @dev The maximum possible l1 fee scale.
|
||||
/// x1000 should be enough.
|
||||
uint256 private constant MAX_SCALE = 1000 * PRECISION;
|
||||
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
/*************
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
uint256 public l1BaseFee;
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
uint256 public l1BaseFee;
|
||||
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
uint256 public override overhead;
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
uint256 public override overhead;
|
||||
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
uint256 public override scalar;
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
uint256 public override scalar;
|
||||
|
||||
/// @notice The address of whitelist contract.
|
||||
IWhitelist public whitelist;
|
||||
/// @notice The address of whitelist contract.
|
||||
IWhitelist public whitelist;
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
constructor(address _owner) {
|
||||
_transferOwnership(_owner);
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
function getL1Fee(bytes memory _data) external view override returns (uint256) {
|
||||
uint256 _l1GasUsed = getL1GasUsed(_data);
|
||||
uint256 _l1Fee = _l1GasUsed * l1BaseFee;
|
||||
return (_l1Fee * scalar) / PRECISION;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
/// @dev See the comments in `OVM_GasPriceOracle1` for more details
|
||||
/// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol
|
||||
function getL1GasUsed(bytes memory _data) public view override returns (uint256) {
|
||||
uint256 _total = 0;
|
||||
uint256 _length = _data.length;
|
||||
unchecked {
|
||||
for (uint256 i = 0; i < _length; i++) {
|
||||
if (_data[i] == 0) {
|
||||
_total += 4;
|
||||
} else {
|
||||
_total += 16;
|
||||
}
|
||||
}
|
||||
uint256 _unsigned = _total + overhead;
|
||||
return _unsigned + (68 * 16);
|
||||
constructor(address _owner) {
|
||||
_transferOwnership(_owner);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Public Mutated Functions *
|
||||
****************************/
|
||||
/*************************
|
||||
* Public View Functions *
|
||||
*************************/
|
||||
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
function setL1BaseFee(uint256 _l1BaseFee) external override {
|
||||
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
function getL1Fee(bytes memory _data) external view override returns (uint256) {
|
||||
uint256 _l1GasUsed = getL1GasUsed(_data);
|
||||
uint256 _l1Fee = _l1GasUsed * l1BaseFee;
|
||||
return (_l1Fee * scalar) / PRECISION;
|
||||
}
|
||||
|
||||
l1BaseFee = _l1BaseFee;
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
/// @dev See the comments in `OVM_GasPriceOracle1` for more details
|
||||
/// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol
|
||||
function getL1GasUsed(bytes memory _data) public view override returns (uint256) {
|
||||
uint256 _total = 0;
|
||||
uint256 _length = _data.length;
|
||||
unchecked {
|
||||
for (uint256 i = 0; i < _length; i++) {
|
||||
if (_data[i] == 0) {
|
||||
_total += 4;
|
||||
} else {
|
||||
_total += 16;
|
||||
}
|
||||
}
|
||||
uint256 _unsigned = _total + overhead;
|
||||
return _unsigned + (68 * 16);
|
||||
}
|
||||
}
|
||||
|
||||
emit L1BaseFeeUpdated(_l1BaseFee);
|
||||
}
|
||||
/*****************************
|
||||
* Public Mutating Functions *
|
||||
*****************************/
|
||||
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
/// @inheritdoc IL1GasPriceOracle
|
||||
function setL1BaseFee(uint256 _l1BaseFee) external override {
|
||||
require(whitelist.isSenderAllowed(msg.sender), "Not whitelisted sender");
|
||||
|
||||
/// @notice Allows the owner to modify the overhead.
|
||||
/// @param _overhead New overhead
|
||||
function setOverhead(uint256 _overhead) external onlyOwner {
|
||||
require(_overhead <= MAX_OVERHEAD, "exceed maximum overhead");
|
||||
l1BaseFee = _l1BaseFee;
|
||||
|
||||
overhead = _overhead;
|
||||
emit OverheadUpdated(_overhead);
|
||||
}
|
||||
emit L1BaseFeeUpdated(_l1BaseFee);
|
||||
}
|
||||
|
||||
/// Allows the owner to modify the scalar.
|
||||
/// @param _scalar New scalar
|
||||
function setScalar(uint256 _scalar) external onlyOwner {
|
||||
require(_scalar <= MAX_SCALE, "exceed maximum scale");
|
||||
/************************
|
||||
* Restricted Functions *
|
||||
************************/
|
||||
|
||||
scalar = _scalar;
|
||||
emit ScalarUpdated(_scalar);
|
||||
}
|
||||
/// @notice Allows the owner to modify the overhead.
|
||||
/// @param _overhead New overhead
|
||||
function setOverhead(uint256 _overhead) external onlyOwner {
|
||||
require(_overhead <= MAX_OVERHEAD, "exceed maximum overhead");
|
||||
|
||||
/// @notice Update whitelist contract.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
function updateWhitelist(address _newWhitelist) external onlyOwner {
|
||||
address _oldWhitelist = address(whitelist);
|
||||
overhead = _overhead;
|
||||
emit OverheadUpdated(_overhead);
|
||||
}
|
||||
|
||||
whitelist = IWhitelist(_newWhitelist);
|
||||
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
|
||||
}
|
||||
/// Allows the owner to modify the scalar.
|
||||
/// @param _scalar New scalar
|
||||
function setScalar(uint256 _scalar) external onlyOwner {
|
||||
require(_scalar <= MAX_SCALE, "exceed maximum scale");
|
||||
|
||||
scalar = _scalar;
|
||||
emit ScalarUpdated(_scalar);
|
||||
}
|
||||
|
||||
/// @notice Update whitelist contract.
|
||||
/// @dev This function can only called by contract owner.
|
||||
/// @param _newWhitelist The address of new whitelist contract.
|
||||
function updateWhitelist(address _newWhitelist) external onlyOwner {
|
||||
address _oldWhitelist = address(whitelist);
|
||||
|
||||
whitelist = IWhitelist(_newWhitelist);
|
||||
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user