github.com/ethereum-optimism/optimism@v1.7.2/packages/sdk/src/utils/message-utils.ts (about) 1 import { hashWithdrawal } from '@eth-optimism/core-utils' 2 import { BigNumber, utils, ethers } from 'ethers' 3 4 import { LowLevelMessage } from '../interfaces' 5 6 const { hexDataLength } = utils 7 8 // Constants used by `CrossDomainMessenger.baseGas` 9 const RELAY_CONSTANT_OVERHEAD = BigNumber.from(200_000) 10 const RELAY_PER_BYTE_DATA_COST = BigNumber.from(16) 11 const MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR = BigNumber.from(64) 12 const MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR = BigNumber.from(63) 13 const RELAY_CALL_OVERHEAD = BigNumber.from(40_000) 14 const RELAY_RESERVED_GAS = BigNumber.from(40_000) 15 const RELAY_GAS_CHECK_BUFFER = BigNumber.from(5_000) 16 17 /** 18 * Utility for hashing a LowLevelMessage object. 19 * 20 * @param message LowLevelMessage object to hash. 21 * @returns Hash of the given LowLevelMessage. 22 */ 23 export const hashLowLevelMessage = (message: LowLevelMessage): string => { 24 return hashWithdrawal( 25 message.messageNonce, 26 message.sender, 27 message.target, 28 message.value, 29 message.minGasLimit, 30 message.message 31 ) 32 } 33 34 /** 35 * Utility for hashing a message hash. This computes the storage slot 36 * where the message hash will be stored in state. HashZero is used 37 * because the first mapping in the contract is used. 38 * 39 * @param messageHash Message hash to hash. 40 * @returns Hash of the given message hash. 41 */ 42 export const hashMessageHash = (messageHash: string): string => { 43 const data = ethers.utils.defaultAbiCoder.encode( 44 ['bytes32', 'uint256'], 45 [messageHash, ethers.constants.HashZero] 46 ) 47 return ethers.utils.keccak256(data) 48 } 49 50 /** 51 * Compute the min gas limit for a migrated withdrawal. 52 */ 53 export const migratedWithdrawalGasLimit = ( 54 data: string, 55 chainID: number 56 ): BigNumber => { 57 // Compute the gas limit and cap at 25 million 58 const dataCost = BigNumber.from(hexDataLength(data)).mul( 59 RELAY_PER_BYTE_DATA_COST 60 ) 61 let overhead: BigNumber 62 if (chainID === 420) { 63 overhead = BigNumber.from(200_000) 64 } else { 65 // Dynamic overhead (EIP-150) 66 // We use a constant 1 million gas limit due to the overhead of simulating all migrated withdrawal 67 // transactions during the migration. This is a conservative estimate, and if a withdrawal 68 // uses more than the minimum gas limit, it will fail and need to be replayed with a higher 69 // gas limit. 70 const dynamicOverhead = MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR.mul( 71 1_000_000 72 ).div(MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR) 73 74 // Constant overhead 75 overhead = RELAY_CONSTANT_OVERHEAD.add(dynamicOverhead) 76 .add(RELAY_CALL_OVERHEAD) 77 // Gas reserved for the worst-case cost of 3/5 of the `CALL` opcode's dynamic gas 78 // factors. (Conservative) 79 // Relay reserved gas (to ensure execution of `relayMessage` completes after the 80 // subcontext finishes executing) (Conservative) 81 .add(RELAY_RESERVED_GAS) 82 // Gas reserved for the execution between the `hasMinGas` check and the `CALL` 83 // opcode. (Conservative) 84 .add(RELAY_GAS_CHECK_BUFFER) 85 } 86 87 let minGasLimit = dataCost.add(overhead) 88 if (minGasLimit.gt(25_000_000)) { 89 minGasLimit = BigNumber.from(25_000_000) 90 } 91 return minGasLimit 92 }