Commit 6c87ec92 authored by Will Cory's avatar Will Cory Committed by Mark Tyneway

sdk: bugfixes

parent a00e9eb4
This diff is collapsed.
...@@ -68,6 +68,7 @@ import { ...@@ -68,6 +68,7 @@ import {
migratedWithdrawalGasLimit, migratedWithdrawalGasLimit,
DEPOSIT_CONFIRMATION_BLOCKS, DEPOSIT_CONFIRMATION_BLOCKS,
CHAIN_BLOCK_TIMES, CHAIN_BLOCK_TIMES,
hashMessageHash,
} from './utils' } from './utils'
export class CrossChainMessenger { export class CrossChainMessenger {
...@@ -351,14 +352,12 @@ export class CrossChainMessenger { ...@@ -351,14 +352,12 @@ export class CrossChainMessenger {
} }
} }
const minGasLimit = migratedWithdrawalGasLimit(resolved.message)
return { return {
...resolved, ...resolved,
value, value,
minGasLimit, minGasLimit: BigNumber.from(0),
messageNonce: encodeVersionedNonce( messageNonce: encodeVersionedNonce(
BigNumber.from(1), BigNumber.from(0),
resolved.messageNonce resolved.messageNonce
), ),
} }
...@@ -388,13 +387,23 @@ export class CrossChainMessenger { ...@@ -388,13 +387,23 @@ export class CrossChainMessenger {
updated = resolved updated = resolved
} }
// Encode the updated message, we need this for legacy messages.
const encoded = encodeCrossDomainMessageV1(
updated.messageNonce,
updated.sender,
updated.target,
updated.value,
updated.minGasLimit,
updated.message
)
// 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.
let gasLimit: BigNumber let gasLimit: BigNumber
let messageNonce: BigNumber let messageNonce: BigNumber
if (version.eq(0)) { if (version.eq(0)) {
gasLimit = BigNumber.from(0) gasLimit = migratedWithdrawalGasLimit(encoded)
messageNonce = resolved.messageNonce messageNonce = resolved.messageNonce
} else { } else {
const receipt = await this.l2Provider.getTransactionReceipt( const receipt = await this.l2Provider.getTransactionReceipt(
...@@ -433,14 +442,7 @@ export class CrossChainMessenger { ...@@ -433,14 +442,7 @@ export class CrossChainMessenger {
target: this.contracts.l1.L1CrossDomainMessenger.address, target: this.contracts.l1.L1CrossDomainMessenger.address,
value: updated.value, value: updated.value,
minGasLimit: gasLimit, minGasLimit: gasLimit,
message: encodeCrossDomainMessageV1( message: encoded,
updated.messageNonce,
updated.sender,
updated.target,
updated.value,
updated.minGasLimit,
updated.message
),
} }
} }
...@@ -1360,12 +1362,8 @@ export class CrossChainMessenger { ...@@ -1360,12 +1362,8 @@ export class CrossChainMessenger {
} }
const withdrawal = await this.toLowLevelMessage(resolved) const withdrawal = await this.toLowLevelMessage(resolved)
const messageSlot = ethers.utils.keccak256( const hash = hashLowLevelMessage(withdrawal)
ethers.utils.defaultAbiCoder.encode( const messageSlot = hashMessageHash(hash)
['bytes32', 'uint256'],
[hashLowLevelMessage(withdrawal), ethers.constants.HashZero]
)
)
const stateTrieProof = await makeStateTrieProof( const stateTrieProof = await makeStateTrieProof(
this.l2Provider as ethers.providers.JsonRpcProvider, this.l2Provider as ethers.providers.JsonRpcProvider,
...@@ -1465,9 +1463,8 @@ export class CrossChainMessenger { ...@@ -1465,9 +1463,8 @@ export class CrossChainMessenger {
overrides?: Overrides overrides?: Overrides
} }
): Promise<TransactionResponse> { ): Promise<TransactionResponse> {
return (opts?.signer || this.l1Signer).sendTransaction( const tx = await this.populateTransaction.proveMessage(message, opts)
await this.populateTransaction.proveMessage(message, opts) return (opts?.signer || this.l1Signer).sendTransaction(tx)
)
} }
/** /**
...@@ -1771,7 +1768,8 @@ export class CrossChainMessenger { ...@@ -1771,7 +1768,8 @@ export class CrossChainMessenger {
const withdrawal = await this.toLowLevelMessage(resolved) const withdrawal = await this.toLowLevelMessage(resolved)
const proof = await this.getBedrockMessageProof(resolved) const proof = await this.getBedrockMessageProof(resolved)
return this.contracts.l1.OptimismPortal.populateTransaction.proveWithdrawalTransaction(
const args = [
[ [
withdrawal.messageNonce, withdrawal.messageNonce,
withdrawal.sender, withdrawal.sender,
...@@ -1788,7 +1786,11 @@ export class CrossChainMessenger { ...@@ -1788,7 +1786,11 @@ export class CrossChainMessenger {
proof.outputRootProof.latestBlockhash, proof.outputRootProof.latestBlockhash,
], ],
proof.withdrawalProof, proof.withdrawalProof,
opts?.overrides || {} opts?.overrides || {},
] as const
return this.contracts.l1.OptimismPortal.populateTransaction.proveWithdrawalTransaction(
...args
) )
}, },
......
This diff is collapsed.
import { hashWithdrawal } from '@eth-optimism/core-utils' import { hashWithdrawal } from '@eth-optimism/core-utils'
import { BigNumber, utils } from 'ethers' import { BigNumber, utils, ethers } from 'ethers'
import { LowLevelMessage } from '../interfaces' import { LowLevelMessage } from '../interfaces'
...@@ -22,6 +22,22 @@ export const hashLowLevelMessage = (message: LowLevelMessage): string => { ...@@ -22,6 +22,22 @@ export const hashLowLevelMessage = (message: LowLevelMessage): string => {
) )
} }
/**
* Utility for hashing a message hash. This computes the storage slot
* where the message hash will be stored in state. HashZero is used
* because the first mapping in the contract is used.
*
* @param messageHash Message hash to hash.
* @returns Hash of the given message hash.
*/
export const hashMessageHash = (messageHash: string): string => {
const data = ethers.utils.defaultAbiCoder.encode(
['bytes32', 'uint256'],
[messageHash, ethers.constants.HashZero]
)
return ethers.utils.keccak256(data)
}
/** /**
* Compute the min gas limit for a migrated withdrawal. * Compute the min gas limit for a migrated withdrawal.
*/ */
......
...@@ -99,8 +99,10 @@ describe('prove message', () => { ...@@ -99,8 +99,10 @@ describe('prove message', () => {
expect(txReceipt).toBeDefined() expect(txReceipt).toBeDefined()
expect( const tx = await crossChainMessenger.proveMessage(txWithdrawalHash)
await crossChainMessenger.proveMessage(txWithdrawalHash) const receipt = await tx.wait()
).toMatchInlineSnapshot()
// A 1 means the transaction was successful
expect(receipt.status).toBe(1)
}, 20_000) }, 20_000)
}) })
import { BigNumber } from 'ethers' import { BigNumber } from 'ethers'
import { expect } from '../setup' import { expect } from '../setup'
import { migratedWithdrawalGasLimit } from '../../src/utils/message-utils' import {
migratedWithdrawalGasLimit,
hashLowLevelMessage,
hashMessageHash,
} from '../../src/utils/message-utils'
describe('Message Utils', () => { describe('Message Utils', () => {
describe('migratedWithdrawalGasLimit', () => { describe('migratedWithdrawalGasLimit', () => {
...@@ -26,4 +30,47 @@ describe('Message Utils', () => { ...@@ -26,4 +30,47 @@ describe('Message Utils', () => {
} }
}) })
}) })
/**
* Test that storage slot computation is correct. The test vectors are
* from actual migrated withdrawals on goerli.
*/
describe('Withdrawal Hashing', () => {
it('should work', () => {
const tests = [
{
input: {
messageNonce: BigNumber.from(100000),
sender: '0x4200000000000000000000000000000000000007',
target: '0x5086d1eEF304eb5284A0f6720f79403b4e9bE294',
value: BigNumber.from(0),
minGasLimit: BigNumber.from(207744),
message:
'0xd764ad0b00000000000000000000000000000000000000000000000000000000000186a00000000000000000000000004200000000000000000000000000000000000010000000000000000000000000636af16bf2f682dd3109e60102b8e1a089fedaa80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e4a9f9e67500000000000000000000000007865c6e87b9f70255377e024ace6630c1eaa37f0000000000000000000000003b8e53b3ab8e01fb57d0c9e893bc4d655aa67d84000000000000000000000000b91882244f7f82540f2941a759724523c7b9a166000000000000000000000000b91882244f7f82540f2941a759724523c7b9a166000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
},
result:
'0x7c83d39edf60c0ab61bc7cfd2e5f741efdf02fd6e2da0f12318f0d1858d3773b',
},
{
input: {
messageNonce: BigNumber.from(100001),
sender: '0x4200000000000000000000000000000000000007',
target: '0x5086d1eEF304eb5284A0f6720f79403b4e9bE294',
value: BigNumber.from(0),
minGasLimit: BigNumber.from(207744),
message:
'0xd764ad0b00000000000000000000000000000000000000000000000000000000000186a10000000000000000000000004200000000000000000000000000000000000010000000000000000000000000636af16bf2f682dd3109e60102b8e1a089fedaa80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e4a9f9e67500000000000000000000000007865c6e87b9f70255377e024ace6630c1eaa37f0000000000000000000000004e62882864fb8ce54affcaf8d899a286762b011b000000000000000000000000b91882244f7f82540f2941a759724523c7b9a166000000000000000000000000b91882244f7f82540f2941a759724523c7b9a166000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
},
result:
'0x17c90d87508a23d806962f4c5f366ef505e8d80e5cc2a5c87242560c21d7c588',
},
]
for (const test of tests) {
const hash = hashLowLevelMessage(test.input)
const messageSlot = hashMessageHash(hash)
expect(messageSlot).to.eq(test.result)
}
})
})
}) })
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment