contracts.ts 10.9 KB
Newer Older
1 2
import { getContractInterface, predeploys } from '@eth-optimism/contracts'
import { ethers, Contract } from 'ethers'
3 4 5

import { toAddress } from './coercion'
import { DeepPartial } from './type-utils'
6 7 8 9 10 11 12
import {
  OEContracts,
  OEL1Contracts,
  OEL2Contracts,
  OEContractsLike,
  OEL2ContractsLike,
  AddressLike,
13 14
  BridgeAdapters,
  BridgeAdapterData,
15
  ICrossChainMessenger,
16
  L2ChainID,
17
} from '../interfaces'
18 19 20 21 22
import {
  StandardBridgeAdapter,
  ETHBridgeAdapter,
  DAIBridgeAdapter,
} from '../adapters'
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

/**
 * Full list of default L2 contract addresses.
 */
export const DEFAULT_L2_CONTRACT_ADDRESSES: OEL2ContractsLike = {
  L2CrossDomainMessenger: predeploys.L2CrossDomainMessenger,
  L2StandardBridge: predeploys.L2StandardBridge,
  OVM_L1BlockNumber: predeploys.OVM_L1BlockNumber,
  OVM_L2ToL1MessagePasser: predeploys.OVM_L2ToL1MessagePasser,
  OVM_DeployerWhitelist: predeploys.OVM_DeployerWhitelist,
  OVM_ETH: predeploys.OVM_ETH,
  OVM_GasPriceOracle: predeploys.OVM_GasPriceOracle,
  OVM_SequencerFeeVault: predeploys.OVM_SequencerFeeVault,
  WETH: predeploys.WETH9,
}

/**
 * We've changed some contract names in this SDK to be a bit nicer. Here we remap these nicer names
 * back to the original contract names so we can look them up.
 */
const NAME_REMAPPING = {
44 45 46
  AddressManager: 'Lib_AddressManager' as const,
  OVM_L1BlockNumber: 'iOVM_L1BlockNumber' as const,
  WETH: 'WETH9' as const,
47 48 49 50 51 52 53 54
}

/**
 * Mapping of L1 chain IDs to the appropriate contract addresses for the OE deployments to the
 * given network. Simplifies the process of getting the correct contract addresses for a given
 * contract name.
 */
export const CONTRACT_ADDRESSES: {
55
  [ChainID in L2ChainID]: OEContractsLike
56
} = {
57
  [L2ChainID.OPTIMISM]: {
58
    l1: {
59 60 61 62 63 64 65 66 67
      AddressManager: '0xdE1FCfB0851916CA5101820A69b13a4E276bd81F' as const,
      L1CrossDomainMessenger:
        '0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1' as const,
      L1StandardBridge: '0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1' as const,
      StateCommitmentChain:
        '0xBe5dAb4A2e9cd0F27300dB4aB94BeE3A233AEB19' as const,
      CanonicalTransactionChain:
        '0x5E4e65926BA27467555EB562121fac00D24E9dD2' as const,
      BondManager: '0xcd626E1328b41fCF24737F137BcD4CE0c32bc8d1' as const,
68 69 70
    },
    l2: DEFAULT_L2_CONTRACT_ADDRESSES,
  },
71
  [L2ChainID.OPTIMISM_KOVAN]: {
72
    l1: {
73 74 75 76 77 78 79 80 81
      AddressManager: '0x100Dd3b414Df5BbA2B542864fF94aF8024aFdf3a' as const,
      L1CrossDomainMessenger:
        '0x4361d0F75A0186C05f971c566dC6bEa5957483fD' as const,
      L1StandardBridge: '0x22F24361D548e5FaAfb36d1437839f080363982B' as const,
      StateCommitmentChain:
        '0xD7754711773489F31A0602635f3F167826ce53C5' as const,
      CanonicalTransactionChain:
        '0xf7B88A133202d41Fe5E2Ab22e6309a1A4D50AF74' as const,
      BondManager: '0xc5a603d273E28185c18Ba4d26A0024B2d2F42740' as const,
82 83 84
    },
    l2: DEFAULT_L2_CONTRACT_ADDRESSES,
  },
85
  [L2ChainID.OPTIMISM_GOERLI]: {
86
    l1: {
87
      AddressManager: '0xfA5b622409E1782597952a4A78c1D34CF32fF5e2' as const,
88
      L1CrossDomainMessenger:
89 90
        '0x5086d1eEF304eb5284A0f6720f79403b4e9bE294' as const,
      L1StandardBridge: '0x636Af16bf2f682dD3109e60102b8E1A089FedAa8' as const,
91
      StateCommitmentChain:
92
        '0x9c945aC97Baf48cB784AbBB61399beB71aF7A378' as const,
93
      CanonicalTransactionChain:
94 95
        '0x607F755149cFEB3a14E1Dc3A4E2450Cde7dfb04D' as const,
      BondManager: '0xfC2ab6987C578218f99E85d61Dcf4814A26637Bd' as const,
96 97 98
    },
    l2: DEFAULT_L2_CONTRACT_ADDRESSES,
  },
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
  [L2ChainID.OPTIMISM_HARDHAT_LOCAL]: {
    l1: {
      AddressManager: '0x5FbDB2315678afecb367f032d93F642f64180aa3' as const,
      L1CrossDomainMessenger:
        '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318' as const,
      L1StandardBridge: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788' as const,
      StateCommitmentChain:
        '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9' as const,
      CanonicalTransactionChain:
        '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9' as const,
      BondManager: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707' as const,
    },
    l2: DEFAULT_L2_CONTRACT_ADDRESSES,
  },
  [L2ChainID.OPTIMISM_HARDHAT_DEVNET]: {
114
    l1: {
115 116 117 118 119 120 121 122 123
      AddressManager: '0x5FbDB2315678afecb367f032d93F642f64180aa3' as const,
      L1CrossDomainMessenger:
        '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318' as const,
      L1StandardBridge: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788' as const,
      StateCommitmentChain:
        '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9' as const,
      CanonicalTransactionChain:
        '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9' as const,
      BondManager: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707' as const,
124 125 126 127 128
    },
    l2: DEFAULT_L2_CONTRACT_ADDRESSES,
  },
}

129 130 131 132
/**
 * Mapping of L1 chain IDs to the list of custom bridge addresses for each chain.
 */
export const BRIDGE_ADAPTER_DATA: {
133
  [ChainID in L2ChainID]?: BridgeAdapterData
134
} = {
135
  [L2ChainID.OPTIMISM]: {
136 137
    BitBTC: {
      Adapter: StandardBridgeAdapter,
138 139
      l1Bridge: '0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128' as const,
      l2Bridge: '0x158F513096923fF2d3aab2BcF4478536de6725e2' as const,
140 141 142
    },
    DAI: {
      Adapter: DAIBridgeAdapter,
143 144
      l1Bridge: '0x10E6593CDda8c58a1d0f14C5164B376352a55f2F' as const,
      l2Bridge: '0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65' as const,
145 146
    },
  },
147
  [L2ChainID.OPTIMISM_KOVAN]: {
148 149
    BitBTC: {
      Adapter: StandardBridgeAdapter,
150 151
      l1Bridge: '0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746' as const,
      l2Bridge: '0x0CFb46528a7002a7D8877a5F7a69b9AaF1A9058e' as const,
152 153 154
    },
    USX: {
      Adapter: StandardBridgeAdapter,
155 156
      l1Bridge: '0x40E862341b2416345F02c41Ac70df08525150dC7' as const,
      l2Bridge: '0xB4d37826b14Cd3CB7257A2A5094507d701fe715f' as const,
157 158 159
    },
    DAI: {
      Adapter: DAIBridgeAdapter,
160 161
      l1Bridge: '0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3' as const,
      l2Bridge: '0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65' as const,
162 163 164 165
    },
  },
}

166 167
/**
 * Returns an ethers.Contract object for the given name, connected to the appropriate address for
168
 * the given L2 chain ID. Users can also provide a custom address to connect the contract to
169 170 171 172
 * instead. If the chain ID is not known then the user MUST provide a custom address or this
 * function will throw an error.
 *
 * @param contractName Name of the contract to connect to.
173
 * @param l2ChainId Chain ID for the L2 network.
174 175 176 177 178 179 180
 * @param opts Additional options for connecting to the contract.
 * @param opts.address Custom address to connect to the contract.
 * @param opts.signerOrProvider Signer or provider to connect to the contract.
 * @returns An ethers.Contract object connected to the appropriate address and interface.
 */
export const getOEContract = (
  contractName: keyof OEL1Contracts | keyof OEL2Contracts,
181
  l2ChainId: number,
182 183 184 185 186
  opts: {
    address?: AddressLike
    signerOrProvider?: ethers.Signer | ethers.providers.Provider
  } = {}
): Contract => {
187
  const addresses = CONTRACT_ADDRESSES[l2ChainId]
188 189
  if (addresses === undefined && opts.address === undefined) {
    throw new Error(
190
      `cannot get contract ${contractName} for unknown L2 chain ID ${l2ChainId}, you must provide an address`
191 192 193 194 195 196 197 198 199 200 201 202 203
    )
  }

  return new Contract(
    toAddress(
      opts.address || addresses.l1[contractName] || addresses.l2[contractName]
    ),
    getContractInterface(NAME_REMAPPING[contractName] || contractName),
    opts.signerOrProvider
  )
}

/**
204
 * Automatically connects to all contract addresses, both L1 and L2, for the given L2 chain ID. The
205 206 207 208
 * user can provide custom contract address overrides for L1 or L2 contracts. If the given chain ID
 * is not known then the user MUST provide custom contract addresses for ALL L1 contracts or this
 * function will throw an error.
 *
209
 * @param l2ChainId Chain ID for the L2 network.
210 211 212 213 214 215 216 217
 * @param opts Additional options for connecting to the contracts.
 * @param opts.l1SignerOrProvider: Signer or provider to connect to the L1 contracts.
 * @param opts.l2SignerOrProvider: Signer or provider to connect to the L2 contracts.
 * @param opts.overrides Custom contract address overrides for L1 or L2 contracts.
 * @returns An object containing ethers.Contract objects connected to the appropriate addresses on
 * both L1 and L2.
 */
export const getAllOEContracts = (
218
  l2ChainId: number,
219 220 221 222 223 224
  opts: {
    l1SignerOrProvider?: ethers.Signer | ethers.providers.Provider
    l2SignerOrProvider?: ethers.Signer | ethers.providers.Provider
    overrides?: DeepPartial<OEContractsLike>
  } = {}
): OEContracts => {
225
  const addresses = CONTRACT_ADDRESSES[l2ChainId] || {
226 227 228 229 230 231 232 233 234 235 236 237
    l1: {
      AddressManager: undefined,
      L1CrossDomainMessenger: undefined,
      L1StandardBridge: undefined,
      StateCommitmentChain: undefined,
      CanonicalTransactionChain: undefined,
      BondManager: undefined,
    },
    l2: DEFAULT_L2_CONTRACT_ADDRESSES,
  }

  // Attach all L1 contracts.
238
  const l1Contracts = {} as OEL1Contracts
239
  for (const [contractName, contractAddress] of Object.entries(addresses.l1)) {
240 241
    l1Contracts[contractName] = getOEContract(
      contractName as keyof OEL1Contracts,
242
      l2ChainId,
243 244 245 246 247
      {
        address: opts.overrides?.l1?.[contractName] || contractAddress,
        signerOrProvider: opts.l1SignerOrProvider,
      }
    )
248 249 250
  }

  // Attach all L2 contracts.
251
  const l2Contracts = {} as OEL2Contracts
252
  for (const [contractName, contractAddress] of Object.entries(addresses.l2)) {
253 254
    l2Contracts[contractName] = getOEContract(
      contractName as keyof OEL2Contracts,
255
      l2ChainId,
256 257 258 259 260
      {
        address: opts.overrides?.l2?.[contractName] || contractAddress,
        signerOrProvider: opts.l2SignerOrProvider,
      }
    )
261 262 263 264 265 266 267
  }

  return {
    l1: l1Contracts,
    l2: l2Contracts,
  }
}
268 269

/**
270
 * Gets a series of bridge adapters for the given L2 chain ID.
271
 *
272
 * @param l2ChainId Chain ID for the L2 network.
273
 * @param messenger Cross chain messenger to connect to the bridge adapters
274
 * @param opts Additional options for connecting to the custom bridges.
275 276
 * @param opts.overrides Custom bridge adapters.
 * @returns An object containing all bridge adapters
277
 */
278
export const getBridgeAdapters = (
279
  l2ChainId: number,
280
  messenger: ICrossChainMessenger,
281 282
  opts?: {
    overrides?: BridgeAdapterData
283
  }
284
): BridgeAdapters => {
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
  const adapterData: BridgeAdapterData = {
    ...(CONTRACT_ADDRESSES[l2ChainId]
      ? {
          Standard: {
            Adapter: StandardBridgeAdapter,
            l1Bridge: CONTRACT_ADDRESSES[l2ChainId].l1.L1StandardBridge,
            l2Bridge: predeploys.L2StandardBridge,
          },
          ETH: {
            Adapter: ETHBridgeAdapter,
            l1Bridge: CONTRACT_ADDRESSES[l2ChainId].l1.L1StandardBridge,
            l2Bridge: predeploys.L2StandardBridge,
          },
        }
      : {}),
    ...(BRIDGE_ADAPTER_DATA[l2ChainId] || {}),
301
    ...(opts?.overrides || {}),
302 303 304 305
  }

  const adapters: BridgeAdapters = {}
  for (const [bridgeName, bridgeData] of Object.entries(adapterData)) {
306
    adapters[bridgeName] = new bridgeData.Adapter({
307
      messenger,
308 309 310
      l1Bridge: bridgeData.l1Bridge,
      l2Bridge: bridgeData.l2Bridge,
    })
311 312
  }

313
  return adapters
314
}