hashing.ts 4.24 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

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

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

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

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

/**
 * 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
/**
 * 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
) => {
67 68
  const { version } = decodeVersionedNonce(nonce)
  if (version.eq(0)) {
69
    return hashCrossDomainMessagev0(target, sender, data, nonce)
70
  } else if (version.eq(1)) {
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
    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,
165
        proof.messagePasserStorageRoot,
166 167 168 169 170
        proof.latestBlockhash,
      ]
    )
  )
}