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  }