utils.ts 6.18 KB
Newer Older
1
/* Imports: External */
2 3 4 5 6 7 8
import {
  Contract,
  Wallet,
  constants,
  providers,
  BigNumberish,
  BigNumber,
9
  utils,
10
} from 'ethers'
11 12 13 14 15 16 17 18 19 20 21
import {
  getContractFactory,
  getContractInterface,
  predeploys,
} from '@eth-optimism/contracts'
import { injectL2Context, remove0x, Watcher } from '@eth-optimism/core-utils'
import { cleanEnv, str, num, bool } from 'envalid'
import dotenv from 'dotenv'

/* Imports: Internal */
import { Direction, waitForXDomainTransaction } from './watcher-utils'
22
import { OptimismEnv } from './env'
23

24 25
export const GWEI = BigNumber.from(1e9)

26 27 28 29 30
export const isLiveNetwork = () => {
  return process.env.IS_LIVE_NETWORK === 'true'
}

if (isLiveNetwork()) {
31 32 33
  dotenv.config()
}

34
const env = cleanEnv(process.env, {
35 36
  L1_URL: str({ default: 'http://localhost:9545' }),
  L2_URL: str({ default: 'http://localhost:8545' }),
37
  VERIFIER_URL: str({ default: 'http://localhost:8547' }),
38
  REPLICA_URL: str({ default: 'http://localhost:8549' }),
39 40
  L1_POLLING_INTERVAL: num({ default: 10 }),
  L2_POLLING_INTERVAL: num({ default: 10 }),
41
  VERIFIER_POLLING_INTERVAL: num({ default: 10 }),
42
  REPLICA_POLLING_INTERVAL: num({ default: 10 }),
43 44 45 46 47 48 49
  PRIVATE_KEY: str({
    default:
      '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
  }),
  ADDRESS_MANAGER: str({
    default: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
  }),
50 51 52 53
  GAS_PRICE_ORACLE_PRIVATE_KEY: str({
    default:
      '0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba',
  }),
54 55
  L2_CHAINID: num({ default: 420 }),
  IS_LIVE_NETWORK: bool({ default: false }),
56 57
})

58
// The hardhat instance
59 60 61
export const l1Provider = new providers.JsonRpcProvider(env.L1_URL)
l1Provider.pollingInterval = env.L1_POLLING_INTERVAL

62 63 64
export const l2Provider = injectL2Context(
  new providers.JsonRpcProvider(env.L2_URL)
)
65
l2Provider.pollingInterval = env.L2_POLLING_INTERVAL
66

67 68 69
export const verifierProvider = injectL2Context(
  new providers.JsonRpcProvider(env.VERIFIER_URL)
)
70 71
verifierProvider.pollingInterval = env.VERIFIER_POLLING_INTERVAL

72 73 74
export const replicaProvider = injectL2Context(
  new providers.JsonRpcProvider(env.REPLICA_URL)
)
75 76
replicaProvider.pollingInterval = env.REPLICA_POLLING_INTERVAL

77
// The sequencer private key which is funded on L1
78
export const l1Wallet = new Wallet(env.PRIVATE_KEY, l1Provider)
79 80 81 82 83

// A random private key which should always be funded with deposits from L1 -> L2
// if it's using non-0 gas price
export const l2Wallet = l1Wallet.connect(l2Provider)

84 85 86 87 88 89
// The owner of the GasPriceOracle on L2
export const gasPriceOracleWallet = new Wallet(
  env.GAS_PRICE_ORACLE_PRIVATE_KEY,
  l2Provider
)

90 91 92
// Predeploys
export const PROXY_SEQUENCER_ENTRYPOINT_ADDRESS =
  '0x4200000000000000000000000000000000000004'
93
export const OVM_ETH_ADDRESS = predeploys.OVM_ETH
94

95 96 97
export const L2_CHAINID = env.L2_CHAINID
export const IS_LIVE_NETWORK = env.IS_LIVE_NETWORK

98 99 100
export const getAddressManager = (provider: any) => {
  return getContractFactory('Lib_AddressManager')
    .connect(provider)
101
    .attach(env.ADDRESS_MANAGER)
102
}
103

104 105
// Gets the bridge contract
export const getL1Bridge = async (wallet: Wallet, AddressManager: Contract) => {
106
  const l1BridgeInterface = getContractInterface('L1StandardBridge')
107
  const ProxyBridgeAddress = await AddressManager.getAddress(
108
    'Proxy__OVM_L1StandardBridge'
109
  )
110 111 112 113 114

  if (
    !utils.isAddress(ProxyBridgeAddress) ||
    ProxyBridgeAddress === constants.AddressZero
  ) {
115
    throw new Error('Proxy__OVM_L1StandardBridge not found')
116 117
  }

118
  const L1StandardBridge = new Contract(
119 120
    ProxyBridgeAddress,
    l1BridgeInterface,
121 122
    wallet
  )
123
  return L1StandardBridge
124 125 126
}

export const getL2Bridge = async (wallet: Wallet) => {
127
  const L2BridgeInterface = getContractInterface('L2StandardBridge')
128

129 130
  const L2StandardBridge = new Contract(
    predeploys.L2StandardBridge,
131 132 133
    L2BridgeInterface,
    wallet
  )
134
  return L2StandardBridge
135 136 137 138 139 140 141 142 143 144 145 146 147 148
}

export const getOvmEth = (wallet: Wallet) => {
  const OVM_ETH = new Contract(
    OVM_ETH_ADDRESS,
    getContractInterface('OVM_ETH'),
    wallet
  )

  return OVM_ETH
}

export const fundUser = async (
  watcher: Watcher,
149
  bridge: Contract,
150 151 152 153 154
  amount: BigNumberish,
  recipient?: string
) => {
  const value = BigNumber.from(amount)
  const tx = recipient
155 156
    ? bridge.depositETHTo(recipient, 1_300_000, '0x', { value })
    : bridge.depositETH(1_300_000, '0x', { value })
157

158 159 160 161
  await waitForXDomainTransaction(watcher, tx, Direction.L1ToL2)
}

export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
162 163 164 165 166

const abiCoder = new utils.AbiCoder()
export const encodeSolidityRevertMessage = (_reason: string): string => {
  return '0x08c379a0' + remove0x(abiCoder.encode(['string'], [_reason]))
}
167

168 169 170 171 172 173 174 175
export const defaultTransactionFactory = () => {
  return {
    to: '0x' + '1234'.repeat(10),
    gasLimit: 8_000_000,
    gasPrice: BigNumber.from(0),
    data: '0x',
    value: 0,
  }
176
}
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191
export const waitForL2Geth = async (
  provider: providers.JsonRpcProvider
): Promise<providers.JsonRpcProvider> => {
  let ready: boolean = false
  while (!ready) {
    try {
      await provider.getNetwork()
      ready = true
    } catch (error) {
      await sleep(1000)
    }
  }
  return injectL2Context(provider)
}
192

Matthew Slipper's avatar
Matthew Slipper committed
193 194
// eslint-disable-next-line @typescript-eslint/no-shadow
export const gasPriceForL2 = async (env: OptimismEnv) => {
195 196 197 198 199
  // The integration tests enforce fees on L2
  // which run against hardhat on L1. Update if
  // geth --dev is adopted for L1
  const chainId = await env.l1Wallet.getChainId()
  if ((await isMainnet(env)) || chainId === 31337) {
Matthew Slipper's avatar
Matthew Slipper committed
200 201 202
    return env.l2Wallet.getGasPrice()
  }

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
  if (isLiveNetwork()) {
    return Promise.resolve(BigNumber.from(10000))
  }
  return Promise.resolve(BigNumber.from(0))
}

// eslint-disable-next-line @typescript-eslint/no-shadow
export const gasPriceForL1 = async (env: OptimismEnv) => {
  const chainId = await env.l1Wallet.getChainId()

  switch (chainId) {
    case 1:
      return env.l1Wallet.getGasPrice()
    case 3:
    case 42:
      return utils.parseUnits('10', 'gwei')
    case 5:
      return utils.parseUnits('2', 'gwei')
    default:
      return BigNumber.from(0)
  }
}
Matthew Slipper's avatar
Matthew Slipper committed
225 226 227 228 229 230

// eslint-disable-next-line @typescript-eslint/no-shadow
export const isMainnet = async (env: OptimismEnv) => {
  const chainId = await env.l1Wallet.getChainId()
  return chainId === 1
}