hashing.ts 4.29 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
/**
 * 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,
65
  message: string
66
) => {
67 68
  const { version } = decodeVersionedNonce(nonce)
  if (version.eq(0)) {
69
    return hashCrossDomainMessagev0(target, sender, message, nonce)
70
  } else if (version.eq(1)) {
71 72 73 74 75 76
    return hashCrossDomainMessagev1(
      nonce,
      sender,
      target,
      value,
      gasLimit,
77
      message
78 79 80 81 82 83 84 85 86 87
    )
  }
  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
88
 * @param message      The message passed along with the cross domain message
89 90 91 92 93
 * @param nonce     The cross domain message nonce
 */
export const hashCrossDomainMessagev0 = (
  target: string,
  sender: string,
94
  message: string,
95 96
  nonce: BigNumber
) => {
97
  return keccak256(encodeCrossDomainMessageV0(target, sender, message, nonce))
98 99 100 101 102 103 104 105 106 107
}

/**
 * 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
108
 * @param message      The message passed along with the cross domain message
109 110 111 112 113 114 115
 */
export const hashCrossDomainMessagev1 = (
  nonce: BigNumber,
  sender: string,
  target: string,
  value: BigNumberish,
  gasLimit: BigNumberish,
116
  message: string
117 118
) => {
  return keccak256(
119
    encodeCrossDomainMessageV1(nonce, sender, target, value, gasLimit, message)
120 121 122 123 124 125 126 127 128 129 130
  )
}

/**
 * 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
131
 * @param message      The message passed along with the cross domain message
132 133 134 135 136 137 138
 */
export const hashWithdrawal = (
  nonce: BigNumber,
  sender: string,
  target: string,
  value: BigNumber,
  gasLimit: BigNumber,
139
  message: string
140 141 142 143 144 145 146 147
): string => {
  const types = ['uint256', 'address', 'address', 'uint256', 'uint256', 'bytes']
  const encoded = defaultAbiCoder.encode(types, [
    nonce,
    sender,
    target,
    value,
    gasLimit,
148
    message,
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
  ])
  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,
      ]
    )
  )
}