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
e4ca19e1
Unverified
Commit
e4ca19e1
authored
Jun 29, 2023
by
OptimismBot
Committed by
GitHub
Jun 29, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6053 from ethereum-optimism/willc/multiwithdraw-no-test
fix(sdk): Fix multicall3 support for sdk
parents
13c710c7
19e70598
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
176 additions
and
75 deletions
+176
-75
cuddly-panthers-trade.md
.changeset/cuddly-panthers-trade.md
+5
-0
cross-chain-messenger.ts
packages/sdk/src/cross-chain-messenger.ts
+164
-70
cross-chain-messenger.spec.ts
packages/sdk/test/cross-chain-messenger.spec.ts
+7
-5
No files found.
.changeset/cuddly-panthers-trade.md
0 → 100644
View file @
e4ca19e1
---
'
@eth-optimism/sdk'
:
minor
---
Add support for claiming multicall3 withdrawals
packages/sdk/src/cross-chain-messenger.ts
View file @
e4ca19e1
...
@@ -329,9 +329,13 @@ export class CrossChainMessenger {
...
@@ -329,9 +329,13 @@ export class CrossChainMessenger {
* @returns Bedrock representation of the message.
* @returns Bedrock representation of the message.
*/
*/
public
async
toBedrockCrossChainMessage
(
public
async
toBedrockCrossChainMessage
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
CrossChainMessage
>
{
):
Promise
<
CrossChainMessage
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
// Bedrock messages are already in the correct format.
// Bedrock messages are already in the correct format.
const
{
version
}
=
decodeVersionedNonce
(
resolved
.
messageNonce
)
const
{
version
}
=
decodeVersionedNonce
(
resolved
.
messageNonce
)
...
@@ -375,9 +379,13 @@ export class CrossChainMessenger {
...
@@ -375,9 +379,13 @@ export class CrossChainMessenger {
* @return Transformed message.
* @return Transformed message.
*/
*/
public
async
toLowLevelMessage
(
public
async
toLowLevelMessage
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
LowLevelMessage
>
{
):
Promise
<
LowLevelMessage
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
throw
new
Error
(
`can only convert L2 to L1 messages to low level`
)
throw
new
Error
(
`can only convert L2 to L1 messages to low level`
)
}
}
...
@@ -386,7 +394,7 @@ export class CrossChainMessenger {
...
@@ -386,7 +394,7 @@ export class CrossChainMessenger {
const
{
version
}
=
decodeVersionedNonce
(
resolved
.
messageNonce
)
const
{
version
}
=
decodeVersionedNonce
(
resolved
.
messageNonce
)
let
updated
:
CrossChainMessage
let
updated
:
CrossChainMessage
if
(
version
.
eq
(
0
))
{
if
(
version
.
eq
(
0
))
{
updated
=
await
this
.
toBedrockCrossChainMessage
(
resolved
)
updated
=
await
this
.
toBedrockCrossChainMessage
(
resolved
,
messageIndex
)
}
else
{
}
else
{
updated
=
resolved
updated
=
resolved
}
}
...
@@ -401,6 +409,8 @@ export class CrossChainMessenger {
...
@@ -401,6 +409,8 @@ export class CrossChainMessenger {
updated
.
message
updated
.
message
)
)
// EVERYTHING following here is basically repeating the logic from getMessagesByTransaction
// consider cleaning this up
// We need to figure out the final withdrawal data that was used to compute the withdrawal hash
// We need to figure out the final withdrawal data that was used to compute the withdrawal hash
// inside the L2ToL1Message passer contract. Exact mechanism here depends on whether or not
// inside the L2ToL1Message passer contract. Exact mechanism here depends on whether or not
// this is a legacy message or a new Bedrock message.
// this is a legacy message or a new Bedrock message.
...
@@ -412,10 +422,12 @@ export class CrossChainMessenger {
...
@@ -412,10 +422,12 @@ export class CrossChainMessenger {
messageNonce
=
resolved
.
messageNonce
messageNonce
=
resolved
.
messageNonce
}
else
{
}
else
{
const
receipt
=
await
this
.
l2Provider
.
getTransactionReceipt
(
const
receipt
=
await
this
.
l2Provider
.
getTransactionReceipt
(
resolved
.
transactionHash
(
await
this
.
toCrossChainMessage
(
message
)
).
transactionHash
)
)
const
withdrawals
:
any
[]
=
[]
const
withdrawals
:
ethers
.
utils
.
Result
[]
=
[]
for
(
const
log
of
receipt
.
logs
)
{
for
(
const
log
of
receipt
.
logs
)
{
if
(
log
.
address
===
this
.
contracts
.
l2
.
BedrockMessagePasser
.
address
)
{
if
(
log
.
address
===
this
.
contracts
.
l2
.
BedrockMessagePasser
.
address
)
{
const
decoded
=
const
decoded
=
...
@@ -431,12 +443,12 @@ export class CrossChainMessenger {
...
@@ -431,12 +443,12 @@ export class CrossChainMessenger {
throw
new
Error
(
`no withdrawals found in receipt`
)
throw
new
Error
(
`no withdrawals found in receipt`
)
}
}
// TODO: Add support for multiple withdrawals.
const
withdrawal
=
withdrawals
[
messageIndex
]
if
(
withdrawals
.
length
>
1
)
{
if
(
!
withdrawal
)
{
throw
new
Error
(
`multiple withdrawals found in receipt`
)
throw
new
Error
(
`withdrawal index
${
messageIndex
}
out of bounds there are
${
withdrawals
.
length
}
withdrawals`
)
}
}
const
withdrawal
=
withdrawals
[
0
]
messageNonce
=
withdrawal
.
nonce
messageNonce
=
withdrawal
.
nonce
gasLimit
=
withdrawal
.
gasLimit
gasLimit
=
withdrawal
.
gasLimit
}
}
...
@@ -577,7 +589,11 @@ export class CrossChainMessenger {
...
@@ -577,7 +589,11 @@ export class CrossChainMessenger {
* @returns Message coerced into a CrossChainMessage.
* @returns Message coerced into a CrossChainMessage.
*/
*/
public
async
toCrossChainMessage
(
public
async
toCrossChainMessage
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
CrossChainMessage
>
{
):
Promise
<
CrossChainMessage
>
{
if
(
!
message
)
{
if
(
!
message
)
{
throw
new
Error
(
'
message is undefined
'
)
throw
new
Error
(
'
message is undefined
'
)
...
@@ -621,14 +637,13 @@ export class CrossChainMessenger {
...
@@ -621,14 +637,13 @@ export class CrossChainMessenger {
message
as
TransactionLike
message
as
TransactionLike
)
)
// We only want to treat TransactionLike objects as MessageLike if they only emit a single
const
out
=
messages
[
messageIndex
]
// message (very common). It's unintuitive to treat a TransactionLike as a MessageLike if
if
(
!
out
)
{
// they emit more than one message (which message do you pick?), so we throw an error.
throw
new
Error
(
if
(
messages
.
length
!==
1
)
{
`withdrawal index
${
messageIndex
}
out of bounds. There are
${
messages
.
length
}
withdrawals`
throw
new
Error
(
`expected 1 message, got
${
messages
.
length
}
`
)
)
}
}
return
out
return
messages
[
0
]
}
}
}
}
...
@@ -638,9 +653,16 @@ export class CrossChainMessenger {
...
@@ -638,9 +653,16 @@ export class CrossChainMessenger {
* @param message Cross chain message to check the status of.
* @param message Cross chain message to check the status of.
* @returns Status of the message.
* @returns Status of the message.
*/
*/
public
async
getMessageStatus
(
message
:
MessageLike
):
Promise
<
MessageStatus
>
{
public
async
getMessageStatus
(
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
message
:
MessageLike
,
const
receipt
=
await
this
.
getMessageReceipt
(
resolved
)
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
MessageStatus
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
const
receipt
=
await
this
.
getMessageReceipt
(
resolved
,
messageIndex
)
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
receipt
===
null
)
{
if
(
receipt
===
null
)
{
...
@@ -656,13 +678,19 @@ export class CrossChainMessenger {
...
@@ -656,13 +678,19 @@ export class CrossChainMessenger {
if
(
receipt
===
null
)
{
if
(
receipt
===
null
)
{
let
timestamp
:
number
let
timestamp
:
number
if
(
this
.
bedrock
)
{
if
(
this
.
bedrock
)
{
const
output
=
await
this
.
getMessageBedrockOutput
(
resolved
)
const
output
=
await
this
.
getMessageBedrockOutput
(
resolved
,
messageIndex
)
if
(
output
===
null
)
{
if
(
output
===
null
)
{
return
MessageStatus
.
STATE_ROOT_NOT_PUBLISHED
return
MessageStatus
.
STATE_ROOT_NOT_PUBLISHED
}
}
// Convert the message to the low level message that was proven.
// Convert the message to the low level message that was proven.
const
withdrawal
=
await
this
.
toLowLevelMessage
(
resolved
)
const
withdrawal
=
await
this
.
toLowLevelMessage
(
resolved
,
messageIndex
)
// Attempt to fetch the proven withdrawal.
// Attempt to fetch the proven withdrawal.
const
provenWithdrawal
=
const
provenWithdrawal
=
...
@@ -679,7 +707,10 @@ export class CrossChainMessenger {
...
@@ -679,7 +707,10 @@ export class CrossChainMessenger {
// Set the timestamp to the provenWithdrawal's timestamp
// Set the timestamp to the provenWithdrawal's timestamp
timestamp
=
provenWithdrawal
.
timestamp
.
toNumber
()
timestamp
=
provenWithdrawal
.
timestamp
.
toNumber
()
}
else
{
}
else
{
const
stateRoot
=
await
this
.
getMessageStateRoot
(
resolved
)
const
stateRoot
=
await
this
.
getMessageStateRoot
(
resolved
,
messageIndex
)
if
(
stateRoot
===
null
)
{
if
(
stateRoot
===
null
)
{
return
MessageStatus
.
STATE_ROOT_NOT_PUBLISHED
return
MessageStatus
.
STATE_ROOT_NOT_PUBLISHED
}
}
...
@@ -715,9 +746,14 @@ export class CrossChainMessenger {
...
@@ -715,9 +746,14 @@ export class CrossChainMessenger {
* given message.
* given message.
*/
*/
public
async
getMessageReceipt
(
public
async
getMessageReceipt
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
MessageReceipt
>
{
):
Promise
<
MessageReceipt
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
// legacy withdrawals relayed prebedrock are v1
// legacy withdrawals relayed prebedrock are v1
const
messageHashV0
=
hashCrossDomainMessagev0
(
const
messageHashV0
=
hashCrossDomainMessagev0
(
resolved
.
target
,
resolved
.
target
,
...
@@ -819,15 +855,20 @@ export class CrossChainMessenger {
...
@@ -819,15 +855,20 @@ export class CrossChainMessenger {
confirmations
?:
number
confirmations
?:
number
pollIntervalMs
?:
number
pollIntervalMs
?:
number
timeoutMs
?:
number
timeoutMs
?:
number
}
=
{}
}
=
{},
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
MessageReceipt
>
{
):
Promise
<
MessageReceipt
>
{
// Resolving once up-front is slightly more efficient.
// Resolving once up-front is slightly more efficient.
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
let
totalTimeMs
=
0
let
totalTimeMs
=
0
while
(
totalTimeMs
<
(
opts
.
timeoutMs
||
Infinity
))
{
while
(
totalTimeMs
<
(
opts
.
timeoutMs
||
Infinity
))
{
const
tick
=
Date
.
now
()
const
tick
=
Date
.
now
()
const
receipt
=
await
this
.
getMessageReceipt
(
resolved
)
const
receipt
=
await
this
.
getMessageReceipt
(
resolved
,
messageIndex
)
if
(
receipt
!==
null
)
{
if
(
receipt
!==
null
)
{
return
receipt
return
receipt
}
else
{
}
else
{
...
@@ -857,15 +898,20 @@ export class CrossChainMessenger {
...
@@ -857,15 +898,20 @@ export class CrossChainMessenger {
opts
:
{
opts
:
{
pollIntervalMs
?:
number
pollIntervalMs
?:
number
timeoutMs
?:
number
timeoutMs
?:
number
}
=
{}
}
=
{},
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
void
>
{
):
Promise
<
void
>
{
// Resolving once up-front is slightly more efficient.
// Resolving once up-front is slightly more efficient.
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
let
totalTimeMs
=
0
let
totalTimeMs
=
0
while
(
totalTimeMs
<
(
opts
.
timeoutMs
||
Infinity
))
{
while
(
totalTimeMs
<
(
opts
.
timeoutMs
||
Infinity
))
{
const
tick
=
Date
.
now
()
const
tick
=
Date
.
now
()
const
currentStatus
=
await
this
.
getMessageStatus
(
resolved
)
const
currentStatus
=
await
this
.
getMessageStatus
(
resolved
,
messageIndex
)
// Handle special cases for L1 to L2 messages.
// Handle special cases for L1 to L2 messages.
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
...
@@ -933,7 +979,8 @@ export class CrossChainMessenger {
...
@@ -933,7 +979,8 @@ export class CrossChainMessenger {
opts
?:
{
opts
?:
{
bufferPercent
?:
number
bufferPercent
?:
number
from
?:
string
from
?:
string
}
},
messageIndex
=
0
):
Promise
<
BigNumber
>
{
):
Promise
<
BigNumber
>
{
let
resolved
:
CrossChainMessage
|
CrossChainMessageRequest
let
resolved
:
CrossChainMessage
|
CrossChainMessageRequest
let
from
:
string
let
from
:
string
...
@@ -941,7 +988,10 @@ export class CrossChainMessenger {
...
@@ -941,7 +988,10 @@ export class CrossChainMessenger {
resolved
=
message
as
CrossChainMessageRequest
resolved
=
message
as
CrossChainMessageRequest
from
=
opts
?.
from
from
=
opts
?.
from
}
else
{
}
else
{
resolved
=
await
this
.
toCrossChainMessage
(
message
as
MessageLike
)
resolved
=
await
this
.
toCrossChainMessage
(
message
as
MessageLike
,
messageIndex
)
from
=
opts
?.
from
||
(
resolved
as
CrossChainMessage
).
sender
from
=
opts
?.
from
||
(
resolved
as
CrossChainMessage
).
sender
}
}
...
@@ -971,10 +1021,15 @@ export class CrossChainMessenger {
...
@@ -971,10 +1021,15 @@ export class CrossChainMessenger {
* @returns Estimated amount of time remaining (in seconds) before the message can be executed.
* @returns Estimated amount of time remaining (in seconds) before the message can be executed.
*/
*/
public
async
estimateMessageWaitTimeSeconds
(
public
async
estimateMessageWaitTimeSeconds
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
number
>
{
):
Promise
<
number
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
const
status
=
await
this
.
getMessageStatus
(
resolved
)
const
status
=
await
this
.
getMessageStatus
(
resolved
,
messageIndex
)
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
if
(
status
===
MessageStatus
.
RELAYED
||
status
===
MessageStatus
.
RELAYED
||
...
@@ -1012,7 +1067,7 @@ export class CrossChainMessenger {
...
@@ -1012,7 +1067,7 @@ export class CrossChainMessenger {
// If the message is still within the challenge period, then we need to estimate exactly
// If the message is still within the challenge period, then we need to estimate exactly
// the amount of time left until the challenge period expires. The challenge period starts
// the amount of time left until the challenge period expires. The challenge period starts
// when the state root is published.
// when the state root is published.
const
stateRoot
=
await
this
.
getMessageStateRoot
(
resolved
)
const
stateRoot
=
await
this
.
getMessageStateRoot
(
resolved
,
messageIndex
)
const
challengePeriod
=
await
this
.
getChallengePeriodSeconds
()
const
challengePeriod
=
await
this
.
getChallengePeriodSeconds
()
const
targetBlock
=
await
this
.
l1Provider
.
getBlock
(
const
targetBlock
=
await
this
.
l1Provider
.
getBlock
(
stateRoot
.
batch
.
blockNumber
stateRoot
.
batch
.
blockNumber
...
@@ -1045,13 +1100,13 @@ export class CrossChainMessenger {
...
@@ -1045,13 +1100,13 @@ export class CrossChainMessenger {
const
challengePeriod
=
const
challengePeriod
=
oracleVersion
===
'
1.0.0
'
oracleVersion
===
'
1.0.0
'
?
// The ABI in the SDK does not contain FINALIZATION_PERIOD_SECONDS
?
// The ABI in the SDK does not contain FINALIZATION_PERIOD_SECONDS
// in OptimismPortal, so making an explicit call instead.
// in OptimismPortal, so making an explicit call instead.
BigNumber
.
from
(
BigNumber
.
from
(
await
this
.
contracts
.
l1
.
OptimismPortal
.
provider
.
call
({
await
this
.
contracts
.
l1
.
OptimismPortal
.
provider
.
call
({
to
:
this
.
contracts
.
l1
.
OptimismPortal
.
address
,
to
:
this
.
contracts
.
l1
.
OptimismPortal
.
address
,
data
:
'
0xf4daa291
'
,
// FINALIZATION_PERIOD_SECONDS
data
:
'
0xf4daa291
'
,
// FINALIZATION_PERIOD_SECONDS
})
})
)
)
:
await
this
.
contracts
.
l1
.
L2OutputOracle
.
FINALIZATION_PERIOD_SECONDS
()
:
await
this
.
contracts
.
l1
.
L2OutputOracle
.
FINALIZATION_PERIOD_SECONDS
()
return
challengePeriod
.
toNumber
()
return
challengePeriod
.
toNumber
()
}
}
...
@@ -1082,9 +1137,14 @@ export class CrossChainMessenger {
...
@@ -1082,9 +1137,14 @@ export class CrossChainMessenger {
* @returns Bedrock output root.
* @returns Bedrock output root.
*/
*/
public
async
getMessageBedrockOutput
(
public
async
getMessageBedrockOutput
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
BedrockOutputData
|
null
>
{
):
Promise
<
BedrockOutputData
|
null
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
// Outputs are only a thing for L2 to L1 messages.
// Outputs are only a thing for L2 to L1 messages.
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
...
@@ -1133,9 +1193,14 @@ export class CrossChainMessenger {
...
@@ -1133,9 +1193,14 @@ export class CrossChainMessenger {
* @returns State root for the block in which the message was created.
* @returns State root for the block in which the message was created.
*/
*/
public
async
getMessageStateRoot
(
public
async
getMessageStateRoot
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
StateRoot
|
null
>
{
):
Promise
<
StateRoot
|
null
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
// State roots are only a thing for L2 to L1 messages.
// State roots are only a thing for L2 to L1 messages.
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
...
@@ -1318,14 +1383,19 @@ export class CrossChainMessenger {
...
@@ -1318,14 +1383,19 @@ export class CrossChainMessenger {
* @returns Proof that can be used to finalize the message.
* @returns Proof that can be used to finalize the message.
*/
*/
public
async
getMessageProof
(
public
async
getMessageProof
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
CrossChainMessageProof
>
{
):
Promise
<
CrossChainMessageProof
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
throw
new
Error
(
`can only generate proofs for L2 to L1 messages`
)
throw
new
Error
(
`can only generate proofs for L2 to L1 messages`
)
}
}
const
stateRoot
=
await
this
.
getMessageStateRoot
(
resolved
)
const
stateRoot
=
await
this
.
getMessageStateRoot
(
resolved
,
messageIndex
)
if
(
stateRoot
===
null
)
{
if
(
stateRoot
===
null
)
{
throw
new
Error
(
`state root for message not yet published`
)
throw
new
Error
(
`state root for message not yet published`
)
}
}
...
@@ -1376,19 +1446,24 @@ export class CrossChainMessenger {
...
@@ -1376,19 +1446,24 @@ export class CrossChainMessenger {
* @returns Proof that can be used to finalize the message.
* @returns Proof that can be used to finalize the message.
*/
*/
public
async
getBedrockMessageProof
(
public
async
getBedrockMessageProof
(
message
:
MessageLike
message
:
MessageLike
,
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
BedrockCrossChainMessageProof
>
{
):
Promise
<
BedrockCrossChainMessageProof
>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
throw
new
Error
(
`can only generate proofs for L2 to L1 messages`
)
throw
new
Error
(
`can only generate proofs for L2 to L1 messages`
)
}
}
const
output
=
await
this
.
getMessageBedrockOutput
(
resolved
)
const
output
=
await
this
.
getMessageBedrockOutput
(
resolved
,
messageIndex
)
if
(
output
===
null
)
{
if
(
output
===
null
)
{
throw
new
Error
(
`state root for message not yet published`
)
throw
new
Error
(
`state root for message not yet published`
)
}
}
const
withdrawal
=
await
this
.
toLowLevelMessage
(
resolved
)
const
withdrawal
=
await
this
.
toLowLevelMessage
(
resolved
,
messageIndex
)
const
hash
=
hashLowLevelMessage
(
withdrawal
)
const
hash
=
hashLowLevelMessage
(
withdrawal
)
const
messageSlot
=
hashMessageHash
(
hash
)
const
messageSlot
=
hashMessageHash
(
hash
)
...
@@ -1734,9 +1809,14 @@ export class CrossChainMessenger {
...
@@ -1734,9 +1809,14 @@ export class CrossChainMessenger {
messageGasLimit
:
NumberLike
,
messageGasLimit
:
NumberLike
,
opts
?:
{
opts
?:
{
overrides
?:
Overrides
overrides
?:
Overrides
}
},
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
TransactionRequest
>
=>
{
):
Promise
<
TransactionRequest
>
=>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
if
(
resolved
.
direction
===
MessageDirection
.
L2_TO_L1
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L2_TO_L1
)
{
throw
new
Error
(
`cannot resend L2 to L1 message`
)
throw
new
Error
(
`cannot resend L2 to L1 message`
)
}
}
...
@@ -1780,9 +1860,14 @@ export class CrossChainMessenger {
...
@@ -1780,9 +1860,14 @@ export class CrossChainMessenger {
message
:
MessageLike
,
message
:
MessageLike
,
opts
?:
{
opts
?:
{
overrides
?:
PayableOverrides
overrides
?:
PayableOverrides
}
},
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
TransactionRequest
>
=>
{
):
Promise
<
TransactionRequest
>
=>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
throw
new
Error
(
'
cannot finalize L1 to L2 message
'
)
throw
new
Error
(
'
cannot finalize L1 to L2 message
'
)
}
}
...
@@ -1793,8 +1878,8 @@ export class CrossChainMessenger {
...
@@ -1793,8 +1878,8 @@ export class CrossChainMessenger {
)
)
}
}
const
withdrawal
=
await
this
.
toLowLevelMessage
(
resolved
)
const
withdrawal
=
await
this
.
toLowLevelMessage
(
resolved
,
messageIndex
)
const
proof
=
await
this
.
getBedrockMessageProof
(
resolved
)
const
proof
=
await
this
.
getBedrockMessageProof
(
resolved
,
messageIndex
)
const
args
=
[
const
args
=
[
[
[
...
@@ -1835,15 +1920,20 @@ export class CrossChainMessenger {
...
@@ -1835,15 +1920,20 @@ export class CrossChainMessenger {
message
:
MessageLike
,
message
:
MessageLike
,
opts
?:
{
opts
?:
{
overrides
?:
PayableOverrides
overrides
?:
PayableOverrides
}
},
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
TransactionRequest
>
=>
{
):
Promise
<
TransactionRequest
>
=>
{
const
resolved
=
await
this
.
toCrossChainMessage
(
message
)
const
resolved
=
await
this
.
toCrossChainMessage
(
message
,
messageIndex
)
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
if
(
resolved
.
direction
===
MessageDirection
.
L1_TO_L2
)
{
throw
new
Error
(
`cannot finalize L1 to L2 message`
)
throw
new
Error
(
`cannot finalize L1 to L2 message`
)
}
}
if
(
this
.
bedrock
)
{
if
(
this
.
bedrock
)
{
const
withdrawal
=
await
this
.
toLowLevelMessage
(
resolved
)
const
withdrawal
=
await
this
.
toLowLevelMessage
(
resolved
,
messageIndex
)
return
this
.
contracts
.
l1
.
OptimismPortal
.
populateTransaction
.
finalizeWithdrawalTransaction
(
return
this
.
contracts
.
l1
.
OptimismPortal
.
populateTransaction
.
finalizeWithdrawalTransaction
(
[
[
withdrawal
.
messageNonce
,
withdrawal
.
messageNonce
,
...
@@ -1859,7 +1949,7 @@ export class CrossChainMessenger {
...
@@ -1859,7 +1949,7 @@ export class CrossChainMessenger {
// L1CrossDomainMessenger relayMessage is the only method that isn't fully backwards
// L1CrossDomainMessenger relayMessage is the only method that isn't fully backwards
// compatible, so we need to use the legacy interface. When we fully upgrade to Bedrock we
// compatible, so we need to use the legacy interface. When we fully upgrade to Bedrock we
// should be able to remove this code.
// should be able to remove this code.
const
proof
=
await
this
.
getMessageProof
(
resolved
)
const
proof
=
await
this
.
getMessageProof
(
resolved
,
messageIndex
)
const
legacyL1XDM
=
new
ethers
.
Contract
(
const
legacyL1XDM
=
new
ethers
.
Contract
(
this
.
contracts
.
l1
.
L1CrossDomainMessenger
.
address
,
this
.
contracts
.
l1
.
L1CrossDomainMessenger
.
address
,
getContractInterface
(
'
L1CrossDomainMessenger
'
),
getContractInterface
(
'
L1CrossDomainMessenger
'
),
...
@@ -2116,10 +2206,14 @@ export class CrossChainMessenger {
...
@@ -2116,10 +2206,14 @@ export class CrossChainMessenger {
message
:
MessageLike
,
message
:
MessageLike
,
opts
?:
{
opts
?:
{
overrides
?:
CallOverrides
overrides
?:
CallOverrides
}
},
/**
* The index of the withdrawal if multiple are made with multicall
*/
messageIndex
=
0
):
Promise
<
BigNumber
>
=>
{
):
Promise
<
BigNumber
>
=>
{
return
this
.
l1Provider
.
estimateGas
(
return
this
.
l1Provider
.
estimateGas
(
await
this
.
populateTransaction
.
proveMessage
(
message
,
opts
)
await
this
.
populateTransaction
.
proveMessage
(
message
,
opts
,
messageIndex
)
)
)
},
},
...
...
packages/sdk/test/cross-chain-messenger.spec.ts
View file @
e4ca19e1
...
@@ -565,23 +565,25 @@ describe('CrossChainMessenger', () => {
...
@@ -565,23 +565,25 @@ describe('CrossChainMessenger', () => {
})
})
describe
(
'
when the transaction sent more than one message
'
,
()
=>
{
describe
(
'
when the transaction sent more than one message
'
,
()
=>
{
it
(
'
should
throw an error
'
,
async
()
=>
{
it
(
'
should
be able to get second message by passing in an idex
'
,
async
()
=>
{
const
messages
=
[...
Array
(
2
)].
map
(()
=>
{
const
messages
=
[...
Array
(
2
)].
map
(()
=>
{
return
DUMMY_MESSAGE
return
DUMMY_MESSAGE
})
})
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
await
expect
(
messenger
.
toCrossChainMessage
(
tx
)).
to
.
be
.
rejectedWith
(
const
foundCrossChainMessages
=
'
expected 1 message, got 2
'
await
messenger
.
getMessagesByTransaction
(
tx
)
expect
(
await
messenger
.
toCrossChainMessage
(
tx
,
1
)).
to
.
deep
.
eq
(
foundCrossChainMessages
[
1
]
)
)
})
})
})
})
describe
(
'
when the transaction sent no messages
'
,
()
=>
{
describe
(
'
when the transaction sent no messages
'
,
()
=>
{
it
(
'
should throw an error
'
,
async
()
=>
{
it
(
'
should throw an
out of bounds
error
'
,
async
()
=>
{
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
([])
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
([])
await
expect
(
messenger
.
toCrossChainMessage
(
tx
)).
to
.
be
.
rejectedWith
(
await
expect
(
messenger
.
toCrossChainMessage
(
tx
)).
to
.
be
.
rejectedWith
(
'
expected 1 message, got 0
'
`withdrawal index 0 out of bounds. There are 0 withdrawals`
)
)
})
})
})
})
...
...
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