Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(sdk): check for both v0 and v1 messages when looking for RelayedMessages #6042

Merged
merged 2 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fuzzy-lobsters-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/sdk': minor
---

Fixes issue with legacy withdrawal message status detection
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -626,12 +626,12 @@ jobs:
name: anvil-l1
background: true
# atm this is goerli but we should use mainnet after bedrock is live
command: anvil --fork-url $ANVIL_L1_FORK_URL --fork-block-number 9023108
command: anvil --fork-url $ANVIL_L1_FORK_URL --fork-block-number 9190101
- run:
name: anvil-l2
background: true
# atm this is goerli but we should use mainnet after bedrock is live
command: anvil --fork-url $ANVIL_L2_FORK_URL --port 9545 --fork-block-number 9504811
command: anvil --fork-url $ANVIL_L2_FORK_URL --port 9545 --fork-block-number 10756611
- run:
name: build
command: pnpm build
Expand Down
24 changes: 12 additions & 12 deletions packages/core-utils/src/optimism/hashing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@ export const hashCrossDomainMessage = (
target: string,
value: BigNumber,
gasLimit: BigNumber,
data: string
message: string
) => {
const { version } = decodeVersionedNonce(nonce)
if (version.eq(0)) {
return hashCrossDomainMessagev0(target, sender, data, nonce)
return hashCrossDomainMessagev0(target, sender, message, nonce)
} else if (version.eq(1)) {
return hashCrossDomainMessagev1(
nonce,
sender,
target,
value,
gasLimit,
data
message
)
}
throw new Error(`unknown version ${version.toString()}`)
Expand All @@ -85,16 +85,16 @@ export const hashCrossDomainMessage = (
*
* @param target The target of the cross domain message
* @param sender The sender of the cross domain message
* @param data The data passed along with the cross domain message
* @param message The message passed along with the cross domain message
* @param nonce The cross domain message nonce
*/
export const hashCrossDomainMessagev0 = (
target: string,
sender: string,
data: string,
message: string,
nonce: BigNumber
) => {
return keccak256(encodeCrossDomainMessageV0(target, sender, data, nonce))
return keccak256(encodeCrossDomainMessageV0(target, sender, message, nonce))
}

/**
Expand All @@ -105,18 +105,18 @@ export const hashCrossDomainMessagev0 = (
* @param target The target of the cross domain message
* @param value The value being sent with the cross domain message
* @param gasLimit The gas limit of the cross domain execution
* @param data The data passed along with the cross domain message
* @param message The message passed along with the cross domain message
*/
export const hashCrossDomainMessagev1 = (
nonce: BigNumber,
sender: string,
target: string,
value: BigNumberish,
gasLimit: BigNumberish,
data: string
message: string
) => {
return keccak256(
encodeCrossDomainMessageV1(nonce, sender, target, value, gasLimit, data)
encodeCrossDomainMessageV1(nonce, sender, target, value, gasLimit, message)
)
}

Expand All @@ -128,15 +128,15 @@ export const hashCrossDomainMessagev1 = (
* @param target The target of the cross domain message
* @param value The value being sent with the cross domain message
* @param gasLimit The gas limit of the cross domain execution
* @param data The data passed along with the cross domain message
* @param message The message passed along with the cross domain message
*/
export const hashWithdrawal = (
nonce: BigNumber,
sender: string,
target: string,
value: BigNumber,
gasLimit: BigNumber,
data: string
message: string
): string => {
const types = ['uint256', 'address', 'address', 'uint256', 'uint256', 'bytes']
const encoded = defaultAbiCoder.encode(types, [
Expand All @@ -145,7 +145,7 @@ export const hashWithdrawal = (
target,
value,
gasLimit,
data,
message,
])
return keccak256(encoded)
}
Expand Down
38 changes: 31 additions & 7 deletions packages/sdk/src/cross-chain-messenger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
decodeVersionedNonce,
encodeVersionedNonce,
getChainId,
hashCrossDomainMessagev0,
hashCrossDomainMessagev1,
} from '@eth-optimism/core-utils'
import { getContractInterface, predeploys } from '@eth-optimism/contracts'
import * as rlp from 'rlp'
Expand Down Expand Up @@ -716,7 +718,18 @@ export class CrossChainMessenger {
message: MessageLike
): Promise<MessageReceipt> {
const resolved = await this.toCrossChainMessage(message)
const messageHash = hashCrossDomainMessage(
// legacy withdrawals relayed prebedrock are v1
const messageHashV0 = hashCrossDomainMessagev0(
resolved.target,
resolved.sender,
resolved.message,
resolved.messageNonce
)
// bedrock withdrawals are v1
// legacy withdrawals relayed postbedrock are v1
// there is no good way to differentiate between the two types of legacy
// so what we will check for both
const messageHashV1 = hashCrossDomainMessagev1(
resolved.messageNonce,
resolved.sender,
resolved.target,
Expand All @@ -731,9 +744,15 @@ export class CrossChainMessenger {
? this.contracts.l2.L2CrossDomainMessenger
: this.contracts.l1.L1CrossDomainMessenger

const relayedMessageEvents = await messenger.queryFilter(
messenger.filters.RelayedMessage(messageHash)
)
// this is safe because we can guarantee only one of these filters max will return something
const relayedMessageEvents = [
...(await messenger.queryFilter(
messenger.filters.RelayedMessage(messageHashV0)
)),
...(await messenger.queryFilter(
messenger.filters.RelayedMessage(messageHashV1)
)),
]

// Great, we found the message. Convert it into a transaction receipt.
if (relayedMessageEvents.length === 1) {
Expand All @@ -749,9 +768,14 @@ export class CrossChainMessenger {

// We didn't find a transaction that relayed the message. We now attempt to find
// FailedRelayedMessage events instead.
const failedRelayedMessageEvents = await messenger.queryFilter(
messenger.filters.FailedRelayedMessage(messageHash)
)
const failedRelayedMessageEvents = [
...(await messenger.queryFilter(
messenger.filters.FailedRelayedMessage(messageHashV0)
)),
...(await messenger.queryFilter(
messenger.filters.FailedRelayedMessage(messageHashV1)
)),
]

// A transaction can fail to be relayed multiple times. We'll always return the last
// transaction that attempted to relay the message.
Expand Down
32 changes: 32 additions & 0 deletions packages/sdk/test-next/messageStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { describe, expect, it } from 'vitest'

import { CrossChainMessenger, MessageStatus } from '../src'
import { l1Provider, l2Provider } from './testUtils/ethersProviders'

const crossChainMessenger = new CrossChainMessenger({
l1SignerOrProvider: l1Provider,
l2SignerOrProvider: l2Provider,
l1ChainId: 5,
l2ChainId: 420,
bedrock: true,
})

describe('prove message', () => {
it(`should be able to correctly find a finalized withdrawal`, async () => {
roninjin10 marked this conversation as resolved.
Show resolved Hide resolved
/**
* Tx hash of legacy withdrawal that was claimed
*
* @see https://goerli-optimism.etherscan.io/tx/0xda9e9c8dfc7718bc1499e1e64d8df6cddbabc46e819475a6c755db286a41b9fa
*/
const txWithdrawalHash =
'0xda9e9c8dfc7718bc1499e1e64d8df6cddbabc46e819475a6c755db286a41b9fa'

const txReceipt = await l2Provider.getTransactionReceipt(txWithdrawalHash)

expect(txReceipt).toBeDefined()

expect(await crossChainMessenger.getMessageStatus(txWithdrawalHash)).toBe(
MessageStatus.RELAYED
)
}, 20_000)
roninjin10 marked this conversation as resolved.
Show resolved Hide resolved
})