github.com/ethereum-optimism/optimism@v1.7.2/packages/core-utils/src/optimism/encoding.ts (about)

     1  import { BigNumberish, BigNumber } from '@ethersproject/bignumber'
     2  import { Interface } from '@ethersproject/abi'
     3  
     4  const iface = new Interface([
     5    'function relayMessage(address,address,bytes,uint256)',
     6    'function relayMessage(uint256,address,address,uint256,uint256,bytes)',
     7  ])
     8  
     9  const nonceMask = BigNumber.from(
    10    '0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    11  )
    12  
    13  /**
    14   * Encodes the version into the nonce.
    15   *
    16   * @param nonce
    17   * @param version
    18   */
    19  export const encodeVersionedNonce = (
    20    nonce: BigNumber,
    21    version: BigNumber
    22  ): BigNumber => {
    23    return version.or(nonce.shl(240))
    24  }
    25  
    26  /**
    27   * Decodes the version from the nonce and returns the unversioned nonce as well
    28   * as the version. The version is encoded in the first byte of
    29   * the nonce. Note that this nonce is the nonce held in the
    30   * CrossDomainMessenger.
    31   *
    32   * @param nonce
    33   */
    34  export const decodeVersionedNonce = (
    35    nonce: BigNumber
    36  ): {
    37    version: BigNumber
    38    nonce: BigNumber
    39  } => {
    40    return {
    41      version: nonce.shr(240),
    42      nonce: nonce.and(nonceMask),
    43    }
    44  }
    45  
    46  /**
    47   * Encodes a V1 cross domain message. This message format was used before
    48   * bedrock and does not support value transfer because ETH was represented as an
    49   * ERC20 natively.
    50   *
    51   * @param target    The target of the cross domain message
    52   * @param sender    The sender of the cross domain message
    53   * @param data      The data passed along with the cross domain message
    54   * @param nonce     The cross domain message nonce
    55   */
    56  export const encodeCrossDomainMessageV0 = (
    57    target: string,
    58    sender: string,
    59    data: string,
    60    nonce: BigNumber
    61  ) => {
    62    return iface.encodeFunctionData(
    63      'relayMessage(address,address,bytes,uint256)',
    64      [target, sender, data, nonce]
    65    )
    66  }
    67  
    68  /**
    69   * Encodes a V1 cross domain message. This message format shipped with bedrock
    70   * and supports value transfer with native ETH.
    71   *
    72   * @param nonce     The cross domain message nonce
    73   * @param sender    The sender of the cross domain message
    74   * @param target    The target of the cross domain message
    75   * @param value     The value being sent with the cross domain message
    76   * @param gasLimit  The gas limit of the cross domain execution
    77   * @param data      The data passed along with the cross domain message
    78   */
    79  export const encodeCrossDomainMessageV1 = (
    80    nonce: BigNumber,
    81    sender: string,
    82    target: string,
    83    value: BigNumberish,
    84    gasLimit: BigNumberish,
    85    data: string
    86  ) => {
    87    return iface.encodeFunctionData(
    88      'relayMessage(uint256,address,address,uint256,uint256,bytes)',
    89      [nonce, sender, target, value, gasLimit, data]
    90    )
    91  }
    92  
    93  /**
    94   * Encodes a cross domain message. The version byte in the nonce determines
    95   * the serialization format that is used.
    96   *
    97   * @param nonce     The cross domain message nonce
    98   * @param sender    The sender of the cross domain message
    99   * @param target    The target of the cross domain message
   100   * @param value     The value being sent with the cross domain message
   101   * @param gasLimit  The gas limit of the cross domain execution
   102   * @param data      The data passed along with the cross domain message
   103   */
   104  export const encodeCrossDomainMessage = (
   105    nonce: BigNumber,
   106    sender: string,
   107    target: string,
   108    value: BigNumber,
   109    gasLimit: BigNumber,
   110    data: string
   111  ) => {
   112    const { version } = decodeVersionedNonce(nonce)
   113    if (version.eq(0)) {
   114      return encodeCrossDomainMessageV0(target, sender, data, nonce)
   115    } else if (version.eq(1)) {
   116      return encodeCrossDomainMessageV1(
   117        nonce,
   118        sender,
   119        target,
   120        value,
   121        gasLimit,
   122        data
   123      )
   124    }
   125    throw new Error(`unknown version ${version.toString()}`)
   126  }