hashing.ts 4.21 KB
Newer Older
1 2 3
import { BigNumberish, BigNumber } from '@ethersproject/bignumber'
import { keccak256 } from '@ethersproject/keccak256'
import { defaultAbiCoder } from '@ethersproject/abi'
4 5 6 7 8 9 10 11 12

import {
  decodeVersionedNonce,
  encodeCrossDomainMessageV0,
  encodeCrossDomainMessageV1,
  big0,
  big1,
} from './encoding'

13 14 15 16 17 18 19 20 21 22 23 24
/**
 * Bedrock output oracle data.
 */
export interface BedrockOutputData {
  outputRoot: string
  l1Timestamp: number
  l2BlockNumber: number
}

/**
 * Bedrock state commitment
 */
25 26 27 28 29 30 31
export interface OutputRootProof {
  version: string
  stateRoot: string
  withdrawerStorageRoot: string
  latestBlockhash: string
}

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/**
 * Bedrock proof data required to finalize an L2 to L1 message.
 */
export interface BedrockCrossChainMessageProof {
  outputRootProof: OutputRootProof
  withdrawalProof: string
}

/**
 * Parameters that govern the L2OutputOracle.
 */
export type L2OutputOracleParameters = {
  submissionInterval: number
  startingBlockNumber: number
  l2BlockTime: number
}

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
/**
 * Hahses a cross domain message.
 *
 * @param nonce     The cross domain message nonce
 * @param sender    The sender of the cross domain message
 * @param target    The target of the cross domain message
 * @param value     The value being sent with the cross domain message
 * @param gasLimit  The gas limit of the cross domain execution
 * @param data      The data passed along with the cross domain message
 */
export const hashCrossDomainMessage = (
  nonce: BigNumber,
  sender: string,
  target: string,
  value: BigNumber,
  gasLimit: BigNumber,
  data: string
) => {
  const [, version] = decodeVersionedNonce(nonce)
  if (version.eq(big0)) {
    return hashCrossDomainMessagev0(target, sender, data, nonce)
  } else if (version.eq(big1)) {
    return hashCrossDomainMessagev1(
      nonce,
      sender,
      target,
      value,
      gasLimit,
      data
    )
  }
  throw new Error(`unknown version ${version.toString()}`)
}

/**
 * Hahses a V0 cross domain message
 *
 * @param target    The target of the cross domain message
 * @param sender    The sender of the cross domain message
 * @param data      The data passed along with the cross domain message
 * @param nonce     The cross domain message nonce
 */
export const hashCrossDomainMessagev0 = (
  target: string,
  sender: string,
  data: string,
  nonce: BigNumber
) => {
  return keccak256(encodeCrossDomainMessageV0(target, sender, data, nonce))
}

/**
 * Hahses a V1 cross domain message
 *
 * @param nonce     The cross domain message nonce
 * @param sender    The sender of the cross domain message
 * @param target    The target of the cross domain message
 * @param value     The value being sent with the cross domain message
 * @param gasLimit  The gas limit of the cross domain execution
 * @param data      The data passed along with the cross domain message
 */
export const hashCrossDomainMessagev1 = (
  nonce: BigNumber,
  sender: string,
  target: string,
  value: BigNumberish,
  gasLimit: BigNumberish,
  data: string
) => {
  return keccak256(
    encodeCrossDomainMessageV1(nonce, sender, target, value, gasLimit, data)
  )
}

/**
 * Hashes a withdrawal
 *
 * @param nonce     The cross domain message nonce
 * @param sender    The sender of the cross domain message
 * @param target    The target of the cross domain message
 * @param value     The value being sent with the cross domain message
 * @param gasLimit  The gas limit of the cross domain execution
 * @param data      The data passed along with the cross domain message
 */
export const hashWithdrawal = (
  nonce: BigNumber,
  sender: string,
  target: string,
  value: BigNumber,
  gasLimit: BigNumber,
  data: string
): string => {
  const types = ['uint256', 'address', 'address', 'uint256', 'uint256', 'bytes']
  const encoded = defaultAbiCoder.encode(types, [
    nonce,
    sender,
    target,
    value,
    gasLimit,
    data,
  ])
  return keccak256(encoded)
}

/**
 * Hahses an output root proof
 *
 * @param proof OutputRootProof
 */
export const hashOutputRootProof = (proof: OutputRootProof): string => {
  return keccak256(
    defaultAbiCoder.encode(
      ['bytes32', 'bytes32', 'bytes32', 'bytes32'],
      [
        proof.version,
        proof.stateRoot,
        proof.withdrawerStorageRoot,
        proof.latestBlockhash,
      ]
    )
  )
}