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 {
migratedWithdrawalGasLimit,
DEPOSIT_CONFIRMATION_BLOCKS,
CHAIN_BLOCK_TIMES,
hashMessageHash,
} from './utils'
export class CrossChainMessenger {
......@@ -351,14 +352,12 @@ export class CrossChainMessenger {
}
}
const minGasLimit = migratedWithdrawalGasLimit(resolved.message)
return {
...resolved,
value,
minGasLimit,
minGasLimit: BigNumber.from(0),
messageNonce: encodeVersionedNonce(
BigNumber.from(1),
BigNumber.from(0),
resolved.messageNonce
),
}
......@@ -388,13 +387,23 @@ export class CrossChainMessenger {
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
// inside the L2ToL1Message passer contract. Exact mechanism here depends on whether or not
// this is a legacy message or a new Bedrock message.
let gasLimit: BigNumber
let messageNonce: BigNumber
if (version.eq(0)) {
gasLimit = BigNumber.from(0)
gasLimit = migratedWithdrawalGasLimit(encoded)
messageNonce = resolved.messageNonce
} else {
const receipt = await this.l2Provider.getTransactionReceipt(
......@@ -433,14 +442,7 @@ export class CrossChainMessenger {
target: this.contracts.l1.L1CrossDomainMessenger.address,
value: updated.value,
minGasLimit: gasLimit,
message: encodeCrossDomainMessageV1(
updated.messageNonce,
updated.sender,
updated.target,
updated.value,
updated.minGasLimit,
updated.message
),
message: encoded,
}
}
......@@ -1360,12 +1362,8 @@ export class CrossChainMessenger {
}
const withdrawal = await this.toLowLevelMessage(resolved)
const messageSlot = ethers.utils.keccak256(
ethers.utils.defaultAbiCoder.encode(
['bytes32', 'uint256'],
[hashLowLevelMessage(withdrawal), ethers.constants.HashZero]
)
)
const hash = hashLowLevelMessage(withdrawal)
const messageSlot = hashMessageHash(hash)
const stateTrieProof = await makeStateTrieProof(
this.l2Provider as ethers.providers.JsonRpcProvider,
......@@ -1465,9 +1463,8 @@ export class CrossChainMessenger {
overrides?: Overrides
}
): Promise<TransactionResponse> {
return (opts?.signer || this.l1Signer).sendTransaction(
await this.populateTransaction.proveMessage(message, opts)
)
const tx = await this.populateTransaction.proveMessage(message, opts)
return (opts?.signer || this.l1Signer).sendTransaction(tx)
}
/**
......@@ -1771,7 +1768,8 @@ export class CrossChainMessenger {
const withdrawal = await this.toLowLevelMessage(resolved)
const proof = await this.getBedrockMessageProof(resolved)
return this.contracts.l1.OptimismPortal.populateTransaction.proveWithdrawalTransaction(
const args = [
[
withdrawal.messageNonce,
withdrawal.sender,
......@@ -1788,7 +1786,11 @@ export class CrossChainMessenger {
proof.outputRootProof.latestBlockhash,
],
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 { BigNumber, utils } from 'ethers'
import { BigNumber, utils, ethers } from 'ethers'
import { LowLevelMessage } from '../interfaces'
......@@ -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.
*/
......
......@@ -99,8 +99,10 @@ describe('prove message', () => {
expect(txReceipt).toBeDefined()
expect(
await crossChainMessenger.proveMessage(txWithdrawalHash)
).toMatchInlineSnapshot()
const tx = await crossChainMessenger.proveMessage(txWithdrawalHash)
const receipt = await tx.wait()
// A 1 means the transaction was successful
expect(receipt.status).toBe(1)
}, 20_000)
})
import { BigNumber } from 'ethers'
import { expect } from '../setup'
import { migratedWithdrawalGasLimit } from '../../src/utils/message-utils'
import {
migratedWithdrawalGasLimit,
hashLowLevelMessage,
hashMessageHash,
} from '../../src/utils/message-utils'
describe('Message Utils', () => {
describe('migratedWithdrawalGasLimit', () => {
......@@ -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