Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
0bc53656
Unverified
Commit
0bc53656
authored
Feb 01, 2022
by
Matthew Slipper
Committed by
GitHub
Feb 01, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into feat/bring-back-unsupported-rpcs
parents
81d90563
40ffd24d
Changes
41
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
1556 additions
and
473 deletions
+1556
-473
afraid-otters-repeat.md
.changeset/afraid-otters-repeat.md
+5
-0
cool-starfishes-peel.md
.changeset/cool-starfishes-peel.md
+5
-0
famous-wombats-exercise.md
.changeset/famous-wombats-exercise.md
+5
-0
forty-dancers-try.md
.changeset/forty-dancers-try.md
+5
-0
green-donuts-bathe.md
.changeset/green-donuts-bathe.md
+5
-0
quick-drinks-tease.md
.changeset/quick-drinks-tease.md
+5
-0
smooth-bags-applaud.md
.changeset/smooth-bags-applaud.md
+5
-0
.dockerignore
.dockerignore
+2
-0
FakeL2StandardERC20.sol
integration-tests/contracts/FakeL2StandardERC20.sol
+14
-0
bridged-tokens.spec.ts
integration-tests/test/bridged-tokens.spec.ts
+54
-0
env.ts
integration-tests/test/shared/env.ts
+4
-0
utils.ts
integration-tests/test/shared/utils.ts
+11
-1
verifier.spec.ts
integration-tests/test/verifier.spec.ts
+103
-0
worker.go
l2geth/miner/worker.go
+1
-12
sync_service.go
l2geth/rollup/sync_service.go
+3
-2
docker-compose.yml
ops/docker-compose.yml
+3
-1
Dockerfile.batch-submitter-service
ops/docker/Dockerfile.batch-submitter-service
+2
-2
dtl.env
ops/envs/dtl.env
+1
-0
transport-db.ts
packages/data-transport-layer/src/db/transport-db.ts
+43
-41
sequencer-batch-appended.ts
...ervices/l1-ingestion/handlers/sequencer-batch-appended.ts
+1
-1
service.ts
...data-transport-layer/src/services/l1-ingestion/service.ts
+3
-1
service.ts
...data-transport-layer/src/services/l2-ingestion/service.ts
+3
-1
service.ts
packages/data-transport-layer/src/services/main/service.ts
+1
-0
run.ts
packages/data-transport-layer/src/services/run.ts
+1
-0
service.ts
packages/data-transport-layer/src/services/server/service.ts
+4
-1
dai-bridge.ts
packages/sdk/src/adapters/dai-bridge.ts
+63
-0
eth-bridge.ts
packages/sdk/src/adapters/eth-bridge.ts
+142
-0
index.ts
packages/sdk/src/adapters/index.ts
+3
-0
standard-bridge.ts
packages/sdk/src/adapters/standard-bridge.ts
+308
-0
cross-chain-messenger.ts
packages/sdk/src/cross-chain-messenger.ts
+124
-24
cross-chain-provider.ts
packages/sdk/src/cross-chain-provider.ts
+54
-115
index.ts
packages/sdk/src/index.ts
+1
-0
bridge-adapter.ts
packages/sdk/src/interfaces/bridge-adapter.ts
+239
-0
cross-chain-messenger.ts
packages/sdk/src/interfaces/cross-chain-messenger.ts
+132
-7
cross-chain-provider.ts
packages/sdk/src/interfaces/cross-chain-provider.ts
+16
-6
index.ts
packages/sdk/src/interfaces/index.ts
+1
-1
types.ts
packages/sdk/src/interfaces/types.ts
+15
-14
contracts.ts
packages/sdk/src/utils/contracts.ts
+115
-83
cross-chain-erc20-pair.spec.ts
packages/sdk/test/cross-chain-erc20-pair.spec.ts
+0
-95
cross-chain-messenger.spec.ts
packages/sdk/test/cross-chain-messenger.spec.ts
+39
-0
cross-chain-provider.spec.ts
packages/sdk/test/cross-chain-provider.spec.ts
+15
-65
No files found.
.changeset/afraid-otters-repeat.md
0 → 100644
View file @
0bc53656
---
'
@eth-optimism/integration-tests'
:
patch
---
Increase withdrawal test timeout
.changeset/cool-starfishes-peel.md
0 → 100644
View file @
0bc53656
---
'
@eth-optimism/data-transport-layer'
:
patch
---
Updates DTL to correctly parse L1 to L2 tx timestamps after the first bss hardfork
.changeset/famous-wombats-exercise.md
0 → 100644
View file @
0bc53656
---
'
@eth-optimism/integration-tests'
:
patch
---
Add an integration test showing the infeasability of withdrawing a fake token in exchange for a legitimate token.
.changeset/forty-dancers-try.md
0 → 100644
View file @
0bc53656
---
'
@eth-optimism/integration-tests'
:
patch
---
Updates integration tests to include a test for syncing a Verifier from L1
.changeset/green-donuts-bathe.md
0 → 100644
View file @
0bc53656
---
'
@eth-optimism/l2geth'
:
patch
---
Fixes incorrect timestamp handling for L1 syncing verifiers
.changeset/quick-drinks-tease.md
0 → 100644
View file @
0bc53656
---
'
@eth-optimism/batch-submitter'
:
patch
---
Updates batch submitter to also include separate timestamps for deposit transactions"
.changeset/smooth-bags-applaud.md
0 → 100644
View file @
0bc53656
---
'
@eth-optimism/integration-tests'
:
patch
---
Add verifier integration tests
.dockerignore
View file @
0bc53656
.github
.github
node_modules
node_modules
.env
**/.env
test
test
**/*_test.go
**/*_test.go
...
...
integration-tests/contracts/FakeL2StandardERC20.sol
0 → 100644
View file @
0bc53656
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract FakeL2StandardERC20 {
address public immutable l1Token;
constructor(address _l1Token) {
l1Token = _l1Token;
}
// Burn will be called by the L2 Bridge to burn the tokens we are bridging to L1
function burn(address, uint256) external {}
}
integration-tests/test/bridged-tokens.spec.ts
View file @
0bc53656
...
@@ -127,4 +127,58 @@ describe('Bridged tokens', () => {
...
@@ -127,4 +127,58 @@ describe('Bridged tokens', () => {
)
)
}
}
)
)
// This test demonstrates that an apparent withdrawal bug is in fact non-existent.
// Specifically, the L2 bridge does not check that the L2 token being burned corresponds
// with the L1 token which is specified for the withdrawal.
withdrawalTest
(
'
should not allow an arbitrary L2 token to be withdrawn in exchange for a legitimate L1 token
'
,
async
()
=>
{
before
(
async
()
=>
{
// First deposit some of the L1 token to L2, so that there is something which could be stolen.
const
depositTx
=
await
env
.
l1Bridge
.
connect
(
env
.
l1Wallet
)
.
depositERC20
(
L1__ERC20
.
address
,
L2__ERC20
.
address
,
1000
,
2000000
,
'
0x
'
)
await
env
.
waitForXDomainTransaction
(
depositTx
,
Direction
.
L1ToL2
)
expect
(
await
L2__ERC20
.
balanceOf
(
env
.
l2Wallet
.
address
)).
to
.
deep
.
equal
(
BigNumber
.
from
(
1000
)
)
})
// Deploy a Fake L2 token, which:
// - returns the address of a legitimate L1 token from its l1Token() getter.
// - allows the L2 bridge to call its burn() function.
const
fakeToken
=
await
(
await
ethers
.
getContractFactory
(
'
FakeL2StandardERC20
'
,
env
.
l2Wallet
)
).
deploy
(
L1__ERC20
.
address
)
await
fakeToken
.
deployed
()
const
balBefore
=
await
L1__ERC20
.
balanceOf
(
otherWalletL1
.
address
)
// Withdraw some of the Fake L2 token, hoping to receive the same amount of the legitimate
// token on L1.
const
withdrawalTx
=
await
env
.
l2Bridge
.
connect
(
otherWalletL2
)
.
withdrawTo
(
fakeToken
.
address
,
otherWalletL1
.
address
,
500
,
1
_000_000
,
'
0x
'
)
await
env
.
relayXDomainMessages
(
withdrawalTx
)
await
env
.
waitForXDomainTransaction
(
withdrawalTx
,
Direction
.
L2ToL1
)
// Ensure that the L1 recipient address has not received any additional L1 token balance.
expect
(
await
L1__ERC20
.
balanceOf
(
otherWalletL1
.
address
)).
to
.
deep
.
equal
(
balBefore
)
}
)
})
})
integration-tests/test/shared/env.ts
View file @
0bc53656
...
@@ -11,6 +11,7 @@ import {
...
@@ -11,6 +11,7 @@ import {
l1Provider
,
l1Provider
,
l2Provider
,
l2Provider
,
replicaProvider
,
replicaProvider
,
verifierProvider
,
l1Wallet
,
l1Wallet
,
l2Wallet
,
l2Wallet
,
gasPriceOracleWallet
,
gasPriceOracleWallet
,
...
@@ -57,6 +58,7 @@ export class OptimismEnv {
...
@@ -57,6 +58,7 @@ export class OptimismEnv {
l1Provider
:
providers
.
JsonRpcProvider
l1Provider
:
providers
.
JsonRpcProvider
l2Provider
:
providers
.
JsonRpcProvider
l2Provider
:
providers
.
JsonRpcProvider
replicaProvider
:
providers
.
JsonRpcProvider
replicaProvider
:
providers
.
JsonRpcProvider
verifierProvider
:
providers
.
JsonRpcProvider
constructor
(
args
:
any
)
{
constructor
(
args
:
any
)
{
this
.
addressManager
=
args
.
addressManager
this
.
addressManager
=
args
.
addressManager
...
@@ -74,6 +76,7 @@ export class OptimismEnv {
...
@@ -74,6 +76,7 @@ export class OptimismEnv {
this
.
l1Provider
=
args
.
l1Provider
this
.
l1Provider
=
args
.
l1Provider
this
.
l2Provider
=
args
.
l2Provider
this
.
l2Provider
=
args
.
l2Provider
this
.
replicaProvider
=
args
.
replicaProvider
this
.
replicaProvider
=
args
.
replicaProvider
this
.
verifierProvider
=
args
.
verifierProvider
this
.
ctc
=
args
.
ctc
this
.
ctc
=
args
.
ctc
this
.
scc
=
args
.
scc
this
.
scc
=
args
.
scc
}
}
...
@@ -140,6 +143,7 @@ export class OptimismEnv {
...
@@ -140,6 +143,7 @@ export class OptimismEnv {
l2Wallet
,
l2Wallet
,
l1Provider
,
l1Provider
,
l2Provider
,
l2Provider
,
verifierProvider
,
replicaProvider
,
replicaProvider
,
})
})
}
}
...
...
integration-tests/test/shared/utils.ts
View file @
0bc53656
...
@@ -62,6 +62,8 @@ const procEnv = cleanEnv(process.env, {
...
@@ -62,6 +62,8 @@ const procEnv = cleanEnv(process.env, {
REPLICA_URL
:
str
({
default
:
'
http://localhost:8549
'
}),
REPLICA_URL
:
str
({
default
:
'
http://localhost:8549
'
}),
REPLICA_POLLING_INTERVAL
:
num
({
default
:
10
}),
REPLICA_POLLING_INTERVAL
:
num
({
default
:
10
}),
VERIFIER_URL
:
str
({
default
:
'
http://localhost:8547
'
}),
PRIVATE_KEY
:
str
({
PRIVATE_KEY
:
str
({
default
:
default
:
'
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
'
,
'
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
'
,
...
@@ -96,6 +98,9 @@ const procEnv = cleanEnv(process.env, {
...
@@ -96,6 +98,9 @@ const procEnv = cleanEnv(process.env, {
RUN_NIGHTLY_TESTS
:
bool
({
RUN_NIGHTLY_TESTS
:
bool
({
default
:
false
,
default
:
false
,
}),
}),
RUN_VERIFIER_TESTS
:
bool
({
default
:
true
,
}),
MOCHA_TIMEOUT
:
num
({
MOCHA_TIMEOUT
:
num
({
default
:
120
_000
,
default
:
120
_000
,
...
@@ -121,6 +126,11 @@ export const replicaProvider = injectL2Context(
...
@@ -121,6 +126,11 @@ export const replicaProvider = injectL2Context(
)
)
replicaProvider
.
pollingInterval
=
procEnv
.
REPLICA_POLLING_INTERVAL
replicaProvider
.
pollingInterval
=
procEnv
.
REPLICA_POLLING_INTERVAL
export
const
verifierProvider
=
injectL2Context
(
new
providers
.
JsonRpcProvider
(
procEnv
.
VERIFIER_URL
)
)
verifierProvider
.
pollingInterval
=
procEnv
.
L2_POLLING_INTERVAL
// The sequencer private key which is funded on L1
// The sequencer private key which is funded on L1
export
const
l1Wallet
=
new
Wallet
(
procEnv
.
PRIVATE_KEY
,
l1Provider
)
export
const
l1Wallet
=
new
Wallet
(
procEnv
.
PRIVATE_KEY
,
l1Provider
)
...
@@ -210,7 +220,7 @@ export const conditionalTest = (
...
@@ -210,7 +220,7 @@ export const conditionalTest = (
}
}
await
fn
()
await
fn
()
}).
timeout
(
timeout
||
envConfig
.
MOCHA_TIMEOUT
)
}).
timeout
(
timeout
||
envConfig
.
MOCHA_TIMEOUT
*
2
)
}
}
export
const
withdrawalTest
=
(
name
,
fn
,
timeout
?:
number
)
=>
export
const
withdrawalTest
=
(
name
,
fn
,
timeout
?:
number
)
=>
...
...
integration-tests/test/verifier.spec.ts
0 → 100644
View file @
0bc53656
import
{
TransactionReceipt
}
from
'
@ethersproject/abstract-provider
'
import
{
expect
}
from
'
./shared/setup
'
import
{
OptimismEnv
}
from
'
./shared/env
'
import
{
defaultTransactionFactory
,
gasPriceForL2
,
sleep
,
envConfig
,
}
from
'
./shared/utils
'
describe
(
'
Verifier Tests
'
,
()
=>
{
let
env
:
OptimismEnv
before
(
async
function
()
{
if
(
!
envConfig
.
RUN_VERIFIER_TESTS
)
{
this
.
skip
()
return
}
env
=
await
OptimismEnv
.
new
()
})
describe
(
'
Matching blocks
'
,
()
=>
{
it
(
'
should sync a transaction
'
,
async
()
=>
{
const
tx
=
defaultTransactionFactory
()
tx
.
gasPrice
=
await
gasPriceForL2
()
const
result
=
await
env
.
l2Wallet
.
sendTransaction
(
tx
)
let
receipt
:
TransactionReceipt
while
(
!
receipt
)
{
receipt
=
await
env
.
verifierProvider
.
getTransactionReceipt
(
result
.
hash
)
await
sleep
(
200
)
}
const
sequencerBlock
=
(
await
env
.
l2Provider
.
getBlock
(
result
.
blockNumber
))
as
any
const
verifierBlock
=
(
await
env
.
verifierProvider
.
getBlock
(
result
.
blockNumber
))
as
any
expect
(
sequencerBlock
.
stateRoot
).
to
.
deep
.
eq
(
verifierBlock
.
stateRoot
)
expect
(
sequencerBlock
.
hash
).
to
.
deep
.
eq
(
verifierBlock
.
hash
)
})
it
(
'
sync an unprotected tx (eip155)
'
,
async
()
=>
{
const
tx
=
{
...
defaultTransactionFactory
(),
nonce
:
await
env
.
l2Wallet
.
getTransactionCount
(),
gasPrice
:
await
gasPriceForL2
(),
chainId
:
null
,
// Disables EIP155 transaction signing.
}
const
signed
=
await
env
.
l2Wallet
.
signTransaction
(
tx
)
const
result
=
await
env
.
l2Provider
.
sendTransaction
(
signed
)
let
receipt
:
TransactionReceipt
while
(
!
receipt
)
{
receipt
=
await
env
.
verifierProvider
.
getTransactionReceipt
(
result
.
hash
)
await
sleep
(
200
)
}
const
sequencerBlock
=
(
await
env
.
l2Provider
.
getBlock
(
result
.
blockNumber
))
as
any
const
verifierBlock
=
(
await
env
.
verifierProvider
.
getBlock
(
result
.
blockNumber
))
as
any
expect
(
sequencerBlock
.
stateRoot
).
to
.
deep
.
eq
(
verifierBlock
.
stateRoot
)
expect
(
sequencerBlock
.
hash
).
to
.
deep
.
eq
(
verifierBlock
.
hash
)
})
it
(
'
should forward tx to sequencer
'
,
async
()
=>
{
const
tx
=
{
...
defaultTransactionFactory
(),
nonce
:
await
env
.
l2Wallet
.
getTransactionCount
(),
gasPrice
:
await
gasPriceForL2
(),
}
const
signed
=
await
env
.
l2Wallet
.
signTransaction
(
tx
)
const
result
=
await
env
.
verifierProvider
.
sendTransaction
(
signed
)
let
receipt
:
TransactionReceipt
while
(
!
receipt
)
{
receipt
=
await
env
.
verifierProvider
.
getTransactionReceipt
(
result
.
hash
)
await
sleep
(
200
)
}
const
sequencerBlock
=
(
await
env
.
l2Provider
.
getBlock
(
result
.
blockNumber
))
as
any
const
verifierBlock
=
(
await
env
.
verifierProvider
.
getBlock
(
result
.
blockNumber
))
as
any
expect
(
sequencerBlock
.
stateRoot
).
to
.
deep
.
eq
(
verifierBlock
.
stateRoot
)
expect
(
sequencerBlock
.
hash
).
to
.
deep
.
eq
(
verifierBlock
.
hash
)
})
})
})
l2geth/miner/worker.go
View file @
0bc53656
...
@@ -931,18 +931,7 @@ func (w *worker) commitNewTx(tx *types.Transaction) error {
...
@@ -931,18 +931,7 @@ func (w *worker) commitNewTx(tx *types.Transaction) error {
// Preserve liveliness as best as possible. Must panic on L1 to L2
// Preserve liveliness as best as possible. Must panic on L1 to L2
// transactions as the timestamp cannot be malleated
// transactions as the timestamp cannot be malleated
if
parent
.
Time
()
>
tx
.
L1Timestamp
()
{
if
parent
.
Time
()
>
tx
.
L1Timestamp
()
{
log
.
Error
(
"Monotonicity violation"
,
"index"
,
num
)
log
.
Error
(
"Monotonicity violation"
,
"index"
,
num
,
"parent"
,
parent
.
Time
(),
"tx"
,
tx
.
L1Timestamp
())
if
tx
.
QueueOrigin
()
==
types
.
QueueOriginSequencer
{
tx
.
SetL1Timestamp
(
parent
.
Time
())
prev
:=
parent
.
Transactions
()
if
len
(
prev
)
==
1
{
tx
.
SetL1BlockNumber
(
prev
[
0
]
.
L1BlockNumber
()
.
Uint64
())
}
else
{
log
.
Error
(
"Cannot recover L1 Blocknumber"
)
}
}
else
{
log
.
Error
(
"Cannot recover from monotonicity violation"
)
}
}
}
// Fill in the index field in the tx meta if it is `nil`.
// Fill in the index field in the tx meta if it is `nil`.
...
...
l2geth/rollup/sync_service.go
View file @
0bc53656
...
@@ -825,13 +825,14 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
...
@@ -825,13 +825,14 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
if
now
.
Sub
(
current
)
>
s
.
timestampRefreshThreshold
{
if
now
.
Sub
(
current
)
>
s
.
timestampRefreshThreshold
{
current
=
now
current
=
now
}
}
log
.
Info
(
"Updating latest timestamp"
,
"timestamp"
,
current
,
"unix"
,
current
.
Unix
())
tx
.
SetL1Timestamp
(
uint64
(
current
.
Unix
()))
tx
.
SetL1Timestamp
(
uint64
(
current
.
Unix
()))
}
else
if
tx
.
L1Timestamp
()
==
0
&&
s
.
verifier
{
}
else
if
tx
.
L1Timestamp
()
==
0
&&
s
.
verifier
{
// This should never happen
// This should never happen
log
.
Error
(
"No tx timestamp found when running as verifier"
,
"hash"
,
tx
.
Hash
()
.
Hex
())
log
.
Error
(
"No tx timestamp found when running as verifier"
,
"hash"
,
tx
.
Hash
()
.
Hex
())
}
else
if
tx
.
L1Timestamp
()
<
s
.
GetLatestL1Timestamp
()
{
}
else
if
tx
.
L1Timestamp
()
<
ts
{
// This should never happen, but sometimes does
// This should never happen, but sometimes does
log
.
Error
(
"Timestamp monotonicity violation"
,
"hash"
,
tx
.
Hash
()
.
Hex
())
log
.
Error
(
"Timestamp monotonicity violation"
,
"hash"
,
tx
.
Hash
()
.
Hex
()
,
"latest"
,
ts
,
"tx"
,
tx
.
L1Timestamp
()
)
}
}
l1BlockNumber
:=
tx
.
L1BlockNumber
()
l1BlockNumber
:=
tx
.
L1BlockNumber
()
...
...
ops/docker-compose.yml
View file @
0bc53656
...
@@ -136,8 +136,9 @@ services:
...
@@ -136,8 +136,9 @@ services:
-
l1_chain
-
l1_chain
-
deployer
-
deployer
-
dtl
-
dtl
-
l2geth
deploy
:
deploy
:
replicas
:
0
replicas
:
1
build
:
build
:
context
:
..
context
:
..
dockerfile
:
./ops/docker/Dockerfile.geth
dockerfile
:
./ops/docker/Dockerfile.geth
...
@@ -146,6 +147,7 @@ services:
...
@@ -146,6 +147,7 @@ services:
-
./envs/geth.env
-
./envs/geth.env
environment
:
environment
:
ETH1_HTTP
:
http://l1_chain:8545
ETH1_HTTP
:
http://l1_chain:8545
SEQUENCER_CLIENT_HTTP
:
http://l2geth:8545
ROLLUP_STATE_DUMP_PATH
:
http://deployer:8081/state-dump.latest.json
ROLLUP_STATE_DUMP_PATH
:
http://deployer:8081/state-dump.latest.json
ROLLUP_CLIENT_HTTP
:
http://dtl:7878
ROLLUP_CLIENT_HTTP
:
http://dtl:7878
ROLLUP_BACKEND
:
'
l1'
ROLLUP_BACKEND
:
'
l1'
...
...
ops/docker/Dockerfile.batch-submitter-service
View file @
0bc53656
FROM golang:1.17.
6-alpine3.15
as builder
FROM golang:1.17.
3-alpine3.13
as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
...
@@ -9,7 +9,7 @@ RUN go mod graph | grep -v l2geth | awk '{if ($1 !~ "@") print $2}' | xargs -n 1
...
@@ -9,7 +9,7 @@ RUN go mod graph | grep -v l2geth | awk '{if ($1 !~ "@") print $2}' | xargs -n 1
COPY ./go/batch-submitter/ ./
COPY ./go/batch-submitter/ ./
RUN make
RUN make
FROM alpine:3.1
5
FROM alpine:3.1
3
RUN apk add --no-cache ca-certificates jq curl
RUN apk add --no-cache ca-certificates jq curl
COPY --from=builder /go/batch-submitter/batch-submitter /usr/local/bin/
COPY --from=builder /go/batch-submitter/batch-submitter /usr/local/bin/
...
...
ops/envs/dtl.env
View file @
0bc53656
...
@@ -9,6 +9,7 @@ DATA_TRANSPORT_LAYER__LOGS_PER_POLLING_INTERVAL=2000
...
@@ -9,6 +9,7 @@ DATA_TRANSPORT_LAYER__LOGS_PER_POLLING_INTERVAL=2000
DATA_TRANSPORT_LAYER__DANGEROUSLY_CATCH_ALL_ERRORS=true
DATA_TRANSPORT_LAYER__DANGEROUSLY_CATCH_ALL_ERRORS=true
DATA_TRANSPORT_LAYER__SERVER_HOSTNAME=0.0.0.0
DATA_TRANSPORT_LAYER__SERVER_HOSTNAME=0.0.0.0
DATA_TRANSPORT_LAYER__L1_START_HEIGHT=1
DATA_TRANSPORT_LAYER__L1_START_HEIGHT=1
DATA_TRANSPORT_LAYER__BSS_HARDFORK_1_INDEX=0
DATA_TRANSPORT_LAYER__ADDRESS_MANAGER=
DATA_TRANSPORT_LAYER__ADDRESS_MANAGER=
DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT=
DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT=
...
...
packages/data-transport-layer/src/db/transport-db.ts
View file @
0bc53656
...
@@ -31,11 +31,17 @@ interface Indexed {
...
@@ -31,11 +31,17 @@ interface Indexed {
index
:
number
index
:
number
}
}
interface
ExtraTransportDBOptions
{
bssHardfork1Index
?:
number
}
export
class
TransportDB
{
export
class
TransportDB
{
public
db
:
SimpleDB
public
db
:
SimpleDB
public
opts
:
ExtraTransportDBOptions
constructor
(
leveldb
:
LevelUp
)
{
constructor
(
leveldb
:
LevelUp
,
opts
?:
ExtraTransportDBOptions
)
{
this
.
db
=
new
SimpleDB
(
leveldb
)
this
.
db
=
new
SimpleDB
(
leveldb
)
this
.
opts
=
opts
||
{}
}
}
public
async
putEnqueueEntries
(
entries
:
EnqueueEntry
[]):
Promise
<
void
>
{
public
async
putEnqueueEntries
(
entries
:
EnqueueEntry
[]):
Promise
<
void
>
{
...
@@ -254,26 +260,7 @@ export class TransportDB {
...
@@ -254,26 +260,7 @@ export class TransportDB {
return
null
return
null
}
}
if
(
transaction
.
queueOrigin
===
'
l1
'
)
{
return
this
.
_makeFullTransaction
(
transaction
)
const
enqueue
=
await
this
.
getEnqueueByIndex
(
transaction
.
queueIndex
)
if
(
enqueue
===
null
)
{
return
null
}
return
{
...
transaction
,
...{
blockNumber
:
enqueue
.
blockNumber
,
timestamp
:
enqueue
.
timestamp
,
gasLimit
:
enqueue
.
gasLimit
,
target
:
enqueue
.
target
,
origin
:
enqueue
.
origin
,
data
:
enqueue
.
data
,
},
}
}
else
{
return
transaction
}
}
}
public
async
getLatestFullTransaction
():
Promise
<
TransactionEntry
>
{
public
async
getLatestFullTransaction
():
Promise
<
TransactionEntry
>
{
...
@@ -293,31 +280,46 @@ export class TransportDB {
...
@@ -293,31 +280,46 @@ export class TransportDB {
const
fullTransactions
=
[]
const
fullTransactions
=
[]
for
(
const
transaction
of
transactions
)
{
for
(
const
transaction
of
transactions
)
{
if
(
transaction
.
queueOrigin
===
'
l1
'
)
{
fullTransactions
.
push
(
await
this
.
_makeFullTransaction
(
transaction
))
const
enqueue
=
await
this
.
getEnqueueByIndex
(
transaction
.
queueIndex
)
if
(
enqueue
===
null
)
{
return
null
}
fullTransactions
.
push
({
...
transaction
,
...{
blockNumber
:
enqueue
.
blockNumber
,
timestamp
:
enqueue
.
timestamp
,
gasLimit
:
enqueue
.
gasLimit
,
target
:
enqueue
.
target
,
origin
:
enqueue
.
origin
,
data
:
enqueue
.
data
,
},
})
}
else
{
fullTransactions
.
push
(
transaction
)
}
}
}
return
fullTransactions
return
fullTransactions
}
}
private
async
_makeFullTransaction
(
transaction
:
TransactionEntry
):
Promise
<
TransactionEntry
>
{
// We only need to do extra work for L1 to L2 transactions.
if
(
transaction
.
queueOrigin
!==
'
l1
'
)
{
return
transaction
}
const
enqueue
=
await
this
.
getEnqueueByIndex
(
transaction
.
queueIndex
)
if
(
enqueue
===
null
)
{
return
null
}
let
timestamp
=
enqueue
.
timestamp
if
(
typeof
this
.
opts
.
bssHardfork1Index
===
'
number
'
&&
transaction
.
index
>=
this
.
opts
.
bssHardfork1Index
)
{
timestamp
=
transaction
.
timestamp
}
return
{
...
transaction
,
...{
blockNumber
:
enqueue
.
blockNumber
,
timestamp
,
gasLimit
:
enqueue
.
gasLimit
,
target
:
enqueue
.
target
,
origin
:
enqueue
.
origin
,
data
:
enqueue
.
data
,
},
}
}
private
async
_getLatestEntryIndex
(
key
:
string
):
Promise
<
number
>
{
private
async
_getLatestEntryIndex
(
key
:
string
):
Promise
<
number
>
{
return
this
.
db
.
get
<
number
>
(
`
${
key
}
:latest`
,
0
)
||
0
return
this
.
db
.
get
<
number
>
(
`
${
key
}
:latest`
,
0
)
||
0
}
}
...
...
packages/data-transport-layer/src/services/l1-ingestion/handlers/sequencer-batch-appended.ts
View file @
0bc53656
...
@@ -143,7 +143,7 @@ export const handleEventsSequencerBatchAppended: EventHandlerSet<
...
@@ -143,7 +143,7 @@ export const handleEventsSequencerBatchAppended: EventHandlerSet<
.
toNumber
(),
.
toNumber
(),
batchIndex
:
extraData
.
batchIndex
.
toNumber
(),
batchIndex
:
extraData
.
batchIndex
.
toNumber
(),
blockNumber
:
BigNumber
.
from
(
0
).
toNumber
(),
blockNumber
:
BigNumber
.
from
(
0
).
toNumber
(),
timestamp
:
BigNumber
.
from
(
0
).
toNumber
()
,
timestamp
:
context
.
timestamp
,
gasLimit
:
BigNumber
.
from
(
0
).
toString
(),
gasLimit
:
BigNumber
.
from
(
0
).
toString
(),
target
:
constants
.
AddressZero
,
target
:
constants
.
AddressZero
,
origin
:
constants
.
AddressZero
,
origin
:
constants
.
AddressZero
,
...
...
packages/data-transport-layer/src/services/l1-ingestion/service.ts
View file @
0bc53656
...
@@ -104,7 +104,9 @@ export class L1IngestionService extends BaseService<L1IngestionServiceOptions> {
...
@@ -104,7 +104,9 @@ export class L1IngestionService extends BaseService<L1IngestionServiceOptions> {
}
=
{}
as
any
}
=
{}
as
any
protected
async
_init
():
Promise
<
void
>
{
protected
async
_init
():
Promise
<
void
>
{
this
.
state
.
db
=
new
TransportDB
(
this
.
options
.
db
)
this
.
state
.
db
=
new
TransportDB
(
this
.
options
.
db
,
{
bssHardfork1Index
:
this
.
options
.
bssHardfork1Index
,
})
this
.
l1IngestionMetrics
=
registerMetrics
(
this
.
metrics
)
this
.
l1IngestionMetrics
=
registerMetrics
(
this
.
metrics
)
...
...
packages/data-transport-layer/src/services/l2-ingestion/service.ts
View file @
0bc53656
...
@@ -84,7 +84,9 @@ export class L2IngestionService extends BaseService<L2IngestionServiceOptions> {
...
@@ -84,7 +84,9 @@ export class L2IngestionService extends BaseService<L2IngestionServiceOptions> {
this
.
l2IngestionMetrics
=
registerMetrics
(
this
.
metrics
)
this
.
l2IngestionMetrics
=
registerMetrics
(
this
.
metrics
)
this
.
state
.
db
=
new
TransportDB
(
this
.
options
.
db
)
this
.
state
.
db
=
new
TransportDB
(
this
.
options
.
db
,
{
bssHardfork1Index
:
this
.
options
.
bssHardfork1Index
,
})
this
.
state
.
l2RpcProvider
=
this
.
state
.
l2RpcProvider
=
typeof
this
.
options
.
l2RpcProvider
===
'
string
'
typeof
this
.
options
.
l2RpcProvider
===
'
string
'
...
...
packages/data-transport-layer/src/services/main/service.ts
View file @
0bc53656
...
@@ -36,6 +36,7 @@ export interface L1DataTransportServiceOptions {
...
@@ -36,6 +36,7 @@ export interface L1DataTransportServiceOptions {
defaultBackend
:
string
defaultBackend
:
string
l1GasPriceBackend
:
string
l1GasPriceBackend
:
string
l1StartHeight
?:
number
l1StartHeight
?:
number
bssHardfork1Index
?:
number
}
}
const
optionSettings
=
{
const
optionSettings
=
{
...
...
packages/data-transport-layer/src/services/run.ts
View file @
0bc53656
...
@@ -51,6 +51,7 @@ type ethNetwork = 'mainnet' | 'kovan' | 'goerli'
...
@@ -51,6 +51,7 @@ type ethNetwork = 'mainnet' | 'kovan' | 'goerli'
useSentry
:
config
.
bool
(
'
use-sentry
'
,
false
),
useSentry
:
config
.
bool
(
'
use-sentry
'
,
false
),
sentryDsn
:
config
.
str
(
'
sentry-dsn
'
),
sentryDsn
:
config
.
str
(
'
sentry-dsn
'
),
sentryTraceRate
:
config
.
ufloat
(
'
sentry-trace-rate
'
,
0.05
),
sentryTraceRate
:
config
.
ufloat
(
'
sentry-trace-rate
'
,
0.05
),
bssHardfork1Index
:
config
.
uint
(
'
bss-hardfork-1-index
'
,
null
),
})
})
const
stop
=
async
(
signal
)
=>
{
const
stop
=
async
(
signal
)
=>
{
...
...
packages/data-transport-layer/src/services/server/service.ts
View file @
0bc53656
...
@@ -87,7 +87,10 @@ export class L1TransportServer extends BaseService<L1TransportServerOptions> {
...
@@ -87,7 +87,10 @@ export class L1TransportServer extends BaseService<L1TransportServerOptions> {
await
this
.
options
.
db
.
open
()
await
this
.
options
.
db
.
open
()
}
}
this
.
state
.
db
=
new
TransportDB
(
this
.
options
.
db
)
this
.
state
.
db
=
new
TransportDB
(
this
.
options
.
db
,
{
bssHardfork1Index
:
this
.
options
.
bssHardfork1Index
,
})
this
.
state
.
l1RpcProvider
=
this
.
state
.
l1RpcProvider
=
typeof
this
.
options
.
l1RpcProvider
===
'
string
'
typeof
this
.
options
.
l1RpcProvider
===
'
string
'
?
new
JsonRpcProvider
(
this
.
options
.
l1RpcProvider
)
?
new
JsonRpcProvider
(
this
.
options
.
l1RpcProvider
)
...
...
packages/sdk/src/adapters/dai-bridge.ts
0 → 100644
View file @
0bc53656
/* eslint-disable @typescript-eslint/no-unused-vars */
import
{
Contract
}
from
'
ethers
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
AddressLike
}
from
'
../interfaces
'
import
{
toAddress
}
from
'
../utils
'
import
{
StandardBridgeAdapter
}
from
'
./standard-bridge
'
/**
* Bridge adapter for DAI.
*/
export
class
DAIBridgeAdapter
extends
StandardBridgeAdapter
{
public
async
supportsTokenPair
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
):
Promise
<
boolean
>
{
// Just need access to this ABI for this one function.
const
l1Bridge
=
new
Contract
(
this
.
l1Bridge
.
address
,
[
{
inputs
:
[],
name
:
'
l1Token
'
,
outputs
:
[
{
internalType
:
'
address
'
,
name
:
''
,
type
:
'
address
'
,
},
],
stateMutability
:
'
view
'
,
type
:
'
function
'
,
},
{
inputs
:
[],
name
:
'
l2Token
'
,
outputs
:
[
{
internalType
:
'
address
'
,
name
:
''
,
type
:
'
address
'
,
},
],
stateMutability
:
'
view
'
,
type
:
'
function
'
,
},
],
this
.
provider
.
l1Provider
)
const
allowedL1Token
=
await
l1Bridge
.
l1Token
()
if
(
!
hexStringEquals
(
allowedL1Token
,
toAddress
(
l1Token
)))
{
return
false
}
const
allowedL2Token
=
await
l1Bridge
.
l2Token
()
if
(
!
hexStringEquals
(
allowedL2Token
,
toAddress
(
l2Token
)))
{
return
false
}
return
true
}
}
packages/sdk/src/adapters/eth-bridge.ts
0 → 100644
View file @
0bc53656
/* eslint-disable @typescript-eslint/no-unused-vars */
import
{
ethers
,
Overrides
}
from
'
ethers
'
import
{
TransactionRequest
,
BlockTag
}
from
'
@ethersproject/abstract-provider
'
import
{
predeploys
}
from
'
@eth-optimism/contracts
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
NumberLike
,
AddressLike
,
TokenBridgeMessage
,
MessageDirection
,
}
from
'
../interfaces
'
import
{
toAddress
,
omit
}
from
'
../utils
'
import
{
StandardBridgeAdapter
}
from
'
./standard-bridge
'
/**
* Bridge adapter for the ETH bridge.
*/
export
class
ETHBridgeAdapter
extends
StandardBridgeAdapter
{
public
async
getDepositsByAddress
(
address
:
AddressLike
,
opts
?:
{
fromBlock
?:
BlockTag
toBlock
?:
BlockTag
}
):
Promise
<
TokenBridgeMessage
[]
>
{
const
events
=
await
this
.
l1Bridge
.
queryFilter
(
this
.
l1Bridge
.
filters
.
ETHDepositInitiated
(
address
),
opts
?.
fromBlock
,
opts
?.
toBlock
)
return
events
.
map
((
event
)
=>
{
return
{
direction
:
MessageDirection
.
L1_TO_L2
,
from
:
event
.
args
.
_from
,
to
:
event
.
args
.
_to
,
l1Token
:
ethers
.
constants
.
AddressZero
,
l2Token
:
predeploys
.
OVM_ETH
,
amount
:
event
.
args
.
_amount
,
data
:
event
.
args
.
_data
,
logIndex
:
event
.
logIndex
,
blockNumber
:
event
.
blockNumber
,
transactionHash
:
event
.
transactionHash
,
}
})
}
public
async
getWithdrawalsByAddress
(
address
:
AddressLike
,
opts
?:
{
fromBlock
?:
BlockTag
toBlock
?:
BlockTag
}
):
Promise
<
TokenBridgeMessage
[]
>
{
const
events
=
await
this
.
l2Bridge
.
queryFilter
(
this
.
l2Bridge
.
filters
.
WithdrawalInitiated
(
undefined
,
undefined
,
address
),
opts
?.
fromBlock
,
opts
?.
toBlock
)
return
events
.
filter
((
event
)
=>
{
// Only find ETH withdrawals.
return
(
hexStringEquals
(
event
.
args
.
_l1Token
,
ethers
.
constants
.
AddressZero
)
&&
hexStringEquals
(
event
.
args
.
_l2Token
,
predeploys
.
OVM_ETH
)
)
})
.
map
((
event
)
=>
{
return
{
direction
:
MessageDirection
.
L2_TO_L1
,
from
:
event
.
args
.
_from
,
to
:
event
.
args
.
_to
,
l1Token
:
event
.
args
.
_l1Token
,
l2Token
:
event
.
args
.
_l2Token
,
amount
:
event
.
args
.
_amount
,
data
:
event
.
args
.
_data
,
logIndex
:
event
.
logIndex
,
blockNumber
:
event
.
blockNumber
,
transactionHash
:
event
.
transactionHash
,
}
})
}
public
async
supportsTokenPair
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
):
Promise
<
boolean
>
{
// Only support ETH deposits and withdrawals.
return
(
hexStringEquals
(
toAddress
(
l1Token
),
ethers
.
constants
.
AddressZero
)
&&
hexStringEquals
(
toAddress
(
l2Token
),
predeploys
.
OVM_ETH
)
)
}
populateTransaction
=
{
deposit
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
TransactionRequest
>
=>
{
if
(
!
(
await
this
.
supportsTokenPair
(
l1Token
,
l2Token
)))
{
throw
new
Error
(
`token pair not supported by bridge`
)
}
return
this
.
l1Bridge
.
populateTransaction
.
depositETH
(
opts
?.
l2GasLimit
||
200
_000
,
// Default to 200k gas limit.
'
0x
'
,
// No data.
{
...
omit
(
opts
?.
overrides
||
{},
'
value
'
),
value
:
amount
,
}
)
},
withdraw
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
TransactionRequest
>
=>
{
if
(
!
(
await
this
.
supportsTokenPair
(
l1Token
,
l2Token
)))
{
throw
new
Error
(
`token pair not supported by bridge`
)
}
return
this
.
l2Bridge
.
populateTransaction
.
withdraw
(
toAddress
(
l2Token
),
amount
,
0
,
// L1 gas not required.
'
0x
'
,
// No data.
opts
?.
overrides
||
{}
)
},
}
}
packages/sdk/src/adapters/index.ts
0 → 100644
View file @
0bc53656
export
*
from
'
./standard-bridge
'
export
*
from
'
./eth-bridge
'
export
*
from
'
./dai-bridge
'
packages/sdk/src/adapters/standard-bridge.ts
0 → 100644
View file @
0bc53656
/* eslint-disable @typescript-eslint/no-unused-vars */
import
{
ethers
,
Contract
,
Overrides
,
Signer
,
BigNumber
}
from
'
ethers
'
import
{
TransactionRequest
,
TransactionResponse
,
BlockTag
,
}
from
'
@ethersproject/abstract-provider
'
import
{
getContractInterface
,
predeploys
}
from
'
@eth-optimism/contracts
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
IBridgeAdapter
,
ICrossChainProvider
,
NumberLike
,
AddressLike
,
TokenBridgeMessage
,
MessageDirection
,
}
from
'
../interfaces
'
import
{
toAddress
}
from
'
../utils
'
/**
* Bridge adapter for any token bridge that uses the standard token bridge interface.
*/
export
class
StandardBridgeAdapter
implements
IBridgeAdapter
{
public
provider
:
ICrossChainProvider
public
l1Bridge
:
Contract
public
l2Bridge
:
Contract
/**
* Creates a StandardBridgeAdapter instance.
*
* @param opts Options for the adapter.
* @param opts.provider Provider used to make queries related to cross-chain interactions.
* @param opts.l1Bridge L1 bridge contract.
* @param opts.l2Bridge L2 bridge contract.
*/
constructor
(
opts
:
{
provider
:
ICrossChainProvider
l1Bridge
:
AddressLike
l2Bridge
:
AddressLike
})
{
this
.
provider
=
opts
.
provider
this
.
l1Bridge
=
new
Contract
(
toAddress
(
opts
.
l1Bridge
),
getContractInterface
(
'
L1StandardBridge
'
),
this
.
provider
.
l1Provider
)
this
.
l2Bridge
=
new
Contract
(
toAddress
(
opts
.
l2Bridge
),
getContractInterface
(
'
IL2ERC20Bridge
'
),
this
.
provider
.
l2Provider
)
}
public
async
getTokenBridgeMessagesByAddress
(
address
:
AddressLike
,
opts
?:
{
direction
?:
MessageDirection
}
):
Promise
<
TokenBridgeMessage
[]
>
{
let
messages
:
TokenBridgeMessage
[]
=
[]
if
(
opts
?.
direction
===
undefined
||
opts
?.
direction
===
MessageDirection
.
L1_TO_L2
)
{
messages
=
messages
.
concat
(
await
this
.
getDepositsByAddress
(
address
))
}
if
(
opts
?.
direction
===
undefined
||
opts
?.
direction
===
MessageDirection
.
L2_TO_L1
)
{
messages
=
messages
.
concat
(
await
this
.
getWithdrawalsByAddress
(
address
))
}
return
messages
}
public
async
getDepositsByAddress
(
address
:
AddressLike
,
opts
?:
{
fromBlock
?:
BlockTag
toBlock
?:
BlockTag
}
):
Promise
<
TokenBridgeMessage
[]
>
{
const
events
=
await
this
.
l1Bridge
.
queryFilter
(
this
.
l1Bridge
.
filters
.
ERC20DepositInitiated
(
undefined
,
undefined
,
address
),
opts
?.
fromBlock
,
opts
?.
toBlock
)
return
events
.
filter
((
event
)
=>
{
// Specifically filter out ETH. ETH deposits and withdrawals are handled by the ETH bridge
// adapter. Bridges that are not the ETH bridge should not be able to handle or even
// present ETH deposits or withdrawals.
return
(
!
hexStringEquals
(
event
.
args
.
_l1Token
,
ethers
.
constants
.
AddressZero
)
&&
!
hexStringEquals
(
event
.
args
.
_l2Token
,
predeploys
.
OVM_ETH
)
)
})
.
map
((
event
)
=>
{
return
{
direction
:
MessageDirection
.
L1_TO_L2
,
from
:
event
.
args
.
_from
,
to
:
event
.
args
.
_to
,
l1Token
:
event
.
args
.
_l1Token
,
l2Token
:
event
.
args
.
_l2Token
,
amount
:
event
.
args
.
_amount
,
data
:
event
.
args
.
_data
,
logIndex
:
event
.
logIndex
,
blockNumber
:
event
.
blockNumber
,
transactionHash
:
event
.
transactionHash
,
}
})
}
public
async
getWithdrawalsByAddress
(
address
:
AddressLike
,
opts
?:
{
fromBlock
?:
BlockTag
toBlock
?:
BlockTag
}
):
Promise
<
TokenBridgeMessage
[]
>
{
const
events
=
await
this
.
l2Bridge
.
queryFilter
(
this
.
l2Bridge
.
filters
.
WithdrawalInitiated
(
undefined
,
undefined
,
address
),
opts
?.
fromBlock
,
opts
?.
toBlock
)
return
events
.
filter
((
event
)
=>
{
// Specifically filter out ETH. ETH deposits and withdrawals are handled by the ETH bridge
// adapter. Bridges that are not the ETH bridge should not be able to handle or even
// present ETH deposits or withdrawals.
return
(
!
hexStringEquals
(
event
.
args
.
_l1Token
,
ethers
.
constants
.
AddressZero
)
&&
!
hexStringEquals
(
event
.
args
.
_l2Token
,
predeploys
.
OVM_ETH
)
)
})
.
map
((
event
)
=>
{
return
{
direction
:
MessageDirection
.
L2_TO_L1
,
from
:
event
.
args
.
_from
,
to
:
event
.
args
.
_to
,
l1Token
:
event
.
args
.
_l1Token
,
l2Token
:
event
.
args
.
_l2Token
,
amount
:
event
.
args
.
_amount
,
data
:
event
.
args
.
_data
,
logIndex
:
event
.
logIndex
,
blockNumber
:
event
.
blockNumber
,
transactionHash
:
event
.
transactionHash
,
}
})
}
public
async
supportsTokenPair
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
):
Promise
<
boolean
>
{
try
{
const
contract
=
new
Contract
(
toAddress
(
l2Token
),
getContractInterface
(
'
L2StandardERC20
'
),
this
.
provider
.
l2Provider
)
// Don't support ETH deposits or withdrawals via this bridge.
if
(
hexStringEquals
(
toAddress
(
l1Token
),
ethers
.
constants
.
AddressZero
)
||
hexStringEquals
(
toAddress
(
l2Token
),
predeploys
.
OVM_ETH
)
)
{
return
false
}
// Make sure the L1 token matches.
const
remoteL1Token
=
await
contract
.
l1Token
()
if
(
!
hexStringEquals
(
remoteL1Token
,
toAddress
(
l1Token
)))
{
return
false
}
// Make sure the L2 bridge matches.
const
remoteL2Bridge
=
await
contract
.
l2Bridge
()
if
(
!
hexStringEquals
(
remoteL2Bridge
,
this
.
l2Bridge
.
address
))
{
return
false
}
return
true
}
catch
(
err
)
{
// If the L2 token is not an L2StandardERC20, it may throw an error. If there's a call
// exception then we assume that the token is not supported. Other errors are thrown.
if
(
err
.
message
.
toString
().
includes
(
'
CALL_EXCEPTION
'
))
{
return
false
}
else
{
throw
err
}
}
}
public
async
deposit
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
signer
:
Signer
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
TransactionResponse
>
{
return
signer
.
sendTransaction
(
await
this
.
populateTransaction
.
deposit
(
l1Token
,
l2Token
,
amount
,
opts
)
)
}
public
async
withdraw
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
signer
:
Signer
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
TransactionResponse
>
{
return
signer
.
sendTransaction
(
await
this
.
populateTransaction
.
withdraw
(
l1Token
,
l2Token
,
amount
,
opts
)
)
}
populateTransaction
=
{
deposit
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
TransactionRequest
>
=>
{
if
(
!
(
await
this
.
supportsTokenPair
(
l1Token
,
l2Token
)))
{
throw
new
Error
(
`token pair not supported by bridge`
)
}
return
this
.
l1Bridge
.
depositERC20
(
toAddress
(
l1Token
),
toAddress
(
l2Token
),
amount
,
opts
?.
l2GasLimit
||
200
_000
,
// Default to 200k gas limit.
'
0x
'
,
// No data.
opts
?.
overrides
||
{}
)
},
withdraw
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
TransactionRequest
>
=>
{
if
(
!
(
await
this
.
supportsTokenPair
(
l1Token
,
l2Token
)))
{
throw
new
Error
(
`token pair not supported by bridge`
)
}
return
this
.
l2Bridge
.
populateTransaction
.
withdraw
(
toAddress
(
l2Token
),
amount
,
0
,
// L1 gas not required.
'
0x
'
,
// No data.
opts
?.
overrides
||
{}
)
},
}
estimateGas
=
{
deposit
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
BigNumber
>
=>
{
return
this
.
provider
.
l1Provider
.
estimateGas
(
await
this
.
populateTransaction
.
deposit
(
l1Token
,
l2Token
,
amount
,
opts
)
)
},
withdraw
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
BigNumber
>
=>
{
return
this
.
provider
.
l2Provider
.
estimateGas
(
await
this
.
populateTransaction
.
withdraw
(
l1Token
,
l2Token
,
amount
,
opts
)
)
},
}
}
packages/sdk/src/cross-chain-messenger.ts
View file @
0bc53656
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-unused-vars */
import
{
Overrides
,
Signer
,
BigNumber
}
from
'
ethers
'
import
{
ethers
,
Overrides
,
Signer
,
BigNumber
}
from
'
ethers
'
import
{
import
{
TransactionRequest
,
TransactionRequest
,
TransactionResponse
,
TransactionResponse
,
...
@@ -10,11 +10,12 @@ import {
...
@@ -10,11 +10,12 @@ import {
CrossChainMessageRequest
,
CrossChainMessageRequest
,
ICrossChainMessenger
,
ICrossChainMessenger
,
ICrossChainProvider
,
ICrossChainProvider
,
IBridgeAdapter
,
MessageLike
,
MessageLike
,
NumberLike
,
NumberLike
,
AddressLike
,
MessageDirection
,
MessageDirection
,
}
from
'
./interfaces
'
}
from
'
./interfaces
'
import
{
omit
}
from
'
./utils
'
export
class
CrossChainMessenger
implements
ICrossChainMessenger
{
export
class
CrossChainMessenger
implements
ICrossChainMessenger
{
provider
:
ICrossChainProvider
provider
:
ICrossChainProvider
...
@@ -102,6 +103,43 @@ export class CrossChainMessenger implements ICrossChainMessenger {
...
@@ -102,6 +103,43 @@ export class CrossChainMessenger implements ICrossChainMessenger {
)
)
}
}
public
async
depositERC20
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
TransactionResponse
>
{
return
this
.
l1Signer
.
sendTransaction
(
await
this
.
populateTransaction
.
depositERC20
(
l1Token
,
l2Token
,
amount
,
opts
)
)
}
public
async
withdrawERC20
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
TransactionResponse
>
{
return
this
.
l2Signer
.
sendTransaction
(
await
this
.
populateTransaction
.
withdrawERC20
(
l1Token
,
l2Token
,
amount
,
opts
)
)
}
populateTransaction
=
{
populateTransaction
=
{
sendMessage
:
async
(
sendMessage
:
async
(
message
:
CrossChainMessageRequest
,
message
:
CrossChainMessageRequest
,
...
@@ -118,7 +156,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
...
@@ -118,7 +156,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
message
.
message
,
message
.
message
,
opts
?.
l2GasLimit
||
opts
?.
l2GasLimit
||
(
await
this
.
provider
.
estimateL2MessageGasLimit
(
message
)),
(
await
this
.
provider
.
estimateL2MessageGasLimit
(
message
)),
o
mit
(
opts
?.
overrides
||
{},
'
l2GasLimit
'
)
o
pts
?.
overrides
||
{}
)
)
}
else
{
}
else
{
return
this
.
provider
.
contracts
.
l2
.
L2CrossDomainMessenger
.
connect
(
return
this
.
provider
.
contracts
.
l2
.
L2CrossDomainMessenger
.
connect
(
...
@@ -127,7 +165,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
...
@@ -127,7 +165,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
message
.
target
,
message
.
target
,
message
.
message
,
message
.
message
,
0
,
// Gas limit goes unused when sending from L2 to L1
0
,
// Gas limit goes unused when sending from L2 to L1
o
mit
(
opts
?.
overrides
||
{},
'
l2GasLimit
'
)
o
pts
?.
overrides
||
{}
)
)
}
}
},
},
...
@@ -173,13 +211,11 @@ export class CrossChainMessenger implements ICrossChainMessenger {
...
@@ -173,13 +211,11 @@ export class CrossChainMessenger implements ICrossChainMessenger {
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
TransactionRequest
>
=>
{
):
Promise
<
TransactionRequest
>
=>
{
return
this
.
provider
.
contracts
.
l1
.
L1StandardBridge
.
populateTransaction
.
depositETH
(
return
this
.
provider
.
bridges
.
ETH
.
populateTransaction
.
deposit
(
opts
?.
l2GasLimit
||
200000
,
// 200k gas is fine as a default
ethers
.
constants
.
AddressZero
,
'
0x
'
,
// No data
predeploys
.
OVM_ETH
,
{
amount
,
...
omit
(
opts
?.
overrides
||
{},
'
l2GasLimit
'
,
'
value
'
),
opts
value
:
amount
,
}
)
)
},
},
...
@@ -189,14 +225,38 @@ export class CrossChainMessenger implements ICrossChainMessenger {
...
@@ -189,14 +225,38 @@ export class CrossChainMessenger implements ICrossChainMessenger {
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
TransactionRequest
>
=>
{
):
Promise
<
TransactionRequest
>
=>
{
return
this
.
provider
.
contracts
.
l2
.
L2StandardBridge
.
populateTransaction
.
withdraw
(
return
this
.
provider
.
bridges
.
ETH
.
populateTransaction
.
withdraw
(
ethers
.
constants
.
AddressZero
,
predeploys
.
OVM_ETH
,
predeploys
.
OVM_ETH
,
amount
,
amount
,
0
,
// No need to supply gas here
opts
'
0x
'
,
// No data,
opts
?.
overrides
||
{}
)
)
},
},
depositERC20
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
TransactionRequest
>
=>
{
const
bridge
=
await
this
.
provider
.
getBridgeForTokenPair
(
l1Token
,
l2Token
)
return
bridge
.
populateTransaction
.
deposit
(
l1Token
,
l2Token
,
amount
,
opts
)
},
withdrawERC20
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
TransactionRequest
>
=>
{
const
bridge
=
await
this
.
provider
.
getBridgeForTokenPair
(
l1Token
,
l2Token
)
return
bridge
.
populateTransaction
.
withdraw
(
l1Token
,
l2Token
,
amount
,
opts
)
},
}
}
estimateGas
=
{
estimateGas
=
{
...
@@ -222,12 +282,13 @@ export class CrossChainMessenger implements ICrossChainMessenger {
...
@@ -222,12 +282,13 @@ export class CrossChainMessenger implements ICrossChainMessenger {
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
BigNumber
>
=>
{
):
Promise
<
BigNumber
>
=>
{
const
tx
=
await
this
.
populateTransaction
.
resendMessage
(
return
this
.
provider
.
l1Provider
.
estimateGas
(
message
,
await
this
.
populateTransaction
.
resendMessage
(
messageGasLimit
,
message
,
opts
messageGasLimit
,
opts
)
)
)
return
this
.
provider
.
l1Provider
.
estimateGas
(
tx
)
},
},
finalizeMessage
:
async
(
finalizeMessage
:
async
(
...
@@ -246,8 +307,9 @@ export class CrossChainMessenger implements ICrossChainMessenger {
...
@@ -246,8 +307,9 @@ export class CrossChainMessenger implements ICrossChainMessenger {
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
BigNumber
>
=>
{
):
Promise
<
BigNumber
>
=>
{
const
tx
=
await
this
.
populateTransaction
.
depositETH
(
amount
,
opts
)
return
this
.
provider
.
l1Provider
.
estimateGas
(
return
this
.
provider
.
l1Provider
.
estimateGas
(
tx
)
await
this
.
populateTransaction
.
depositETH
(
amount
,
opts
)
)
},
},
withdrawETH
:
async
(
withdrawETH
:
async
(
...
@@ -256,8 +318,46 @@ export class CrossChainMessenger implements ICrossChainMessenger {
...
@@ -256,8 +318,46 @@ export class CrossChainMessenger implements ICrossChainMessenger {
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
BigNumber
>
=>
{
):
Promise
<
BigNumber
>
=>
{
const
tx
=
await
this
.
populateTransaction
.
withdrawETH
(
amount
,
opts
)
return
this
.
provider
.
l2Provider
.
estimateGas
(
return
this
.
provider
.
l2Provider
.
estimateGas
(
tx
)
await
this
.
populateTransaction
.
withdrawETH
(
amount
,
opts
)
)
},
depositERC20
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
BigNumber
>
=>
{
return
this
.
provider
.
l2Provider
.
estimateGas
(
await
this
.
populateTransaction
.
depositERC20
(
l1Token
,
l2Token
,
amount
,
opts
)
)
},
withdrawERC20
:
async
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
BigNumber
>
=>
{
return
this
.
provider
.
l2Provider
.
estimateGas
(
await
this
.
populateTransaction
.
withdrawERC20
(
l1Token
,
l2Token
,
amount
,
opts
)
)
},
},
}
}
}
}
packages/sdk/src/cross-chain-provider.ts
View file @
0bc53656
...
@@ -4,7 +4,7 @@ import {
...
@@ -4,7 +4,7 @@ import {
BlockTag
,
BlockTag
,
TransactionReceipt
,
TransactionReceipt
,
}
from
'
@ethersproject/abstract-provider
'
}
from
'
@ethersproject/abstract-provider
'
import
{
ethers
,
BigNumber
,
Event
}
from
'
ethers
'
import
{
ethers
,
BigNumber
}
from
'
ethers
'
import
{
sleep
}
from
'
@eth-optimism/core-utils
'
import
{
sleep
}
from
'
@eth-optimism/core-utils
'
import
{
import
{
...
@@ -24,10 +24,11 @@ import {
...
@@ -24,10 +24,11 @@ import {
TokenBridgeMessage
,
TokenBridgeMessage
,
MessageReceipt
,
MessageReceipt
,
MessageReceiptStatus
,
MessageReceiptStatus
,
CustomBridges
,
BridgeAdapterData
,
CustomBridgesLike
,
BridgeAdapters
,
StateRoot
,
StateRoot
,
StateRootBatch
,
StateRootBatch
,
IBridgeAdapter
,
}
from
'
./interfaces
'
}
from
'
./interfaces
'
import
{
import
{
toProvider
,
toProvider
,
...
@@ -35,7 +36,7 @@ import {
...
@@ -35,7 +36,7 @@ import {
toTransactionHash
,
toTransactionHash
,
DeepPartial
,
DeepPartial
,
getAllOEContracts
,
getAllOEContracts
,
get
CustomBridge
s
,
get
BridgeAdapter
s
,
hashCrossChainMessage
,
hashCrossChainMessage
,
}
from
'
./utils
'
}
from
'
./utils
'
...
@@ -44,7 +45,7 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -44,7 +45,7 @@ export class CrossChainProvider implements ICrossChainProvider {
public
l2Provider
:
Provider
public
l2Provider
:
Provider
public
l1ChainId
:
number
public
l1ChainId
:
number
public
contracts
:
OEContracts
public
contracts
:
OEContracts
public
bridges
:
CustomBridge
s
public
bridges
:
BridgeAdapter
s
/**
/**
* Creates a new CrossChainProvider instance.
* Creates a new CrossChainProvider instance.
...
@@ -61,7 +62,7 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -61,7 +62,7 @@ export class CrossChainProvider implements ICrossChainProvider {
l2Provider
:
ProviderLike
l2Provider
:
ProviderLike
l1ChainId
:
NumberLike
l1ChainId
:
NumberLike
contracts
?:
DeepPartial
<
OEContractsLike
>
contracts
?:
DeepPartial
<
OEContractsLike
>
bridges
?:
Partial
<
CustomBridgesLike
>
bridges
?:
BridgeAdapterData
})
{
})
{
this
.
l1Provider
=
toProvider
(
opts
.
l1Provider
)
this
.
l1Provider
=
toProvider
(
opts
.
l1Provider
)
this
.
l2Provider
=
toProvider
(
opts
.
l2Provider
)
this
.
l2Provider
=
toProvider
(
opts
.
l2Provider
)
...
@@ -71,9 +72,7 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -71,9 +72,7 @@ export class CrossChainProvider implements ICrossChainProvider {
l2SignerOrProvider
:
this
.
l2Provider
,
l2SignerOrProvider
:
this
.
l2Provider
,
overrides
:
opts
.
contracts
,
overrides
:
opts
.
contracts
,
})
})
this
.
bridges
=
getCustomBridges
(
this
.
l1ChainId
,
{
this
.
bridges
=
getBridgeAdapters
(
this
.
l1ChainId
,
this
,
{
l1SignerOrProvider
:
this
.
l1Provider
,
l2SignerOrProvider
:
this
.
l2Provider
,
overrides
:
opts
.
bridges
,
overrides
:
opts
.
bridges
,
})
})
}
}
...
@@ -153,113 +152,43 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -153,113 +152,43 @@ export class CrossChainProvider implements ICrossChainProvider {
throw
new
Error
(
'
Not implemented
'
)
throw
new
Error
(
'
Not implemented
'
)
}
}
public
async
getTokenBridgeMessagesByAddress
(
public
async
getBridgeForTokenPair
(
address
:
AddressLike
,
l1Token
:
AddressLike
,
opts
:
{
l2Token
:
AddressLike
direction
?:
MessageDirection
):
Promise
<
IBridgeAdapter
>
{
fromBlock
?:
BlockTag
const
bridges
:
IBridgeAdapter
[]
=
[]
toBlock
?:
BlockTag
for
(
const
bridge
of
Object
.
values
(
this
.
bridges
))
{
}
=
{}
if
(
await
bridge
.
supportsTokenPair
(
l1Token
,
l2Token
))
{
):
Promise
<
TokenBridgeMessage
[]
>
{
bridges
.
push
(
bridge
)
const
parseTokenEvent
=
(
event
:
Event
,
dir
:
MessageDirection
):
TokenBridgeMessage
=>
{
return
{
direction
:
dir
,
from
:
event
.
args
.
_from
,
to
:
event
.
args
.
_to
,
l1Token
:
event
.
args
.
_l1Token
||
ethers
.
constants
.
AddressZero
,
l2Token
:
event
.
args
.
_l2Token
||
this
.
contracts
.
l2
.
OVM_ETH
.
address
,
amount
:
event
.
args
.
_amount
,
data
:
event
.
args
.
_data
,
logIndex
:
event
.
logIndex
,
blockNumber
:
event
.
blockNumber
,
transactionHash
:
event
.
transactionHash
,
}
}
}
}
// Make sure you provide a direction if you specify a block range. Block ranges don't make
if
(
bridges
.
length
===
0
)
{
// sense to use on both chains at the same time.
throw
new
Error
(
`no supported bridge for token pair`
)
if
(
opts
.
fromBlock
!==
undefined
||
opts
.
toBlock
!==
undefined
)
{
if
(
opts
.
direction
===
undefined
)
{
throw
new
Error
(
'
direction must be specified when using a block range
'
)
}
}
}
// Keep track of all of the messages triggered by the address in question.
if
(
bridges
.
length
>
1
)
{
// We'll add messages to this list as we find them, based on the direction that the user has
throw
new
Error
(
`found more than one bridge for token pair`
)
// requested we find messages in. If the user hasn't requested a direction, we find messages in
// both directions.
const
messages
:
TokenBridgeMessage
[]
=
[]
// First find all messages in the L1 to L2 direction.
if
(
opts
.
direction
===
undefined
||
opts
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
// Find all ETH deposit events and push them into the messages array.
const
ethDepositEvents
=
await
this
.
contracts
.
l1
.
L1StandardBridge
.
queryFilter
(
this
.
contracts
.
l1
.
L1StandardBridge
.
filters
.
ETHDepositInitiated
(
address
),
opts
.
fromBlock
,
opts
.
toBlock
)
for
(
const
event
of
ethDepositEvents
)
{
messages
.
push
(
parseTokenEvent
(
event
,
MessageDirection
.
L1_TO_L2
))
}
// Send an event query for every L1 bridge, this will return an array of arrays.
const
erc20DepositEventSets
=
await
Promise
.
all
(
[
this
.
contracts
.
l1
.
L1StandardBridge
,
...
Object
.
values
(
this
.
bridges
.
l1
),
].
map
(
async
(
bridge
)
=>
{
return
bridge
.
queryFilter
(
bridge
.
filters
.
ERC20DepositInitiated
(
undefined
,
undefined
,
address
),
opts
.
fromBlock
,
opts
.
toBlock
)
})
)
for
(
const
erc20DepositEvents
of
erc20DepositEventSets
)
{
for
(
const
event
of
erc20DepositEvents
)
{
messages
.
push
(
parseTokenEvent
(
event
,
MessageDirection
.
L1_TO_L2
))
}
}
}
}
// Next find all messages in the L2 to L1 direction.
return
bridges
[
0
]
if
(
}
opts
.
direction
===
undefined
||
opts
.
direction
===
MessageDirection
.
L2_TO_L1
public
async
getTokenBridgeMessagesByAddress
(
)
{
address
:
AddressLike
,
// ETH withdrawals and ERC20 withdrawals are the same event on L2.
opts
:
{
// Send an event query for every L2 bridge, this will return an array of arrays.
direction
?:
MessageDirection
const
withdrawalEventSets
=
await
Promise
.
all
(
}
=
{}
[
):
Promise
<
TokenBridgeMessage
[]
>
{
this
.
contracts
.
l2
.
L2StandardBridge
,
return
(
...
Object
.
values
(
this
.
bridges
.
l2
),
await
Promise
.
all
(
].
map
(
async
(
bridge
)
=>
{
Object
.
values
(
this
.
bridges
).
map
(
async
(
bridge
)
=>
{
return
bridge
.
queryFilter
(
return
bridge
.
getTokenBridgeMessagesByAddress
(
address
,
opts
)
bridge
.
filters
.
WithdrawalInitiated
(
undefined
,
undefined
,
address
),
opts
.
fromBlock
,
opts
.
toBlock
)
})
})
)
)
).
reduce
((
acc
,
val
)
=>
{
for
(
const
withdrawalEvents
of
withdrawalEventSets
)
{
return
acc
.
concat
(
val
)
for
(
const
event
of
withdrawalEvents
)
{
},
[])
messages
.
push
(
parseTokenEvent
(
event
,
MessageDirection
.
L2_TO_L1
))
}
}
}
return
messages
}
}
public
async
getDepositsByAddress
(
public
async
getDepositsByAddress
(
...
@@ -269,10 +198,15 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -269,10 +198,15 @@ export class CrossChainProvider implements ICrossChainProvider {
toBlock
?:
BlockTag
toBlock
?:
BlockTag
}
=
{}
}
=
{}
):
Promise
<
TokenBridgeMessage
[]
>
{
):
Promise
<
TokenBridgeMessage
[]
>
{
return
this
.
getTokenBridgeMessagesByAddress
(
address
,
{
return
(
...
opts
,
await
Promise
.
all
(
direction
:
MessageDirection
.
L1_TO_L2
,
Object
.
values
(
this
.
bridges
).
map
(
async
(
bridge
)
=>
{
})
return
bridge
.
getDepositsByAddress
(
address
,
opts
)
})
)
).
reduce
((
acc
,
val
)
=>
{
return
acc
.
concat
(
val
)
},
[])
}
}
public
async
getWithdrawalsByAddress
(
public
async
getWithdrawalsByAddress
(
...
@@ -282,10 +216,15 @@ export class CrossChainProvider implements ICrossChainProvider {
...
@@ -282,10 +216,15 @@ export class CrossChainProvider implements ICrossChainProvider {
toBlock
?:
BlockTag
toBlock
?:
BlockTag
}
=
{}
}
=
{}
):
Promise
<
TokenBridgeMessage
[]
>
{
):
Promise
<
TokenBridgeMessage
[]
>
{
return
this
.
getTokenBridgeMessagesByAddress
(
address
,
{
return
(
...
opts
,
await
Promise
.
all
(
direction
:
MessageDirection
.
L2_TO_L1
,
Object
.
values
(
this
.
bridges
).
map
(
async
(
bridge
)
=>
{
})
return
bridge
.
getWithdrawalsByAddress
(
address
,
opts
)
})
)
).
reduce
((
acc
,
val
)
=>
{
return
acc
.
concat
(
val
)
},
[])
}
}
public
async
toCrossChainMessage
(
public
async
toCrossChainMessage
(
...
...
packages/sdk/src/index.ts
View file @
0bc53656
...
@@ -2,3 +2,4 @@ export * from './interfaces'
...
@@ -2,3 +2,4 @@ export * from './interfaces'
export
*
from
'
./utils
'
export
*
from
'
./utils
'
export
*
from
'
./cross-chain-provider
'
export
*
from
'
./cross-chain-provider
'
export
*
from
'
./cross-chain-messenger
'
export
*
from
'
./cross-chain-messenger
'
export
*
from
'
./adapters
'
packages/sdk/src/interfaces/
cross-chain-erc20-pai
r.ts
→
packages/sdk/src/interfaces/
bridge-adapte
r.ts
View file @
0bc53656
import
{
Overrides
,
Contract
}
from
'
ethers
'
import
{
Contract
,
Overrides
,
Signer
,
BigNumber
}
from
'
ethers
'
import
{
import
{
TransactionRequest
,
TransactionRequest
,
TransactionResponse
,
TransactionResponse
,
BlockTag
,
}
from
'
@ethersproject/abstract-provider
'
}
from
'
@ethersproject/abstract-provider
'
import
{
NumberLike
}
from
'
./types
'
import
{
import
{
ICrossChainMessenger
}
from
'
./cross-chain-messenger
'
NumberLike
,
AddressLike
,
MessageDirection
,
TokenBridgeMessage
,
}
from
'
./types
'
import
{
ICrossChainProvider
}
from
'
./cross-chain-provider
'
/**
/**
* Represents an L1<>L2 ERC20 token pair.
* Represents an adapter for an L1<>L2 token bridge. Each custom bridge currently needs its own
* adapter because the bridge interface is not standardized. This may change in the future.
*/
*/
export
interface
ICrossChainERC20Pair
{
export
interface
IBridgeAdapter
{
/**
* Provider used to make queries related to cross-chain interactions.
*/
provider
:
ICrossChainProvider
/**
* L1 bridge contract.
*/
l1Bridge
:
Contract
/**
/**
*
Messenger that will be used to carry out cross-chain iteractions
.
*
L2 bridge contract
.
*/
*/
messenger
:
ICrossChainMessenger
l2Bridge
:
Contract
/**
/**
* Ethers Contract object connected to the L1 token.
* Finds all cross chain messages that correspond to token deposits or withdrawals sent by a
* particular address. Useful for finding deposits/withdrawals because the sender of the message
* will appear to be the StandardBridge contract and not the actual end user.
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.direction Direction to search for messages in. If not provided, will attempt to
* find all messages in both directions.
* @returns All token bridge messages sent by the given address.
*/
*/
l1Token
:
Contract
getTokenBridgeMessagesByAddress
(
address
:
AddressLike
,
opts
?:
{
direction
?:
MessageDirection
}
):
Promise
<
TokenBridgeMessage
[]
>
/**
/**
* Ethers Contract object connected to the L2 token.
* Gets all deposits for a given address.
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All deposit token bridge messages sent by the given address.
*/
*/
l2Token
:
Contract
getDepositsByAddress
(
address
:
AddressLike
,
opts
?:
{
fromBlock
?:
BlockTag
toBlock
?:
BlockTag
}
):
Promise
<
TokenBridgeMessage
[]
>
/**
* Gets all withdrawals for a given address.
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All withdrawal token bridge messages sent by the given address.
*/
getWithdrawalsByAddress
(
address
:
AddressLike
,
opts
?:
{
fromBlock
?:
BlockTag
toBlock
?:
BlockTag
}
):
Promise
<
TokenBridgeMessage
[]
>
/**
* Checks whether the given token pair is supported by the bridge.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @returns Whether the given token pair is supported by the bridge.
*/
supportsTokenPair
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
):
Promise
<
boolean
>
/**
/**
* Deposits some tokens into the L2 chain.
* Deposits some tokens into the L2 chain.
*
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to deposit.
* @param amount Amount of the token to deposit.
* @param signer Signer used to sign and send the transaction.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction response for the deposit transaction.
* @returns Transaction response for the deposit transaction.
*/
*/
deposit
(
deposit
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
amount
:
NumberLike
,
signer
:
Signer
,
opts
?:
{
opts
?:
{
l2GasLimit
?:
NumberLike
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
overrides
?:
Overrides
...
@@ -46,13 +127,19 @@ export interface ICrossChainERC20Pair {
...
@@ -46,13 +127,19 @@ export interface ICrossChainERC20Pair {
/**
/**
* Withdraws some tokens back to the L1 chain.
* Withdraws some tokens back to the L1 chain.
*
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to withdraw.
* @param amount Amount of the token to withdraw.
* @param signer Signer used to sign and send the transaction.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction response for the withdraw transaction.
* @returns Transaction response for the withdraw transaction.
*/
*/
withdraw
(
withdraw
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
amount
:
NumberLike
,
signer
:
Signer
,
opts
?:
{
opts
?:
{
overrides
?:
Overrides
overrides
?:
Overrides
}
}
...
@@ -66,6 +153,8 @@ export interface ICrossChainERC20Pair {
...
@@ -66,6 +153,8 @@ export interface ICrossChainERC20Pair {
/**
/**
* Generates a transaction for depositing some tokens into the L2 chain.
* Generates a transaction for depositing some tokens into the L2 chain.
*
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to deposit.
* @param amount Amount of the token to deposit.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
...
@@ -73,22 +162,28 @@ export interface ICrossChainERC20Pair {
...
@@ -73,22 +162,28 @@ export interface ICrossChainERC20Pair {
* @returns Transaction that can be signed and executed to deposit the tokens.
* @returns Transaction that can be signed and executed to deposit the tokens.
*/
*/
deposit
(
deposit
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
amount
:
NumberLike
,
opts
?:
{
opts
?:
{
l2GasLimit
?:
NumberLike
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
TransactionRe
sponse
>
):
Promise
<
TransactionRe
quest
>
/**
/**
* Generates a transaction for withdrawing some tokens back to the L1 chain.
* Generates a transaction for withdrawing some tokens back to the L1 chain.
*
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to withdraw.
* @param amount Amount of the token to withdraw.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to withdraw the tokens.
* @returns Transaction that can be signed and executed to withdraw the tokens.
*/
*/
withdraw
(
withdraw
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
amount
:
NumberLike
,
opts
?:
{
opts
?:
{
overrides
?:
Overrides
overrides
?:
Overrides
...
@@ -104,33 +199,41 @@ export interface ICrossChainERC20Pair {
...
@@ -104,33 +199,41 @@ export interface ICrossChainERC20Pair {
/**
/**
* Estimates gas required to deposit some tokens into the L2 chain.
* Estimates gas required to deposit some tokens into the L2 chain.
*
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to deposit.
* @param amount Amount of the token to deposit.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns
Transaction that can be signed and executed to deposit the tokens
.
* @returns
Gas estimate for the transaction
.
*/
*/
deposit
(
deposit
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
amount
:
NumberLike
,
opts
?:
{
opts
?:
{
l2GasLimit
?:
NumberLike
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
TransactionResponse
>
):
Promise
<
BigNumber
>
/**
/**
* Estimates gas required to withdraw some tokens back to the L1 chain.
* Estimates gas required to withdraw some tokens back to the L1 chain.
*
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to withdraw.
* @param amount Amount of the token to withdraw.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns
Transaction that can be signed and executed to withdraw the tokens
.
* @returns
Gas estimate for the transaction
.
*/
*/
withdraw
(
withdraw
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
amount
:
NumberLike
,
opts
?:
{
opts
?:
{
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
TransactionRequest
>
):
Promise
<
BigNumber
>
}
}
}
}
packages/sdk/src/interfaces/cross-chain-messenger.ts
View file @
0bc53656
...
@@ -4,7 +4,12 @@ import {
...
@@ -4,7 +4,12 @@ import {
TransactionResponse
,
TransactionResponse
,
}
from
'
@ethersproject/abstract-provider
'
}
from
'
@ethersproject/abstract-provider
'
import
{
MessageLike
,
NumberLike
,
CrossChainMessageRequest
}
from
'
./types
'
import
{
MessageLike
,
NumberLike
,
CrossChainMessageRequest
,
AddressLike
,
}
from
'
./types
'
import
{
ICrossChainProvider
}
from
'
./cross-chain-provider
'
import
{
ICrossChainProvider
}
from
'
./cross-chain-provider
'
/**
/**
...
@@ -110,6 +115,46 @@ export interface ICrossChainMessenger {
...
@@ -110,6 +115,46 @@ export interface ICrossChainMessenger {
}
}
):
Promise
<
TransactionResponse
>
):
Promise
<
TransactionResponse
>
/**
* Deposits some ERC20 tokens into the L2 chain.
*
* @param l1Token Address of the L1 token.
* @param l2Token Address of the L2 token.
* @param amount Amount to deposit.
* @param opts Additional options.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction response for the deposit transaction.
*/
depositERC20
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
TransactionResponse
>
/**
* Withdraws some ERC20 tokens back to the L1 chain.
*
* @param l1Token Address of the L1 token.
* @param l2Token Address of the L2 token.
* @param amount Amount to withdraw.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction response for the withdraw transaction.
*/
withdrawERC20
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
TransactionResponse
>
/**
/**
* Object that holds the functions that generate transactions to be signed by the user.
* Object that holds the functions that generate transactions to be signed by the user.
* Follows the pattern used by ethers.js.
* Follows the pattern used by ethers.js.
...
@@ -191,7 +236,7 @@ export interface ICrossChainMessenger {
...
@@ -191,7 +236,7 @@ export interface ICrossChainMessenger {
* @param amount Amount of ETH to withdraw.
* @param amount Amount of ETH to withdraw.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to withdraw the
tokens
.
* @returns Transaction that can be signed and executed to withdraw the
ETH
.
*/
*/
withdrawETH
(
withdrawETH
(
amount
:
NumberLike
,
amount
:
NumberLike
,
...
@@ -199,6 +244,46 @@ export interface ICrossChainMessenger {
...
@@ -199,6 +244,46 @@ export interface ICrossChainMessenger {
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
TransactionRequest
>
):
Promise
<
TransactionRequest
>
/**
* Generates a transaction for depositing some ERC20 tokens into the L2 chain.
*
* @param l1Token Address of the L1 token.
* @param l2Token Address of the L2 token.
* @param amount Amount to deposit.
* @param opts Additional options.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to deposit the tokens.
*/
depositERC20
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
TransactionRequest
>
/**
* Generates a transaction for withdrawing some ERC20 tokens back to the L1 chain.
*
* @param l1Token Address of the L1 token.
* @param l2Token Address of the L2 token.
* @param amount Amount to withdraw.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to withdraw the tokens.
*/
withdrawERC20
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
TransactionRequest
>
}
}
/**
/**
...
@@ -213,7 +298,7 @@ export interface ICrossChainMessenger {
...
@@ -213,7 +298,7 @@ export interface ICrossChainMessenger {
* @param opts Additional options.
* @param opts Additional options.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns
Transaction that can be signed and executed to send the message
.
* @returns
Gas estimate for the transaction
.
*/
*/
sendMessage
:
(
sendMessage
:
(
message
:
CrossChainMessageRequest
,
message
:
CrossChainMessageRequest
,
...
@@ -230,7 +315,7 @@ export interface ICrossChainMessenger {
...
@@ -230,7 +315,7 @@ export interface ICrossChainMessenger {
* @param messageGasLimit New gas limit to use for the message.
* @param messageGasLimit New gas limit to use for the message.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns
Transaction that can be signed and executed to resend the message
.
* @returns
Gas estimate for the transaction
.
*/
*/
resendMessage
(
resendMessage
(
message
:
MessageLike
,
message
:
MessageLike
,
...
@@ -246,7 +331,7 @@ export interface ICrossChainMessenger {
...
@@ -246,7 +331,7 @@ export interface ICrossChainMessenger {
* @param message Message to generate the finalization transaction for.
* @param message Message to generate the finalization transaction for.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns
Transaction that can be signed and executed to finalize the message
.
* @returns
Gas estimate for the transaction
.
*/
*/
finalizeMessage
(
finalizeMessage
(
message
:
MessageLike
,
message
:
MessageLike
,
...
@@ -262,7 +347,7 @@ export interface ICrossChainMessenger {
...
@@ -262,7 +347,7 @@ export interface ICrossChainMessenger {
* @param opts Additional options.
* @param opts Additional options.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns
Transaction that can be signed and executed to deposit the ETH
.
* @returns
Gas estimate for the transaction
.
*/
*/
depositETH
(
depositETH
(
amount
:
NumberLike
,
amount
:
NumberLike
,
...
@@ -278,7 +363,7 @@ export interface ICrossChainMessenger {
...
@@ -278,7 +363,7 @@ export interface ICrossChainMessenger {
* @param amount Amount of ETH to withdraw.
* @param amount Amount of ETH to withdraw.
* @param opts Additional options.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @param opts.overrides Optional transaction overrides.
* @returns
Transaction that can be signed and executed to withdraw the tokens
.
* @returns
Gas estimate for the transaction
.
*/
*/
withdrawETH
(
withdrawETH
(
amount
:
NumberLike
,
amount
:
NumberLike
,
...
@@ -286,5 +371,45 @@ export interface ICrossChainMessenger {
...
@@ -286,5 +371,45 @@ export interface ICrossChainMessenger {
overrides
?:
Overrides
overrides
?:
Overrides
}
}
):
Promise
<
BigNumber
>
):
Promise
<
BigNumber
>
/**
* Estimates gas required to deposit some ERC20 tokens into the L2 chain.
*
* @param l1Token Address of the L1 token.
* @param l2Token Address of the L2 token.
* @param amount Amount to deposit.
* @param opts Additional options.
* @param opts.l2GasLimit Optional gas limit to use for the transaction on L2.
* @param opts.overrides Optional transaction overrides.
* @returns Gas estimate for the transaction.
*/
depositERC20
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
l2GasLimit
?:
NumberLike
overrides
?:
Overrides
}
):
Promise
<
BigNumber
>
/**
* Estimates gas required to withdraw some ERC20 tokens back to the L1 chain.
*
* @param l1Token Address of the L1 token.
* @param l2Token Address of the L2 token.
* @param amount Amount to withdraw.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @returns Gas estimate for the transaction.
*/
withdrawERC20
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
,
amount
:
NumberLike
,
opts
?:
{
overrides
?:
Overrides
}
):
Promise
<
BigNumber
>
}
}
}
}
packages/sdk/src/interfaces/cross-chain-provider.ts
View file @
0bc53656
...
@@ -13,10 +13,11 @@ import {
...
@@ -13,10 +13,11 @@ import {
TokenBridgeMessage
,
TokenBridgeMessage
,
OEContracts
,
OEContracts
,
MessageReceipt
,
MessageReceipt
,
CustomBridges
,
StateRoot
,
StateRoot
,
StateRootBatch
,
StateRootBatch
,
BridgeAdapters
,
}
from
'
./types
'
}
from
'
./types
'
import
{
IBridgeAdapter
}
from
'
./bridge-adapter
'
/**
/**
* Represents the L1/L2 connection. Only handles read requests. If you want to send messages, use
* Represents the L1/L2 connection. Only handles read requests. If you want to send messages, use
...
@@ -46,7 +47,7 @@ export interface ICrossChainProvider {
...
@@ -46,7 +47,7 @@ export interface ICrossChainProvider {
/**
/**
* List of custom bridges for the given network.
* List of custom bridges for the given network.
*/
*/
bridges
:
CustomBridge
s
bridges
:
BridgeAdapter
s
/**
/**
* Retrieves all cross chain messages sent within a given transaction.
* Retrieves all cross chain messages sent within a given transaction.
...
@@ -87,6 +88,19 @@ export interface ICrossChainProvider {
...
@@ -87,6 +88,19 @@ export interface ICrossChainProvider {
}
}
):
Promise
<
CrossChainMessage
[]
>
):
Promise
<
CrossChainMessage
[]
>
/**
* Finds the appropriate bridge adapter for a given L1<>L2 token pair. Will throw if no bridges
* support the token pair or if more than one bridge supports the token pair.
*
* @param l1Token L1 token address.
* @param l2Token L2 token address.
* @returns The appropriate bridge adapter for the given token pair.
*/
getBridgeForTokenPair
(
l1Token
:
AddressLike
,
l2Token
:
AddressLike
):
Promise
<
IBridgeAdapter
>
/**
/**
* Finds all cross chain messages that correspond to token deposits or withdrawals sent by a
* Finds all cross chain messages that correspond to token deposits or withdrawals sent by a
* particular address. Useful for finding deposits/withdrawals because the sender of the message
* particular address. Useful for finding deposits/withdrawals because the sender of the message
...
@@ -96,10 +110,6 @@ export interface ICrossChainProvider {
...
@@ -96,10 +110,6 @@ export interface ICrossChainProvider {
* @param opts Options object.
* @param opts Options object.
* @param opts.direction Direction to search for messages in. If not provided, will attempt to
* @param opts.direction Direction to search for messages in. If not provided, will attempt to
* find all messages in both directions.
* find all messages in both directions.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All token bridge messages sent by the given address.
* @returns All token bridge messages sent by the given address.
*/
*/
getTokenBridgeMessagesByAddress
(
getTokenBridgeMessagesByAddress
(
...
...
packages/sdk/src/interfaces/index.ts
View file @
0bc53656
export
*
from
'
./
cross-chain-erc20-pai
r
'
export
*
from
'
./
bridge-adapte
r
'
export
*
from
'
./cross-chain-messenger
'
export
*
from
'
./cross-chain-messenger
'
export
*
from
'
./cross-chain-provider
'
export
*
from
'
./cross-chain-provider
'
export
*
from
'
./l2-provider
'
export
*
from
'
./l2-provider
'
...
...
packages/sdk/src/interfaces/types.ts
View file @
0bc53656
...
@@ -6,6 +6,9 @@ import {
...
@@ -6,6 +6,9 @@ import {
import
{
Signer
}
from
'
@ethersproject/abstract-signer
'
import
{
Signer
}
from
'
@ethersproject/abstract-signer
'
import
{
Contract
,
BigNumber
}
from
'
ethers
'
import
{
Contract
,
BigNumber
}
from
'
ethers
'
import
{
ICrossChainProvider
}
from
'
./cross-chain-provider
'
import
{
IBridgeAdapter
}
from
'
./bridge-adapter
'
/**
/**
* L1 contract references.
* L1 contract references.
*/
*/
...
@@ -68,27 +71,25 @@ export interface OEContractsLike {
...
@@ -68,27 +71,25 @@ export interface OEContractsLike {
}
}
/**
/**
*
Represents
list of custom bridges.
*
Something that looks like the
list of custom bridges.
*/
*/
export
interface
CustomBridges
{
export
interface
BridgeAdapterData
{
l1
:
{
[
name
:
string
]:
{
[
name
:
string
]:
Contract
Adapter
:
new
(
opts
:
{
}
provider
:
ICrossChainProvider
l2
:
{
l1Bridge
:
AddressLike
[
name
:
string
]:
Contract
l2Bridge
:
AddressLike
})
=>
IBridgeAdapter
l1Bridge
:
AddressLike
l2Bridge
:
AddressLike
}
}
}
}
/**
/**
* Something that looks like the list of custom bridges.
* Something that looks like the list of custom bridges.
*/
*/
export
interface
CustomBridgesLike
{
export
interface
BridgeAdapters
{
l1
:
{
[
name
:
string
]:
IBridgeAdapter
[
K
in
keyof
CustomBridges
[
'
l1
'
]]:
AddressLike
}
l2
:
{
[
K
in
keyof
CustomBridges
[
'
l2
'
]]:
AddressLike
}
}
}
/**
/**
...
...
packages/sdk/src/utils/contracts.ts
View file @
0bc53656
...
@@ -10,9 +10,15 @@ import {
...
@@ -10,9 +10,15 @@ import {
OEContractsLike
,
OEContractsLike
,
OEL2ContractsLike
,
OEL2ContractsLike
,
AddressLike
,
AddressLike
,
CustomBridges
,
BridgeAdapters
,
CustomBridgesLike
,
BridgeAdapterData
,
ICrossChainProvider
,
}
from
'
../interfaces
'
}
from
'
../interfaces
'
import
{
StandardBridgeAdapter
,
ETHBridgeAdapter
,
DAIBridgeAdapter
,
}
from
'
../adapters
'
/**
/**
* Full list of default L2 contract addresses.
* Full list of default L2 contract addresses.
...
@@ -39,42 +45,6 @@ const NAME_REMAPPING = {
...
@@ -39,42 +45,6 @@ const NAME_REMAPPING = {
WETH
:
'
WETH9
'
,
WETH
:
'
WETH9
'
,
}
}
/**
* Mapping of L1 chain IDs to the list of custom bridge addresses for each chain.
*/
export
const
CUSTOM_BRIDGE_ADDRESSES
:
{
[
l1ChainId
:
number
]:
CustomBridgesLike
}
=
{
// TODO: Maybe we can pull these automatically from the token list?
// Alternatively, check against the token list in CI.
1
:
{
l1
:
{
SNX
:
'
0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068
'
,
DAI
:
'
0x10E6593CDda8c58a1d0f14C5164B376352a55f2F
'
,
BitBTC
:
'
0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128
'
,
},
l2
:
{
SNX
:
'
0x3f87Ff1de58128eF8FCb4c807eFD776E1aC72E51
'
,
DAI
:
'
0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65
'
,
BitBTC
:
'
0x158F513096923fF2d3aab2BcF4478536de6725e2
'
,
},
},
42
:
{
l1
:
{
SNX
:
'
0xD134Db47DDF5A6feB245452af17cCAf92ee53D3c
'
,
DAI
:
'
0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3
'
,
BitBTC
:
'
0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746
'
,
USX
:
'
0x40E862341b2416345F02c41Ac70df08525150dC7
'
,
},
l2
:
{
SNX
:
'
0x5C3f51CEd0C2F6157e2be67c029264D6C44bfe42
'
,
DAI
:
'
0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65
'
,
BitBTC
:
'
0x0CFb46528a7002a7D8877a5F7a69b9AaF1A9058e
'
,
USX
:
'
0xB4d37826b14Cd3CB7257A2A5094507d701fe715f
'
,
},
},
}
/**
/**
* Mapping of L1 chain IDs to the appropriate contract addresses for the OE deployments to the
* Mapping of L1 chain IDs to the appropriate contract addresses for the OE deployments to the
* given network. Simplifies the process of getting the correct contract addresses for a given
* given network. Simplifies the process of getting the correct contract addresses for a given
...
@@ -135,6 +105,93 @@ export const CONTRACT_ADDRESSES: {
...
@@ -135,6 +105,93 @@ export const CONTRACT_ADDRESSES: {
},
},
}
}
/**
* Mapping of L1 chain IDs to the list of custom bridge addresses for each chain.
*/
export
const
BRIDGE_ADAPTER_DATA
:
{
[
l1ChainId
:
number
]:
BridgeAdapterData
}
=
{
// TODO: Maybe we can pull these automatically from the token list?
// Alternatively, check against the token list in CI.
1
:
{
Standard
:
{
Adapter
:
StandardBridgeAdapter
,
l1Bridge
:
CONTRACT_ADDRESSES
[
1
].
l1
.
L1StandardBridge
,
l2Bridge
:
predeploys
.
L2StandardBridge
,
},
ETH
:
{
Adapter
:
ETHBridgeAdapter
,
l1Bridge
:
CONTRACT_ADDRESSES
[
1
].
l1
.
L1StandardBridge
,
l2Bridge
:
predeploys
.
L2StandardBridge
,
},
BitBTC
:
{
Adapter
:
StandardBridgeAdapter
,
l1Bridge
:
'
0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128
'
,
l2Bridge
:
'
0x158F513096923fF2d3aab2BcF4478536de6725e2
'
,
},
DAI
:
{
Adapter
:
DAIBridgeAdapter
,
l1Bridge
:
'
0x10E6593CDda8c58a1d0f14C5164B376352a55f2F
'
,
l2Bridge
:
'
0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65
'
,
},
},
42
:
{
Standard
:
{
Adapter
:
StandardBridgeAdapter
,
l1Bridge
:
CONTRACT_ADDRESSES
[
42
].
l1
.
L1StandardBridge
,
l2Bridge
:
predeploys
.
L2StandardBridge
,
},
ETH
:
{
Adapter
:
ETHBridgeAdapter
,
l1Bridge
:
CONTRACT_ADDRESSES
[
42
].
l1
.
L1StandardBridge
,
l2Bridge
:
predeploys
.
L2StandardBridge
,
},
BitBTC
:
{
Adapter
:
StandardBridgeAdapter
,
l1Bridge
:
'
0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746
'
,
l2Bridge
:
'
0x0CFb46528a7002a7D8877a5F7a69b9AaF1A9058e
'
,
},
USX
:
{
Adapter
:
StandardBridgeAdapter
,
l1Bridge
:
'
0x40E862341b2416345F02c41Ac70df08525150dC7
'
,
l2Bridge
:
'
0xB4d37826b14Cd3CB7257A2A5094507d701fe715f
'
,
},
DAI
:
{
Adapter
:
DAIBridgeAdapter
,
l1Bridge
:
'
0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3
'
,
l2Bridge
:
'
0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65
'
,
},
},
5
:
{
Standard
:
{
Adapter
:
StandardBridgeAdapter
,
l1Bridge
:
CONTRACT_ADDRESSES
[
5
].
l1
.
L1StandardBridge
,
l2Bridge
:
predeploys
.
L2StandardBridge
,
},
ETH
:
{
Adapter
:
ETHBridgeAdapter
,
l1Bridge
:
CONTRACT_ADDRESSES
[
5
].
l1
.
L1StandardBridge
,
l2Bridge
:
predeploys
.
L2StandardBridge
,
},
},
}
// TODO: PR is big enough as-is, will add support for SNX in another PR
// MAINNET
// l1: {
// SNX: '0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068',
// },
// l2: {
// SNX: '0x3f87Ff1de58128eF8FCb4c807eFD776E1aC72E51',
// },
// KOVAN
// l1: {
// SNX: '0xD134Db47DDF5A6feB245452af17cCAf92ee53D3c',
// },
// l2: {
// SNX: '0x5C3f51CEd0C2F6157e2be67c029264D6C44bfe42',
// },
/**
/**
* Returns an ethers.Contract object for the given name, connected to the appropriate address for
* Returns an ethers.Contract object for the given name, connected to the appropriate address for
* the given L1 chain ID. Users can also provide a custom address to connect the contract to
* the given L1 chain ID. Users can also provide a custom address to connect the contract to
...
@@ -231,57 +288,32 @@ export const getAllOEContracts = (
...
@@ -231,57 +288,32 @@ export const getAllOEContracts = (
}
}
/**
/**
* Gets a series of
custom bridge
s for the given L1 chain ID.
* Gets a series of
bridge adapter
s for the given L1 chain ID.
*
*
* @param l1ChainId L1 chain ID for the L1 network where the custom bridges are deployed.
* @param l1ChainId L1 chain ID for the L1 network where the custom bridges are deployed.
* @param provider Cross chain provider to connect to the bridge adapters
* @param opts Additional options for connecting to the custom bridges.
* @param opts Additional options for connecting to the custom bridges.
* @param opts.l1SignerOrProvider Signer or provider to connect to the L1 contracts.
* @param opts.overrides Custom bridge adapters.
* @param opts.l2SignerOrProvider Signer or provider to connect to the L2 contracts.
* @returns An object containing all bridge adapters
* @param opts.overrides Custom contract address overrides for L1 or L2 contracts.
* @returns An object containing ethers.Contract objects connected to the appropriate addresses on
* both L1 and L2.
*/
*/
export
const
get
CustomBridge
s
=
(
export
const
get
BridgeAdapter
s
=
(
l1ChainId
:
number
,
l1ChainId
:
number
,
opts
:
{
provider
:
ICrossChainProvider
,
l1SignerOrProvider
?:
ethers
.
Signer
|
ethers
.
providers
.
Provider
opts
?:
{
l2SignerOrProvider
?:
ethers
.
Signer
|
ethers
.
providers
.
Provider
overrides
?:
BridgeAdapterData
overrides
?:
Partial
<
CustomBridgesLike
>
}
=
{}
):
CustomBridges
=>
{
const
addresses
=
CUSTOM_BRIDGE_ADDRESSES
[
l1ChainId
]
||
{
l1
:
{},
l2
:
{},
}
for
(
const
[
contractName
,
contractAddress
]
of
Object
.
entries
(
opts
.
overrides
?.
l1
||
{}
))
{
addresses
.
l1
[
contractName
]
=
contractAddress
}
}
for
(
const
[
contractName
,
contractAddress
]
of
Object
.
entries
(
):
BridgeAdapters
=>
{
opts
.
overrides
?.
l2
||
{}
const
adapters
:
BridgeAdapters
=
{}
))
{
for
(
const
[
bridgeName
,
bridgeData
]
of
Object
.
entries
({
addresses
.
l2
[
contractName
]
=
contractAddress
...(
BRIDGE_ADAPTER_DATA
[
l1ChainId
]
||
{}),
}
...(
opts
?.
overrides
||
{}),
}))
{
const
bridges
=
{
adapters
[
bridgeName
]
=
new
bridgeData
.
Adapter
({
l1
:
{},
provider
,
l2
:
{},
l1Bridge
:
bridgeData
.
l1Bridge
,
}
l2Bridge
:
bridgeData
.
l2Bridge
,
for
(
const
[
contractName
,
contractAddress
]
of
Object
.
entries
(
addresses
.
l1
))
{
})
bridges
.
l1
[
contractName
]
=
new
Contract
(
toAddress
(
contractAddress
),
getContractInterface
(
'
IL1ERC20Bridge
'
),
opts
.
l1SignerOrProvider
)
}
for
(
const
[
contractName
,
contractAddress
]
of
Object
.
entries
(
addresses
.
l2
))
{
bridges
.
l2
[
contractName
]
=
new
Contract
(
toAddress
(
contractAddress
),
getContractInterface
(
'
IL2ERC20Bridge
'
),
opts
.
l2SignerOrProvider
)
}
}
return
bridge
s
return
adapter
s
}
}
packages/sdk/test/cross-chain-erc20-pair.spec.ts
deleted
100644 → 0
View file @
81d90563
import
'
./setup
'
describe
(
'
CrossChainERC20Pair
'
,
()
=>
{
describe
(
'
construction
'
,
()
=>
{
it
(
'
should have a messenger
'
)
describe
(
'
when the token is a standard bridge token
'
,
()
=>
{
it
(
'
should resolve the correct bridge
'
)
})
describe
(
'
when the token is SNX
'
,
()
=>
{
it
(
'
should resolve the correct bridge
'
)
})
describe
(
'
when the token is DAI
'
,
()
=>
{
it
(
'
should resolve the correct bridge
'
)
})
describe
(
'
when a custom adapter is provided
'
,
()
=>
{
it
(
'
should use the custom adapter
'
)
})
})
describe
(
'
deposit
'
,
()
=>
{
describe
(
'
when the user has enough balance and allowance
'
,
()
=>
{
describe
(
'
when the token is a standard bridge token
'
,
()
=>
{
it
(
'
should trigger a token deposit
'
)
})
describe
(
'
when the token is ETH
'
,
()
=>
{
it
(
'
should trigger a token deposit
'
)
})
describe
(
'
when the token is SNX
'
,
()
=>
{
it
(
'
should trigger a token deposit
'
)
})
describe
(
'
when the token is DAI
'
,
()
=>
{
it
(
'
should trigger a token deposit
'
)
})
})
describe
(
'
when the user does not have enough balance
'
,
()
=>
{
it
(
'
should throw an error
'
)
})
describe
(
'
when the user has not given enough allowance to the bridge
'
,
()
=>
{
it
(
'
should throw an error
'
)
})
})
describe
(
'
withdraw
'
,
()
=>
{
describe
(
'
when the user has enough balance
'
,
()
=>
{
describe
(
'
when the token is a standard bridge token
'
,
()
=>
{
it
(
'
should trigger a token withdrawal
'
)
})
describe
(
'
when the token is ETH
'
,
()
=>
{
it
(
'
should trigger a token withdrawal
'
)
})
describe
(
'
when the token is SNX
'
,
()
=>
{
it
(
'
should trigger a token withdrawal
'
)
})
describe
(
'
when the token is DAI
'
,
()
=>
{
it
(
'
should trigger a token withdrawal
'
)
})
})
describe
(
'
when the user does not have enough balance
'
,
()
=>
{
it
(
'
should throw an error
'
)
})
})
describe
(
'
populateTransaction
'
,
()
=>
{
describe
(
'
deposit
'
,
()
=>
{
it
(
'
should populate the transaction with the correct values
'
)
})
describe
(
'
withdraw
'
,
()
=>
{
it
(
'
should populate the transaction with the correct values
'
)
})
})
describe
(
'
estimateGas
'
,
()
=>
{
describe
(
'
deposit
'
,
()
=>
{
it
(
'
should estimate gas required for the transaction
'
)
})
describe
(
'
withdraw
'
,
()
=>
{
it
(
'
should estimate gas required for the transaction
'
)
})
})
})
packages/sdk/test/cross-chain-messenger.spec.ts
View file @
0bc53656
...
@@ -7,6 +7,7 @@ import {
...
@@ -7,6 +7,7 @@ import {
CrossChainProvider
,
CrossChainProvider
,
CrossChainMessenger
,
CrossChainMessenger
,
MessageDirection
,
MessageDirection
,
ETHBridgeAdapter
,
}
from
'
../src
'
}
from
'
../src
'
describe
(
'
CrossChainMessenger
'
,
()
=>
{
describe
(
'
CrossChainMessenger
'
,
()
=>
{
...
@@ -215,7 +216,9 @@ describe('CrossChainMessenger', () => {
...
@@ -215,7 +216,9 @@ describe('CrossChainMessenger', () => {
describe
(
'
depositETH
'
,
()
=>
{
describe
(
'
depositETH
'
,
()
=>
{
let
l1Messenger
:
Contract
let
l1Messenger
:
Contract
let
l2Messenger
:
Contract
let
l1Bridge
:
Contract
let
l1Bridge
:
Contract
let
l2Bridge
:
Contract
let
provider
:
CrossChainProvider
let
provider
:
CrossChainProvider
let
messenger
:
CrossChainMessenger
let
messenger
:
CrossChainMessenger
beforeEach
(
async
()
=>
{
beforeEach
(
async
()
=>
{
...
@@ -225,6 +228,12 @@ describe('CrossChainMessenger', () => {
...
@@ -225,6 +228,12 @@ describe('CrossChainMessenger', () => {
l1Bridge
=
(
await
(
l1Bridge
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockBridge
'
)
await
ethers
.
getContractFactory
(
'
MockBridge
'
)
).
deploy
(
l1Messenger
.
address
))
as
any
).
deploy
(
l1Messenger
.
address
))
as
any
l2Messenger
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockMessenger
'
)
).
deploy
())
as
any
l2Bridge
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockBridge
'
)
).
deploy
(
l2Messenger
.
address
))
as
any
provider
=
new
CrossChainProvider
({
provider
=
new
CrossChainProvider
({
l1Provider
:
ethers
.
provider
,
l1Provider
:
ethers
.
provider
,
...
@@ -235,6 +244,17 @@ describe('CrossChainMessenger', () => {
...
@@ -235,6 +244,17 @@ describe('CrossChainMessenger', () => {
L1CrossDomainMessenger
:
l1Messenger
.
address
,
L1CrossDomainMessenger
:
l1Messenger
.
address
,
L1StandardBridge
:
l1Bridge
.
address
,
L1StandardBridge
:
l1Bridge
.
address
,
},
},
l2
:
{
L2CrossDomainMessenger
:
l2Messenger
.
address
,
L2StandardBridge
:
l2Bridge
.
address
,
},
},
bridges
:
{
ETH
:
{
Adapter
:
ETHBridgeAdapter
,
l1Bridge
:
l1Bridge
.
address
,
l2Bridge
:
l2Bridge
.
address
,
},
},
},
})
})
...
@@ -258,11 +278,19 @@ describe('CrossChainMessenger', () => {
...
@@ -258,11 +278,19 @@ describe('CrossChainMessenger', () => {
})
})
describe
(
'
withdrawETH
'
,
()
=>
{
describe
(
'
withdrawETH
'
,
()
=>
{
let
l1Messenger
:
Contract
let
l2Messenger
:
Contract
let
l2Messenger
:
Contract
let
l1Bridge
:
Contract
let
l2Bridge
:
Contract
let
l2Bridge
:
Contract
let
provider
:
CrossChainProvider
let
provider
:
CrossChainProvider
let
messenger
:
CrossChainMessenger
let
messenger
:
CrossChainMessenger
beforeEach
(
async
()
=>
{
beforeEach
(
async
()
=>
{
l1Messenger
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockMessenger
'
)
).
deploy
())
as
any
l1Bridge
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockBridge
'
)
).
deploy
(
l1Messenger
.
address
))
as
any
l2Messenger
=
(
await
(
l2Messenger
=
(
await
(
await
ethers
.
getContractFactory
(
'
MockMessenger
'
)
await
ethers
.
getContractFactory
(
'
MockMessenger
'
)
).
deploy
())
as
any
).
deploy
())
as
any
...
@@ -275,11 +303,22 @@ describe('CrossChainMessenger', () => {
...
@@ -275,11 +303,22 @@ describe('CrossChainMessenger', () => {
l2Provider
:
ethers
.
provider
,
l2Provider
:
ethers
.
provider
,
l1ChainId
:
31337
,
l1ChainId
:
31337
,
contracts
:
{
contracts
:
{
l1
:
{
L1CrossDomainMessenger
:
l1Messenger
.
address
,
L1StandardBridge
:
l1Bridge
.
address
,
},
l2
:
{
l2
:
{
L2CrossDomainMessenger
:
l2Messenger
.
address
,
L2CrossDomainMessenger
:
l2Messenger
.
address
,
L2StandardBridge
:
l2Bridge
.
address
,
L2StandardBridge
:
l2Bridge
.
address
,
},
},
},
},
bridges
:
{
ETH
:
{
Adapter
:
ETHBridgeAdapter
,
l1Bridge
:
l1Bridge
.
address
,
l2Bridge
:
l2Bridge
.
address
,
},
},
})
})
messenger
=
new
CrossChainMessenger
({
messenger
=
new
CrossChainMessenger
({
...
...
packages/sdk/test/cross-chain-provider.spec.ts
View file @
0bc53656
...
@@ -12,6 +12,7 @@ import {
...
@@ -12,6 +12,7 @@ import {
omit
,
omit
,
MessageStatus
,
MessageStatus
,
CrossChainMessage
,
CrossChainMessage
,
StandardBridgeAdapter
,
}
from
'
../src
'
}
from
'
../src
'
import
{
DUMMY_MESSAGE
}
from
'
./helpers
'
import
{
DUMMY_MESSAGE
}
from
'
./helpers
'
...
@@ -434,6 +435,13 @@ describe('CrossChainProvider', () => {
...
@@ -434,6 +435,13 @@ describe('CrossChainProvider', () => {
L2StandardBridge
:
l2Bridge
.
address
,
L2StandardBridge
:
l2Bridge
.
address
,
},
},
},
},
bridges
:
{
Standard
:
{
Adapter
:
StandardBridgeAdapter
,
l1Bridge
:
l1Bridge
.
address
,
l2Bridge
:
l2Bridge
.
address
,
},
},
})
})
})
})
...
@@ -566,71 +574,6 @@ describe('CrossChainProvider', () => {
...
@@ -566,71 +574,6 @@ describe('CrossChainProvider', () => {
expect
(
found
[
1
].
to
).
to
.
deep
.
equal
(
withdrawal
.
to
)
expect
(
found
[
1
].
to
).
to
.
deep
.
equal
(
withdrawal
.
to
)
})
})
})
})
describe
(
'
when a block range is specified
'
,
()
=>
{
describe
(
'
when a direction is specified
'
,
()
=>
{
it
(
'
should find all deposits or withdrawals only in the given direction and within the block range
'
,
async
()
=>
{
const
from
=
'
0x
'
+
'
99
'
.
repeat
(
20
)
const
deposit1
=
{
l1Token
:
'
0x
'
+
'
11
'
.
repeat
(
20
),
l2Token
:
'
0x
'
+
'
22
'
.
repeat
(
20
),
from
,
to
:
'
0x
'
+
'
44
'
.
repeat
(
20
),
amount
:
ethers
.
BigNumber
.
from
(
1234
),
data
:
'
0x1234
'
,
}
const
deposit2
=
{
l1Token
:
'
0x
'
+
'
33
'
.
repeat
(
20
),
l2Token
:
'
0x
'
+
'
44
'
.
repeat
(
20
),
from
,
to
:
'
0x
'
+
'
55
'
.
repeat
(
20
),
amount
:
ethers
.
BigNumber
.
from
(
1234
),
data
:
'
0x1234
'
,
}
const
withdrawal
=
{
l1Token
:
'
0x
'
+
'
12
'
.
repeat
(
20
),
l2Token
:
'
0x
'
+
'
23
'
.
repeat
(
20
),
from
,
to
:
'
0x
'
+
'
45
'
.
repeat
(
20
),
amount
:
ethers
.
BigNumber
.
from
(
5678
),
data
:
'
0x5678
'
,
}
await
l1Bridge
.
emitERC20DepositInitiated
(
deposit1
)
const
tx
=
await
l1Bridge
.
emitERC20DepositInitiated
(
deposit2
)
await
l2Bridge
.
emitWithdrawalInitiated
(
withdrawal
)
const
found
=
await
provider
.
getTokenBridgeMessagesByAddress
(
from
,
{
direction
:
MessageDirection
.
L1_TO_L2
,
fromBlock
:
tx
.
blockNumber
,
})
expect
(
found
.
length
).
to
.
equal
(
1
)
expect
(
found
[
0
].
amount
).
to
.
deep
.
equal
(
deposit2
.
amount
)
expect
(
found
[
0
].
data
).
to
.
deep
.
equal
(
deposit2
.
data
)
expect
(
found
[
0
].
direction
).
to
.
equal
(
MessageDirection
.
L1_TO_L2
)
expect
(
found
[
0
].
l1Token
).
to
.
deep
.
equal
(
deposit2
.
l1Token
)
expect
(
found
[
0
].
l2Token
).
to
.
deep
.
equal
(
deposit2
.
l2Token
)
expect
(
found
[
0
].
from
).
to
.
deep
.
equal
(
deposit2
.
from
)
expect
(
found
[
0
].
to
).
to
.
deep
.
equal
(
deposit2
.
to
)
})
})
describe
(
'
when a direction is not specified
'
,
()
=>
{
it
(
'
should throw an error
'
,
async
()
=>
{
const
from
=
'
0x
'
+
'
99
'
.
repeat
(
20
)
await
expect
(
provider
.
getTokenBridgeMessagesByAddress
(
from
,
{
fromBlock
:
0
,
toBlock
:
100
,
})
).
to
.
be
.
rejectedWith
(
'
direction must be specified
'
)
})
})
})
})
})
describe
(
'
when the address has not made any deposits or withdrawals
'
,
()
=>
{
describe
(
'
when the address has not made any deposits or withdrawals
'
,
()
=>
{
...
@@ -676,6 +619,13 @@ describe('CrossChainProvider', () => {
...
@@ -676,6 +619,13 @@ describe('CrossChainProvider', () => {
L2StandardBridge
:
l2Bridge
.
address
,
L2StandardBridge
:
l2Bridge
.
address
,
},
},
},
},
bridges
:
{
Standard
:
{
Adapter
:
StandardBridgeAdapter
,
l1Bridge
:
l1Bridge
.
address
,
l2Bridge
:
l2Bridge
.
address
,
},
},
})
})
})
})
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment