UNPKG

@hyperlane-xyz/core

Version:

Core solidity contracts for Hyperlane

287 lines (268 loc) 10.2 kB
'use strict' import { ethers } from 'ethers' import { task } from 'hardhat/config' import * as types from 'hardhat/internal/core/params/argumentTypes' import { hexStringEquals } from '@eth-optimism/core-utils' import { getContractFactory, getContractDefinition } from '../src/contract-defs' import { names } from '../src/address-names' import { getInput, color as c, getArtifactFromManagedName, getEtherscanUrl, printSectionHead, printComparison, } from '../src/validation-utils' task('validate:address-dictator') .addParam( 'dictator', 'Address of the AddressDictator to validate.', undefined, types.string ) .addParam( 'manager', 'Address of the Address Manager contract which would be updated by the Dictator.', undefined, types.string ) .addParam( 'multisig', 'Address of the multisig contract which should be the final owner', undefined, types.string ) .addOptionalParam( 'contractsRpcUrl', 'RPC Endpoint to query for data', process.env.CONTRACTS_RPC_URL, types.string ) .setAction(async (args) => { if (!args.contractsRpcUrl) { throw new Error( c.red('RPC URL must be set in your env, or passed as an argument.') ) } const provider = new ethers.providers.JsonRpcProvider(args.contractsRpcUrl) const network = await provider.getNetwork() console.log() printSectionHead("First make sure you're on the right chain:") console.log( `Reading from the ${c.red(network.name)} network (Chain ID: ${c.red( '' + network.chainId )})` ) await getInput(c.yellow('OK? Hit enter to continue.')) const dictatorArtifact = getContractDefinition('AddressDictator') const dictatorCode = await provider.getCode(args.dictator) printSectionHead(` Validate the Address Dictator deployment at\n${getEtherscanUrl( network, args.dictator )}`) printComparison( 'Comparing deployed AddressDictator bytecode against local build artifacts', 'Deployed AddressDictator code', { name: 'Compiled bytecode', value: dictatorArtifact.deployedBytecode }, { name: 'Deployed bytecode', value: dictatorCode } ) // Connect to the deployed AddressDictator. const dictatorContract = getContractFactory('AddressDictator') .attach(args.dictator) .connect(provider) const finalOwner = await dictatorContract.finalOwner() printComparison( 'Comparing the finalOwner address in the AddressDictator to the multisig address', 'finalOwner', { name: 'multisig address', value: args.multisig }, { name: 'finalOwner ', value: finalOwner } ) const deployedManager = await dictatorContract.manager() printComparison( 'Validating the AddressManager address in the AddressDictator', 'addressManager', { name: 'manager ', value: args.manager }, { name: 'Address Manager', value: deployedManager } ) await getInput(c.yellow('OK? Hit enter to continue.')) // Get names and addresses from the Dictator. const namedAddresses = await dictatorContract.getNamedAddresses() // In order to reduce noise for the user, we query the AddressManager identify addresses that // will not be changed, and skip over them in this block. const managerContract = getContractFactory('Lib_AddressManager') .attach(args.manager) .connect(provider) // Now we loop over those and compare the addresses/deployedBytecode to deployment artifacts. for (const pair of namedAddresses) { if (pair.name === 'L2CrossDomainMessenger') { console.log('L2CrossDomainMessenger is set to:', pair.addr) await getInput(c.yellow('OK? Hit enter to continue.')) // This is an L2 predeploy, so we skip bytecode and config validation. continue } const currentAddress = await managerContract.getAddress(pair.name) const artifact = getArtifactFromManagedName(pair.name) const addressChanged = !hexStringEquals(currentAddress, pair.addr) if (addressChanged) { printSectionHead( `Validate the ${pair.name} deployment. Current address: ${getEtherscanUrl(network, currentAddress)} Upgraded address ${getEtherscanUrl(network, pair.addr)}` ) const code = await provider.getCode(pair.addr) printComparison( `Verifying ${pair.name} source code against local deployment artifacts`, `Deployed ${pair.name} code`, { name: 'artifact.deployedBytecode', value: artifact.deployedBytecode, }, { name: 'Deployed bytecode ', value: code } ) // Identify contracts which inherit from Lib_AddressResolver, and check that they // have the right manager address. if (Object.keys(artifact)) { if (artifact.abi.some((el) => el.name === 'libAddressManager')) { const libAddressManager = await getContractFactory( 'Lib_AddressResolver' ) .attach(pair.addr) .connect(provider) .libAddressManager() printComparison( `Verifying ${pair.name} has the correct AddressManager address`, `The AddressManager address in ${pair.name}`, { name: 'Deployed value', value: libAddressManager }, { name: 'Expected value', value: deployedManager } ) await getInput(c.yellow('OK? Hit enter to continue.')) } } } await validateDeployedConfig(provider, network, args.manager, pair) } console.log(c.green('\nAddressManager Validation complete!')) }) /** * Validates that the deployed contracts have the expected storage variables. * * @param {*} provider * @param {{ name: string; addr: string }} pair The contract name and address */ const validateDeployedConfig = async ( provider, network, manager, pair: { name: string; addr: string } ) => { printSectionHead(` Ensure that the ${pair.name} at\n${getEtherscanUrl( network, pair.addr )} is configured correctly`) if (pair.name === names.managed.contracts.StateCommitmentChain) { const scc = getContractFactory(pair.name) .attach(pair.addr) .connect(provider) // --scc-fraud-proof-window 604800 \ const fraudProofWindow = await scc.FRAUD_PROOF_WINDOW() printComparison( 'Checking the fraudProofWindow of the StateCommitmentChain', 'StateCommitmentChain.fraudProofWindow', { name: 'Configured fraudProofWindow', value: ethers.BigNumber.from(604_800).toHexString(), }, { name: 'Deployed fraudProofWindow ', value: ethers.BigNumber.from(fraudProofWindow).toHexString(), } ) await getInput(c.yellow('OK? Hit enter to continue.')) // --scc-sequencer-publish-window 12592000 \ const sequencerPublishWindow = await scc.SEQUENCER_PUBLISH_WINDOW() printComparison( 'Checking the sequencerPublishWindow of the StateCommitmentChain', 'StateCommitmentChain.sequencerPublishWindow', { name: 'Configured sequencerPublishWindow ', value: ethers.BigNumber.from(12592000).toHexString(), }, { name: 'Deployed sequencerPublishWindow', value: ethers.BigNumber.from(sequencerPublishWindow).toHexString(), } ) await getInput(c.yellow('OK? Hit enter to continue.')) } else if (pair.name === names.managed.contracts.CanonicalTransactionChain) { const ctc = getContractFactory(pair.name) .attach(pair.addr) .connect(provider) // --ctc-max-transaction-gas-limit 15000000 \ const maxTransactionGasLimit = await ctc.maxTransactionGasLimit() printComparison( 'Checking the maxTransactionGasLimit of the CanonicalTransactionChain', 'CanonicalTransactionChain.maxTransactionGasLimit', { name: 'Configured maxTransactionGasLimit', value: ethers.BigNumber.from(15_000_000).toHexString(), }, { name: 'Deployed maxTransactionGasLimit ', value: ethers.BigNumber.from(maxTransactionGasLimit).toHexString(), } ) await getInput(c.yellow('OK? Hit enter to continue.')) // --ctc-l2-gas-discount-divisor 32 \ const l2GasDiscountDivisor = await ctc.l2GasDiscountDivisor() printComparison( 'Checking the l2GasDiscountDivisor of the CanonicalTransactionChain', 'CanonicalTransactionChain.l2GasDiscountDivisor', { name: 'Configured l2GasDiscountDivisor', value: ethers.BigNumber.from(32).toHexString(), }, { name: 'Deployed l2GasDiscountDivisor ', value: ethers.BigNumber.from(l2GasDiscountDivisor).toHexString(), } ) await getInput(c.yellow('OK? Hit enter to continue.')) // --ctc-enqueue-gas-cost 60000 \ const enqueueGasCost = await ctc.enqueueGasCost() printComparison( 'Checking the enqueueGasCost of the CanonicalTransactionChain', 'CanonicalTransactionChain.enqueueGasCost', { name: 'Configured enqueueGasCost', value: ethers.BigNumber.from(60000).toHexString(), }, { name: 'Deployed enqueueGasCost ', value: ethers.BigNumber.from(enqueueGasCost).toHexString(), } ) await getInput(c.yellow('OK? Hit enter to continue.')) } else if (pair.name === names.managed.contracts.OVM_L1CrossDomainMessenger) { const messengerManager = await getContractFactory('L1CrossDomainMessenger') .attach(pair.addr) .connect(provider) .libAddressManager() printComparison( 'Ensure that the L1CrossDomainMessenger (implementation) is initialized with a non-zero Address Manager variable', "L1CrossDomainMessenger's Lib_AddressManager", { name: 'Configured Lib_AddressManager', value: messengerManager, }, { name: 'Deployed Lib_AddressManager ', value: manager, } ) } else { console.log(c.green(`${pair.name} has no config to check`)) await getInput(c.yellow('OK? Hit enter to continue.')) } }