check-l2.ts 21.9 KB
Newer Older
1 2
import assert from 'assert'

3
import { task, types } from 'hardhat/config'
4 5 6
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
7
import { Contract, providers, Wallet, Signer, BigNumber } from 'ethers'
8 9 10 11 12

import { predeploys } from '../src'

// expectedSemver is the semver version of the contracts
// deployed at bedrock deployment
13
const expectedSemver = '1.0.0'
14 15 16 17 18 19
const implSlot =
  '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'
const adminSlot =
  '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103'
const prefix = '0x420000000000000000000000000000000000'

20 21 22 23
const logLoud = () => {
  console.log('   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
}

24 25 26 27 28 29
const yell = (msg: string) => {
  logLoud()
  console.log(msg)
  logLoud()
}

30
// checkPredeploys will ensure that all of the predeploys are set
31 32 33 34
const checkPredeploys = async (
  hre: HardhatRuntimeEnvironment,
  provider: providers.Provider
) => {
35 36 37 38 39 40 41
  console.log('Checking predeploys are configured correctly')
  for (let i = 0; i < 2048; i++) {
    const num = hre.ethers.utils.hexZeroPad('0x' + i.toString(16), 2)
    const addr = hre.ethers.utils.getAddress(
      hre.ethers.utils.hexConcat([prefix, num])
    )

42
    const code = await provider.getCode(addr)
43 44 45 46
    if (code === '0x') {
      throw new Error(`no code found at ${addr}`)
    }

47 48 49 50 51
    if (
      addr === predeploys.GovernanceToken ||
      addr === predeploys.ProxyAdmin ||
      addr === predeploys.WETH9
    ) {
52 53 54
      continue
    }

55
    const slot = await provider.getStorageAt(addr, adminSlot)
56 57 58 59 60 61 62 63
    const admin = hre.ethers.utils.hexConcat([
      '0x000000000000000000000000',
      predeploys.ProxyAdmin,
    ])

    if (admin !== slot) {
      throw new Error(`incorrect admin slot in ${addr}`)
    }
64 65 66 67

    if (i % 200 === 0) {
      console.log(`Checked through ${addr}`)
    }
68 69 70 71
  }
}

// assertSemver will ensure that the semver is the correct version
72 73 74 75 76 77
const assertSemver = async (
  contract: Contract,
  name: string,
  override?: string
) => {
  const version = await contract.version()
78 79 80 81 82 83 84 85 86 87 88
  let target = expectedSemver
  if (override) {
    target = override
  }
  if (version !== target) {
    throw new Error(
      `${name}: version mismatch. Got ${version}, expected ${target}`
    )
  }
  console.log(`  - version: ${version}`)
}
89

90
// checkProxy will print out the proxy slots
91 92 93 94 95
const checkProxy = async (
  _hre: HardhatRuntimeEnvironment,
  name: string,
  provider: providers.Provider
) => {
96 97 98 99 100
  const address = predeploys[name]
  if (!address) {
    throw new Error(`unknown contract name: ${name}`)
  }

101 102
  const impl = await provider.getStorageAt(address, implSlot)
  const admin = await provider.getStorageAt(address, adminSlot)
103 104 105 106 107 108

  console.log(`  - EIP-1967 implementation slot: ${impl}`)
  console.log(`  - EIP-1967 admin slot: ${admin}`)
}

// assertProxy will require the proxy is set
109 110 111 112 113
const assertProxy = async (
  hre: HardhatRuntimeEnvironment,
  name: string,
  provider: providers.Provider
) => {
114 115 116 117 118
  const address = predeploys[name]
  if (!address) {
    throw new Error(`unknown contract name: ${name}`)
  }

119
  const code = await provider.getCode(address)
120 121 122 123 124 125
  const deployInfo = await hre.artifacts.readArtifact('Proxy')

  if (code !== deployInfo.deployedBytecode) {
    throw new Error(`${address}: code mismatch`)
  }

126
  const impl = await provider.getStorageAt(address, implSlot)
127
  const implAddress = '0x' + impl.slice(26)
128
  const implCode = await provider.getCode(implAddress)
129 130
  if (implCode === '0x') {
    throw new Error('No code at implementation')
131 132 133
  }
}

134 135 136 137
// checks to make sure that the genesis magic value
// was set correctly
const checkGenesisMagic = async (
  hre: HardhatRuntimeEnvironment,
138 139
  l2Provider: providers.Provider,
  args
140 141
) => {
  const magic = '0x' + Buffer.from('BEDROCK').toString('hex')
142 143 144 145 146 147 148
  let startingBlockNumber: number

  // We have a connection to the L1 chain, fetch the remote value
  if (args.l1RpcUrl !== '') {
    const l1Provider = new hre.ethers.providers.StaticJsonRpcProvider(
      args.l1RpcUrl
    )
149 150 151 152 153 154 155 156

    // Get the address if it was passed in via CLI
    // Otherwise get the address from a hardhat deployment file
    let address: string
    if (args.l2OutputOracleAddress !== '') {
      address = args.l2OutputOracleAddress
    } else {
      const Deployment__L2OutputOracle = await hre.deployments.get(
157
        'L2OutputOracleProxy'
158 159 160 161 162 163 164 165 166 167 168 169 170
      )
      address = Deployment__L2OutputOracle.address
    }

    const abi = {
      inputs: [],
      name: 'startingBlockNumber',
      outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
      stateMutability: 'view',
      type: 'function',
    }

    const L2OutputOracle = new hre.ethers.Contract(address, [abi], l1Provider)
171 172 173 174 175 176 177 178

    startingBlockNumber = await L2OutputOracle.startingBlockNumber()
  } else {
    // We do not have a connection to the L1 chain, use the local config
    // The `--network` flag must be set to the L1 network
    startingBlockNumber = hre.deployConfig.l2OutputOracleStartingBlockNumber
  }

179 180 181
  // ensure that the starting block number is a number
  startingBlockNumber = BigNumber.from(startingBlockNumber).toNumber()

182 183
  const block = await l2Provider.getBlock(startingBlockNumber)
  const extradata = block.extraData
184 185 186 187 188 189

  if (extradata !== magic) {
    throw new Error('magic value in extradata does not match')
  }
}

190 191 192
const check = {
  // LegacyMessagePasser
  // - check version
193
  // - is behind a proxy
194 195 196 197
  LegacyMessagePasser: async (
    hre: HardhatRuntimeEnvironment,
    signer: Signer
  ) => {
198 199
    const LegacyMessagePasser = await hre.ethers.getContractAt(
      'LegacyMessagePasser',
200 201
      predeploys.LegacyMessagePasser,
      signer
202 203
    )

204
    await assertSemver(LegacyMessagePasser, 'LegacyMessagePasser')
205 206
    await checkProxy(hre, 'LegacyMessagePasser', signer.provider)
    await assertProxy(hre, 'LegacyMessagePasser', signer.provider)
207 208 209
  },
  // DeployerWhitelist
  // - check version
210 211
  // - is behind a proxy
  // - owner is `address(0)`
212
  DeployerWhitelist: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
213 214
    const DeployerWhitelist = await hre.ethers.getContractAt(
      'DeployerWhitelist',
215 216
      predeploys.DeployerWhitelist,
      signer
217 218
    )

219
    await assertSemver(DeployerWhitelist, 'DeployerWhitelist')
220 221

    const owner = await DeployerWhitelist.owner()
222
    assert(owner === hre.ethers.constants.AddressZero)
223 224
    console.log(`  - owner: ${owner}`)

225 226
    await checkProxy(hre, 'DeployerWhitelist', signer.provider)
    await assertProxy(hre, 'DeployerWhitelist', signer.provider)
227
  },
228 229 230 231 232 233 234
  // L2CrossDomainMessenger
  // - check version
  // - check OTHER_MESSENGER
  // - check l1CrossDomainMessenger (legacy)
  // - is behind a proxy
  // - check owner
  // - check initialized
235 236 237 238
  L2CrossDomainMessenger: async (
    hre: HardhatRuntimeEnvironment,
    signer: Signer
  ) => {
239 240
    const L2CrossDomainMessenger = await hre.ethers.getContractAt(
      'L2CrossDomainMessenger',
241 242
      predeploys.L2CrossDomainMessenger,
      signer
243 244
    )

245
    await assertSemver(L2CrossDomainMessenger, 'L2CrossDomainMessenger')
246

247
    const xDomainMessageSenderSlot = await signer.provider.getStorageAt(
248 249 250 251 252
      predeploys.L2CrossDomainMessenger,
      204
    )

    const xDomainMessageSender = '0x' + xDomainMessageSenderSlot.slice(26)
253 254 255
    assert(
      xDomainMessageSender === '0x000000000000000000000000000000000000dead'
    )
256 257

    const otherMessenger = await L2CrossDomainMessenger.OTHER_MESSENGER()
258 259
    assert(otherMessenger !== hre.ethers.constants.AddressZero)
    yell(`  - OTHER_MESSENGER: ${otherMessenger}`)
260 261 262

    const l1CrossDomainMessenger =
      await L2CrossDomainMessenger.l1CrossDomainMessenger()
263
    yell(`  - l1CrossDomainMessenger: ${l1CrossDomainMessenger}`)
264

265 266
    await checkProxy(hre, 'L2CrossDomainMessenger', signer.provider)
    await assertProxy(hre, 'L2CrossDomainMessenger', signer.provider)
267 268

    const owner = await L2CrossDomainMessenger.owner()
269 270
    assert(owner !== hre.ethers.constants.AddressZero)
    yell(`  - owner: ${owner}`)
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

    const MESSAGE_VERSION = await L2CrossDomainMessenger.MESSAGE_VERSION()
    console.log(`  - MESSAGE_VERSION: ${MESSAGE_VERSION}`)
    const MIN_GAS_CALLDATA_OVERHEAD =
      await L2CrossDomainMessenger.MIN_GAS_CALLDATA_OVERHEAD()
    console.log(`  - MIN_GAS_CALLDATA_OVERHEAD: ${MIN_GAS_CALLDATA_OVERHEAD}`)
    const MIN_GAS_CONSTANT_OVERHEAD =
      await L2CrossDomainMessenger.MIN_GAS_CONSTANT_OVERHEAD()
    console.log(`  - MIN_GAS_CONSTANT_OVERHEAD: ${MIN_GAS_CONSTANT_OVERHEAD}`)
    const MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR =
      await L2CrossDomainMessenger.MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR()
    console.log(
      `  - MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR: ${MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR}`
    )
    const MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR =
      await L2CrossDomainMessenger.MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR()
    console.log(
      `  - MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR: ${MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR}`
    )

291
    const slot = await signer.provider.getStorageAt(
292 293 294 295 296 297 298 299
      predeploys.L2CrossDomainMessenger,
      0
    )

    const spacer = '0x' + slot.slice(26)
    console.log(`  - legacy spacer: ${spacer}`)

    const initialized = '0x' + slot.slice(24, 26)
300
    assert(initialized === '0x01')
301
    console.log(`  - initialized: ${initialized}`)
302
  },
303 304 305
  // GasPriceOracle
  // - check version
  // - check decimals
306
  GasPriceOracle: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
307 308
    const GasPriceOracle = await hre.ethers.getContractAt(
      'GasPriceOracle',
309 310
      predeploys.GasPriceOracle,
      signer
311 312
    )

313
    await assertSemver(GasPriceOracle, 'GasPriceOracle')
314 315

    const decimals = await GasPriceOracle.decimals()
316
    assert(decimals.eq(6))
317 318
    console.log(`  - decimals: ${decimals.toNumber()}`)

319 320
    await checkProxy(hre, 'GasPriceOracle', signer.provider)
    await assertProxy(hre, 'GasPriceOracle', signer.provider)
321
  },
322 323
  // L2StandardBridge
  // - check version
324
  L2StandardBridge: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
325 326
    const L2StandardBridge = await hre.ethers.getContractAt(
      'L2StandardBridge',
327 328
      predeploys.L2StandardBridge,
      signer
329 330
    )

331
    await assertSemver(L2StandardBridge, 'L2StandardBridge', '1.1.0')
332 333

    const OTHER_BRIDGE = await L2StandardBridge.OTHER_BRIDGE()
334 335
    assert(OTHER_BRIDGE !== hre.ethers.constants.AddressZero)
    yell(`  - OTHER_BRIDGE: ${OTHER_BRIDGE}`)
336 337

    const MESSENGER = await L2StandardBridge.MESSENGER()
338
    assert(MESSENGER === predeploys.L2CrossDomainMessenger)
339

340 341
    await checkProxy(hre, 'L2StandardBridge', signer.provider)
    await assertProxy(hre, 'L2StandardBridge', signer.provider)
342
  },
343 344 345 346
  // SequencerFeeVault
  // - check version
  // - check RECIPIENT
  // - check l1FeeWallet (legacy)
347
  SequencerFeeVault: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
348 349
    const SequencerFeeVault = await hre.ethers.getContractAt(
      'SequencerFeeVault',
350 351
      predeploys.SequencerFeeVault,
      signer
352 353
    )

354
    await assertSemver(SequencerFeeVault, 'SequencerFeeVault')
355 356

    const RECIPIENT = await SequencerFeeVault.RECIPIENT()
357 358
    assert(RECIPIENT !== hre.ethers.constants.AddressZero)
    yell(`  - RECIPIENT: ${RECIPIENT}`)
359 360

    const l1FeeWallet = await SequencerFeeVault.l1FeeWallet()
361
    assert(l1FeeWallet !== hre.ethers.constants.AddressZero)
362 363 364 365 366 367
    console.log(`  - l1FeeWallet: ${l1FeeWallet}`)

    const MIN_WITHDRAWAL_AMOUNT =
      await SequencerFeeVault.MIN_WITHDRAWAL_AMOUNT()
    console.log(`  - MIN_WITHDRAWAL_AMOUNT: ${MIN_WITHDRAWAL_AMOUNT}`)

368 369
    await checkProxy(hre, 'SequencerFeeVault', signer.provider)
    await assertProxy(hre, 'SequencerFeeVault', signer.provider)
370
  },
371 372
  // OptimismMintableERC20Factory
  // - check version
373 374 375 376
  OptimismMintableERC20Factory: async (
    hre: HardhatRuntimeEnvironment,
    signer: Signer
  ) => {
377 378
    const OptimismMintableERC20Factory = await hre.ethers.getContractAt(
      'OptimismMintableERC20Factory',
379 380
      predeploys.OptimismMintableERC20Factory,
      signer
381 382
    )

383 384
    await assertSemver(
      OptimismMintableERC20Factory,
385
      'OptimismMintableERC20Factory'
386
    )
387 388

    const BRIDGE = await OptimismMintableERC20Factory.BRIDGE()
389
    assert(BRIDGE !== hre.ethers.constants.AddressZero)
390

391 392
    await checkProxy(hre, 'OptimismMintableERC20Factory', signer.provider)
    await assertProxy(hre, 'OptimismMintableERC20Factory', signer.provider)
393
  },
394 395
  // L1BlockNumber
  // - check version
396
  L1BlockNumber: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
397 398
    const L1BlockNumber = await hre.ethers.getContractAt(
      'L1BlockNumber',
399 400
      predeploys.L1BlockNumber,
      signer
401 402
    )

403
    await assertSemver(L1BlockNumber, 'L1BlockNumber')
404

405 406
    await checkProxy(hre, 'L1BlockNumber', signer.provider)
    await assertProxy(hre, 'L1BlockNumber', signer.provider)
407
  },
408 409
  // L1Block
  // - check version
410
  L1Block: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
411 412
    const L1Block = await hre.ethers.getContractAt(
      'L1Block',
413 414
      predeploys.L1Block,
      signer
415 416
    )

417
    await assertSemver(L1Block, 'L1Block')
418

419 420
    await checkProxy(hre, 'L1Block', signer.provider)
    await assertProxy(hre, 'L1Block', signer.provider)
421
  },
422 423 424 425 426 427 428 429
  // LegacyERC20ETH
  // - not behind a proxy
  // - check name
  // - check symbol
  // - check decimals
  // - check BRIDGE
  // - check REMOTE_TOKEN
  // - totalSupply should be set to 0
430
  LegacyERC20ETH: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
431 432
    const LegacyERC20ETH = await hre.ethers.getContractAt(
      'LegacyERC20ETH',
433 434
      predeploys.LegacyERC20ETH,
      signer
435 436
    )

437
    const name = await LegacyERC20ETH.name()
438
    assert(name === 'Ether')
439 440 441
    console.log(`  - name: ${name}`)

    const symbol = await LegacyERC20ETH.symbol()
442
    assert(symbol === 'ETH')
443 444 445
    console.log(`  - symbol: ${symbol}`)

    const decimals = await LegacyERC20ETH.decimals()
446
    assert(decimals === 18)
447 448 449
    console.log(`  - decimals: ${decimals}`)

    const BRIDGE = await LegacyERC20ETH.BRIDGE()
450
    assert(BRIDGE === predeploys.L2StandardBridge)
451 452

    const REMOTE_TOKEN = await LegacyERC20ETH.REMOTE_TOKEN()
453
    assert(REMOTE_TOKEN === hre.ethers.constants.AddressZero)
454 455

    const totalSupply = await LegacyERC20ETH.totalSupply()
456 457
    assert(totalSupply.eq(0))
    console.log(`  - totalSupply: ${totalSupply}`)
458

459
    await checkProxy(hre, 'LegacyERC20ETH', signer.provider)
460
    // No proxy at this address, don't call assertProxy
461
  },
462 463 464 465
  // WETH9
  // - check name
  // - check symbol
  // - check decimals
466 467 468 469 470 471
  WETH9: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
    const WETH9 = await hre.ethers.getContractAt(
      'WETH9',
      predeploys.WETH9,
      signer
    )
472 473

    const name = await WETH9.name()
474
    assert(name === 'Wrapped Ether')
475 476 477
    console.log(`  - name: ${name}`)

    const symbol = await WETH9.symbol()
478
    assert(symbol === 'WETH')
479 480 481
    console.log(`  - symbol: ${symbol}`)

    const decimals = await WETH9.decimals()
482
    assert(decimals === 18)
483
    console.log(`  - decimals: ${decimals}`)
484
  },
485 486 487 488 489
  // GovernanceToken
  // - not behind a proxy
  // - check name
  // - check symbol
  // - check owner
490
  GovernanceToken: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
491 492
    const GovernanceToken = await hre.ethers.getContractAt(
      'GovernanceToken',
493 494
      predeploys.GovernanceToken,
      signer
495 496
    )

497
    const name = await GovernanceToken.name()
498
    assert(name === 'Optimism')
499 500 501
    console.log(`  - name: ${name}`)

    const symbol = await GovernanceToken.symbol()
502
    assert(symbol === 'OP')
503 504 505
    console.log(`  - symbol: ${symbol}`)

    const owner = await GovernanceToken.owner()
506
    yell(`  - owner: ${owner}`)
507 508 509 510

    const totalSupply = await GovernanceToken.totalSupply()
    console.log(`  - totalSupply: ${totalSupply}`)

511
    await checkProxy(hre, 'GovernanceToken', signer.provider)
512
    // No proxy at this address, don't call assertProxy
513
  },
514 515
  // L2ERC721Bridge
  // - check version
516
  L2ERC721Bridge: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
517 518
    const L2ERC721Bridge = await hre.ethers.getContractAt(
      'L2ERC721Bridge',
519 520
      predeploys.L2ERC721Bridge,
      signer
521 522
    )

523
    await assertSemver(L2ERC721Bridge, 'L2ERC721Bridge')
524 525

    const MESSENGER = await L2ERC721Bridge.MESSENGER()
526
    assert(MESSENGER !== hre.ethers.constants.AddressZero)
527
    console.log(`  - MESSENGER: ${MESSENGER}`)
528 529

    const OTHER_BRIDGE = await L2ERC721Bridge.OTHER_BRIDGE()
530 531
    assert(OTHER_BRIDGE !== hre.ethers.constants.AddressZero)
    yell(`  - OTHER_BRIDGE: ${OTHER_BRIDGE}`)
532

533 534
    await checkProxy(hre, 'L2ERC721Bridge', signer.provider)
    await assertProxy(hre, 'L2ERC721Bridge', signer.provider)
535
  },
536 537
  // OptimismMintableERC721Factory
  // - check version
538 539 540 541
  OptimismMintableERC721Factory: async (
    hre: HardhatRuntimeEnvironment,
    signer: Signer
  ) => {
542 543
    const OptimismMintableERC721Factory = await hre.ethers.getContractAt(
      'OptimismMintableERC721Factory',
544 545
      predeploys.OptimismMintableERC721Factory,
      signer
546 547
    )

548 549
    await assertSemver(
      OptimismMintableERC721Factory,
550
      'OptimismMintableERC721Factory'
551
    )
552 553

    const BRIDGE = await OptimismMintableERC721Factory.BRIDGE()
554
    assert(BRIDGE !== hre.ethers.constants.AddressZero)
555 556 557 558
    console.log(`  - BRIDGE: ${BRIDGE}`)

    const REMOTE_CHAIN_ID =
      await OptimismMintableERC721Factory.REMOTE_CHAIN_ID()
559
    assert(REMOTE_CHAIN_ID !== 0)
560 561
    console.log(`  - REMOTE_CHAIN_ID: ${REMOTE_CHAIN_ID}`)

562 563
    await checkProxy(hre, 'OptimismMintableERC721Factory', signer.provider)
    await assertProxy(hre, 'OptimismMintableERC721Factory', signer.provider)
564
  },
565 566
  // ProxyAdmin
  // - check owner
567
  ProxyAdmin: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
568 569
    const ProxyAdmin = await hre.ethers.getContractAt(
      'ProxyAdmin',
570 571
      predeploys.ProxyAdmin,
      signer
572 573 574
    )

    const owner = await ProxyAdmin.owner()
575 576
    assert(owner !== hre.ethers.constants.AddressZero)
    yell(`  - owner: ${owner}`)
577 578 579

    const addressManager = await ProxyAdmin.addressManager()
    console.log(`  - addressManager: ${addressManager}`)
580

581 582
    await checkProxy(hre, 'ProxyAdmin', signer.provider)
    await assertProxy(hre, 'ProxyAdmin', signer.provider)
583
  },
584 585 586 587
  // BaseFeeVault
  // - check version
  // - check MIN_WITHDRAWAL_AMOUNT
  // - check RECIPIENT
588
  BaseFeeVault: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
589 590
    const BaseFeeVault = await hre.ethers.getContractAt(
      'BaseFeeVault',
591 592
      predeploys.BaseFeeVault,
      signer
593 594
    )

595
    await assertSemver(BaseFeeVault, 'BaseFeeVault')
596 597 598 599 600

    const MIN_WITHDRAWAL_AMOUNT = await BaseFeeVault.MIN_WITHDRAWAL_AMOUNT()
    console.log(`  - MIN_WITHDRAWAL_AMOUNT: ${MIN_WITHDRAWAL_AMOUNT}`)

    const RECIPIENT = await BaseFeeVault.RECIPIENT()
601 602
    assert(RECIPIENT !== hre.ethers.constants.AddressZero)
    yell(`  - RECIPIENT: ${RECIPIENT}`)
603

604 605
    await checkProxy(hre, 'BaseFeeVault', signer.provider)
    await assertProxy(hre, 'BaseFeeVault', signer.provider)
606
  },
607 608 609 610
  // L1FeeVault
  // - check version
  // - check MIN_WITHDRAWAL_AMOUNT
  // - check RECIPIENT
611
  L1FeeVault: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
612 613
    const L1FeeVault = await hre.ethers.getContractAt(
      'L1FeeVault',
614 615
      predeploys.L1FeeVault,
      signer
616 617
    )

618
    await assertSemver(L1FeeVault, 'L1FeeVault')
619 620 621 622 623

    const MIN_WITHDRAWAL_AMOUNT = await L1FeeVault.MIN_WITHDRAWAL_AMOUNT()
    console.log(`  - MIN_WITHDRAWAL_AMOUNT: ${MIN_WITHDRAWAL_AMOUNT}`)

    const RECIPIENT = await L1FeeVault.RECIPIENT()
624 625
    assert(RECIPIENT !== hre.ethers.constants.AddressZero)
    yell(`  - RECIPIENT: ${RECIPIENT}`)
626

627 628
    await checkProxy(hre, 'L1FeeVault', signer.provider)
    await assertProxy(hre, 'L1FeeVault', signer.provider)
629 630 631
  },
  // L2ToL1MessagePasser
  // - check version
632 633 634 635
  L2ToL1MessagePasser: async (
    hre: HardhatRuntimeEnvironment,
    signer: Signer
  ) => {
636 637
    const L2ToL1MessagePasser = await hre.ethers.getContractAt(
      'L2ToL1MessagePasser',
638 639
      predeploys.L2ToL1MessagePasser,
      signer
640 641
    )

642
    await assertSemver(L2ToL1MessagePasser, 'L2ToL1MessagePasser')
643 644 645 646 647 648 649

    const MESSAGE_VERSION = await L2ToL1MessagePasser.MESSAGE_VERSION()
    console.log(`  - MESSAGE_VERSION: ${MESSAGE_VERSION}`)

    const messageNonce = await L2ToL1MessagePasser.messageNonce()
    console.log(`  - messageNonce: ${messageNonce}`)

650 651
    await checkProxy(hre, 'L2ToL1MessagePasser', signer.provider)
    await assertProxy(hre, 'L2ToL1MessagePasser', signer.provider)
652 653 654
  },
}

655
task('check-l2', 'Checks a freshly migrated L2 system for correct migration')
656 657
  .addOptionalParam('l1RpcUrl', 'L1 RPC URL of node', '', types.string)
  .addOptionalParam('l2RpcUrl', 'L2 RPC URL of node', '', types.string)
658
  .addOptionalParam('chainId', 'Expected chain id', 0, types.int)
659 660 661 662 663 664
  .addOptionalParam(
    'l2OutputOracleAddress',
    'Address of the L2OutputOracle oracle',
    '',
    types.string
  )
665 666 667 668 669 670 671 672 673 674 675 676
  .addOptionalParam(
    'skipPredeployCheck',
    'Skip long check',
    false,
    types.boolean
  )
  .setAction(async (args, hre: HardhatRuntimeEnvironment) => {
    yell('Manually check values wrapped in !!!!')
    console.log()

    let signer: Signer = hre.ethers.provider.getSigner()

677
    if (args.l2RpcUrl !== '') {
678
      console.log('Using CLI URL for provider instead of hardhat network')
679
      const provider = new hre.ethers.providers.JsonRpcProvider(args.l2RpcUrl)
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
      signer = Wallet.createRandom().connect(provider)
    }

    if (args.chainId !== 0) {
      const chainId = await signer.getChainId()
      if (chainId !== args.chainId) {
        throw new Error(
          `Unexpected Chain ID. Got ${chainId}, expected ${args.chainId}`
        )
      }
      console.log(`Verified Chain ID: ${chainId}`)
    } else {
      console.log(`Skipping Chain ID validation...`)
    }

    // Ensure that all the predeploys exist, including the not
    // currently configured ones
    if (!args.skipPredeployCheck) {
      await checkPredeploys(hre, signer.provider)
    }

701
    await checkGenesisMagic(hre, signer.provider, args)
702

703 704 705 706 707 708 709 710
    console.log()
    // Check the currently configured predeploys
    for (const [name, fn] of Object.entries(check)) {
      const address = predeploys[name]
      console.log(`${name}: ${address}`)
      await fn(hre, signer)
    }
  })