github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/scripts/ChainAssertions.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity ^0.8.0;
     3  
     4  import { ProxyAdmin } from "src/universal/ProxyAdmin.sol";
     5  import { ResourceMetering } from "src/L1/ResourceMetering.sol";
     6  import { DeployConfig } from "scripts/DeployConfig.s.sol";
     7  import { Deployer } from "scripts/Deployer.sol";
     8  import { SystemConfig } from "src/L1/SystemConfig.sol";
     9  import { Constants } from "src/libraries/Constants.sol";
    10  import { L1StandardBridge } from "src/L1/L1StandardBridge.sol";
    11  import { L2OutputOracle } from "src/L1/L2OutputOracle.sol";
    12  import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
    13  import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol";
    14  import { ProtocolVersion, ProtocolVersions } from "src/L1/ProtocolVersions.sol";
    15  import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
    16  import { OptimismPortal } from "src/L1/OptimismPortal.sol";
    17  import { OptimismPortal2 } from "src/L1/OptimismPortal2.sol";
    18  import { L1CrossDomainMessenger } from "src/L1/L1CrossDomainMessenger.sol";
    19  import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC20Factory.sol";
    20  import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
    21  import { Predeploys } from "src/libraries/Predeploys.sol";
    22  import { Types } from "scripts/Types.sol";
    23  import { Vm } from "forge-std/Vm.sol";
    24  import { ISystemConfigV0 } from "scripts/interfaces/ISystemConfigV0.sol";
    25  import { console2 as console } from "forge-std/console2.sol";
    26  
    27  library ChainAssertions {
    28      Vm internal constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
    29  
    30      /// @notice Asserts the correctness of an L1 deployment. This function expects that all contracts
    31      ///         within the `prox` ContractSet are proxies that have been setup and initialized.
    32      function postDeployAssertions(
    33          Types.ContractSet memory _prox,
    34          DeployConfig _cfg,
    35          uint256 _l2OutputOracleStartingTimestamp,
    36          Vm _vm
    37      )
    38          internal
    39          view
    40      {
    41          console.log("Running post-deploy assertions");
    42          ResourceMetering.ResourceConfig memory rcfg = SystemConfig(_prox.SystemConfig).resourceConfig();
    43          ResourceMetering.ResourceConfig memory dflt = Constants.DEFAULT_RESOURCE_CONFIG();
    44          require(keccak256(abi.encode(rcfg)) == keccak256(abi.encode(dflt)));
    45  
    46          checkSystemConfig({ _contracts: _prox, _cfg: _cfg, _isProxy: true });
    47          checkL1CrossDomainMessenger({ _contracts: _prox, _vm: _vm, _isProxy: true });
    48          checkL1StandardBridge({ _contracts: _prox, _isProxy: true });
    49          checkL2OutputOracle({
    50              _contracts: _prox,
    51              _cfg: _cfg,
    52              _l2OutputOracleStartingTimestamp: _l2OutputOracleStartingTimestamp,
    53              _isProxy: true
    54          });
    55          checkOptimismMintableERC20Factory({ _contracts: _prox, _isProxy: true });
    56          checkL1ERC721Bridge({ _contracts: _prox, _isProxy: true });
    57          checkOptimismPortal({ _contracts: _prox, _cfg: _cfg, _isProxy: true });
    58          checkOptimismPortal2({ _contracts: _prox, _cfg: _cfg, _isProxy: true });
    59          checkProtocolVersions({ _contracts: _prox, _cfg: _cfg, _isProxy: true });
    60      }
    61  
    62      /// @notice Asserts that the SystemConfig is setup correctly
    63      function checkSystemConfig(Types.ContractSet memory _contracts, DeployConfig _cfg, bool _isProxy) internal view {
    64          console.log("Running chain assertions on the SystemConfig");
    65          SystemConfig config = SystemConfig(_contracts.SystemConfig);
    66  
    67          // Check that the contract is initialized
    68          assertSlotValueIsOne({ _contractAddress: address(config), _slot: 0, _offset: 0 });
    69  
    70          ResourceMetering.ResourceConfig memory resourceConfig = config.resourceConfig();
    71  
    72          if (_isProxy) {
    73              require(config.owner() == _cfg.finalSystemOwner());
    74              require(config.overhead() == _cfg.gasPriceOracleOverhead());
    75              require(config.scalar() == _cfg.gasPriceOracleScalar());
    76              require(config.batcherHash() == bytes32(uint256(uint160(_cfg.batchSenderAddress()))));
    77              require(config.gasLimit() == uint64(_cfg.l2GenesisBlockGasLimit()));
    78              require(config.unsafeBlockSigner() == _cfg.p2pSequencerAddress());
    79              // Check _config
    80              ResourceMetering.ResourceConfig memory rconfig = Constants.DEFAULT_RESOURCE_CONFIG();
    81              require(resourceConfig.maxResourceLimit == rconfig.maxResourceLimit);
    82              require(resourceConfig.elasticityMultiplier == rconfig.elasticityMultiplier);
    83              require(resourceConfig.baseFeeMaxChangeDenominator == rconfig.baseFeeMaxChangeDenominator);
    84              require(resourceConfig.systemTxMaxGas == rconfig.systemTxMaxGas);
    85              require(resourceConfig.minimumBaseFee == rconfig.minimumBaseFee);
    86              require(resourceConfig.maximumBaseFee == rconfig.maximumBaseFee);
    87              // Depends on start block being set to 0 in `initialize`
    88              uint256 cfgStartBlock = _cfg.systemConfigStartBlock();
    89              require(config.startBlock() == (cfgStartBlock == 0 ? block.number : cfgStartBlock));
    90              require(config.batchInbox() == _cfg.batchInboxAddress());
    91              // Check _addresses
    92              require(config.l1CrossDomainMessenger() == _contracts.L1CrossDomainMessenger);
    93              require(config.l1ERC721Bridge() == _contracts.L1ERC721Bridge);
    94              require(config.l1StandardBridge() == _contracts.L1StandardBridge);
    95              require(config.l2OutputOracle() == _contracts.L2OutputOracle);
    96              require(config.optimismPortal() == _contracts.OptimismPortal);
    97              require(config.optimismMintableERC20Factory() == _contracts.OptimismMintableERC20Factory);
    98          } else {
    99              require(config.owner() == address(0xdead));
   100              require(config.overhead() == 0);
   101              require(config.scalar() == 0);
   102              require(config.batcherHash() == bytes32(0));
   103              require(config.gasLimit() == 1);
   104              require(config.unsafeBlockSigner() == address(0));
   105              // Check _config
   106              require(resourceConfig.maxResourceLimit == 1);
   107              require(resourceConfig.elasticityMultiplier == 1);
   108              require(resourceConfig.baseFeeMaxChangeDenominator == 2);
   109              require(resourceConfig.systemTxMaxGas == 0);
   110              require(resourceConfig.minimumBaseFee == 0);
   111              require(resourceConfig.maximumBaseFee == 0);
   112              // Check _addresses
   113              require(config.startBlock() == type(uint256).max);
   114              require(config.batchInbox() == address(0));
   115              require(config.l1CrossDomainMessenger() == address(0));
   116              require(config.l1ERC721Bridge() == address(0));
   117              require(config.l1StandardBridge() == address(0));
   118              require(config.l2OutputOracle() == address(0));
   119              require(config.optimismPortal() == address(0));
   120              require(config.optimismMintableERC20Factory() == address(0));
   121          }
   122      }
   123  
   124      /// @notice Asserts that the L1CrossDomainMessenger is setup correctly
   125      function checkL1CrossDomainMessenger(Types.ContractSet memory _contracts, Vm _vm, bool _isProxy) internal view {
   126          console.log("Running chain assertions on the L1CrossDomainMessenger");
   127          L1CrossDomainMessenger messenger = L1CrossDomainMessenger(_contracts.L1CrossDomainMessenger);
   128  
   129          // Check that the contract is initialized
   130          assertSlotValueIsOne({ _contractAddress: address(messenger), _slot: 0, _offset: 20 });
   131  
   132          require(address(messenger.OTHER_MESSENGER()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER);
   133          require(address(messenger.otherMessenger()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER);
   134  
   135          if (_isProxy) {
   136              require(address(messenger.PORTAL()) == _contracts.OptimismPortal);
   137              require(address(messenger.portal()) == _contracts.OptimismPortal);
   138              require(address(messenger.superchainConfig()) == _contracts.SuperchainConfig);
   139              bytes32 xdmSenderSlot = _vm.load(address(messenger), bytes32(uint256(204)));
   140              require(address(uint160(uint256(xdmSenderSlot))) == Constants.DEFAULT_L2_SENDER);
   141          } else {
   142              require(address(messenger.PORTAL()) == address(0));
   143              require(address(messenger.portal()) == address(0));
   144              require(address(messenger.superchainConfig()) == address(0));
   145          }
   146      }
   147  
   148      /// @notice Asserts that the L1StandardBridge is setup correctly
   149      function checkL1StandardBridge(Types.ContractSet memory _contracts, bool _isProxy) internal view {
   150          console.log("Running chain assertions on the L1StandardBridge");
   151          L1StandardBridge bridge = L1StandardBridge(payable(_contracts.L1StandardBridge));
   152  
   153          // Check that the contract is initialized
   154          assertSlotValueIsOne({ _contractAddress: address(bridge), _slot: 0, _offset: 0 });
   155  
   156          if (_isProxy) {
   157              require(address(bridge.MESSENGER()) == _contracts.L1CrossDomainMessenger);
   158              require(address(bridge.messenger()) == _contracts.L1CrossDomainMessenger);
   159              require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_STANDARD_BRIDGE);
   160              require(address(bridge.otherBridge()) == Predeploys.L2_STANDARD_BRIDGE);
   161              require(address(bridge.superchainConfig()) == _contracts.SuperchainConfig);
   162          } else {
   163              require(address(bridge.MESSENGER()) == address(0));
   164              require(address(bridge.messenger()) == address(0));
   165              require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_STANDARD_BRIDGE);
   166              require(address(bridge.otherBridge()) == Predeploys.L2_STANDARD_BRIDGE);
   167              require(address(bridge.superchainConfig()) == address(0));
   168          }
   169      }
   170  
   171      /// @notice Asserts that the DisputeGameFactory is setup correctly
   172      function checkDisputeGameFactory(Types.ContractSet memory _contracts, address _expectedOwner) internal view {
   173          console.log("Running chain assertions on the DisputeGameFactory");
   174          DisputeGameFactory factory = DisputeGameFactory(_contracts.DisputeGameFactory);
   175  
   176          // Check that the contract is initialized
   177          assertSlotValueIsOne({ _contractAddress: address(factory), _slot: 0, _offset: 0 });
   178  
   179          require(factory.owner() == _expectedOwner);
   180      }
   181  
   182      /// @notice Asserts that the DelayedWETH is setup correctly
   183      function checkDelayedWETH(
   184          Types.ContractSet memory _contracts,
   185          DeployConfig _cfg,
   186          bool _isProxy,
   187          address _expectedOwner
   188      )
   189          internal
   190          view
   191      {
   192          console.log("Running chain assertions on the DelayedWETH");
   193          DelayedWETH weth = DelayedWETH(payable(_contracts.DelayedWETH));
   194  
   195          // Check that the contract is initialized
   196          assertSlotValueIsOne({ _contractAddress: address(weth), _slot: 0, _offset: 0 });
   197  
   198          if (_isProxy) {
   199              require(weth.owner() == _expectedOwner);
   200              require(weth.delay() == _cfg.faultGameWithdrawalDelay());
   201              require(weth.config() == SuperchainConfig(_contracts.SuperchainConfig));
   202          } else {
   203              require(weth.owner() == _expectedOwner);
   204              require(weth.delay() == _cfg.faultGameWithdrawalDelay());
   205          }
   206      }
   207  
   208      /// @notice Asserts that the L2OutputOracle is setup correctly
   209      function checkL2OutputOracle(
   210          Types.ContractSet memory _contracts,
   211          DeployConfig _cfg,
   212          uint256 _l2OutputOracleStartingTimestamp,
   213          bool _isProxy
   214      )
   215          internal
   216          view
   217      {
   218          console.log("Running chain assertions on the L2OutputOracle");
   219          L2OutputOracle oracle = L2OutputOracle(_contracts.L2OutputOracle);
   220  
   221          // Check that the contract is initialized
   222          assertSlotValueIsOne({ _contractAddress: address(oracle), _slot: 0, _offset: 0 });
   223  
   224          if (_isProxy) {
   225              require(oracle.SUBMISSION_INTERVAL() == _cfg.l2OutputOracleSubmissionInterval());
   226              require(oracle.submissionInterval() == _cfg.l2OutputOracleSubmissionInterval());
   227              require(oracle.L2_BLOCK_TIME() == _cfg.l2BlockTime());
   228              require(oracle.l2BlockTime() == _cfg.l2BlockTime());
   229              require(oracle.PROPOSER() == _cfg.l2OutputOracleProposer());
   230              require(oracle.proposer() == _cfg.l2OutputOracleProposer());
   231              require(oracle.CHALLENGER() == _cfg.l2OutputOracleChallenger());
   232              require(oracle.challenger() == _cfg.l2OutputOracleChallenger());
   233              require(oracle.FINALIZATION_PERIOD_SECONDS() == _cfg.finalizationPeriodSeconds());
   234              require(oracle.finalizationPeriodSeconds() == _cfg.finalizationPeriodSeconds());
   235              require(oracle.startingBlockNumber() == _cfg.l2OutputOracleStartingBlockNumber());
   236              require(oracle.startingTimestamp() == _l2OutputOracleStartingTimestamp);
   237          } else {
   238              require(oracle.SUBMISSION_INTERVAL() == 1);
   239              require(oracle.submissionInterval() == 1);
   240              require(oracle.L2_BLOCK_TIME() == 1);
   241              require(oracle.l2BlockTime() == 1);
   242              require(oracle.PROPOSER() == address(0));
   243              require(oracle.proposer() == address(0));
   244              require(oracle.CHALLENGER() == address(0));
   245              require(oracle.challenger() == address(0));
   246              require(oracle.FINALIZATION_PERIOD_SECONDS() == 0);
   247              require(oracle.finalizationPeriodSeconds() == 0);
   248              require(oracle.startingBlockNumber() == 0);
   249              require(oracle.startingTimestamp() == 0);
   250          }
   251      }
   252  
   253      /// @notice Asserts that the OptimismMintableERC20Factory is setup correctly
   254      function checkOptimismMintableERC20Factory(Types.ContractSet memory _contracts, bool _isProxy) internal view {
   255          console.log("Running chain assertions on the OptimismMintableERC20Factory");
   256          OptimismMintableERC20Factory factory = OptimismMintableERC20Factory(_contracts.OptimismMintableERC20Factory);
   257  
   258          // Check that the contract is initialized
   259          assertSlotValueIsOne({ _contractAddress: address(factory), _slot: 0, _offset: 0 });
   260  
   261          if (_isProxy) {
   262              require(factory.BRIDGE() == _contracts.L1StandardBridge);
   263              require(factory.bridge() == _contracts.L1StandardBridge);
   264          } else {
   265              require(factory.BRIDGE() == address(0));
   266              require(factory.bridge() == address(0));
   267          }
   268      }
   269  
   270      /// @notice Asserts that the L1ERC721Bridge is setup correctly
   271      function checkL1ERC721Bridge(Types.ContractSet memory _contracts, bool _isProxy) internal view {
   272          console.log("Running chain assertions on the L1ERC721Bridge");
   273          L1ERC721Bridge bridge = L1ERC721Bridge(_contracts.L1ERC721Bridge);
   274  
   275          // Check that the contract is initialized
   276          assertSlotValueIsOne({ _contractAddress: address(bridge), _slot: 0, _offset: 0 });
   277  
   278          require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE);
   279          require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE);
   280  
   281          if (_isProxy) {
   282              require(address(bridge.MESSENGER()) == _contracts.L1CrossDomainMessenger);
   283              require(address(bridge.messenger()) == _contracts.L1CrossDomainMessenger);
   284              require(address(bridge.superchainConfig()) == _contracts.SuperchainConfig);
   285          } else {
   286              require(address(bridge.MESSENGER()) == address(0));
   287              require(address(bridge.messenger()) == address(0));
   288              require(address(bridge.superchainConfig()) == address(0));
   289          }
   290      }
   291  
   292      /// @notice Asserts the OptimismPortal is setup correctly
   293      function checkOptimismPortal(Types.ContractSet memory _contracts, DeployConfig _cfg, bool _isProxy) internal view {
   294          console.log("Running chain assertions on the OptimismPortal");
   295  
   296          OptimismPortal portal = OptimismPortal(payable(_contracts.OptimismPortal));
   297  
   298          // Check that the contract is initialized
   299          assertSlotValueIsOne({ _contractAddress: address(portal), _slot: 0, _offset: 0 });
   300  
   301          address guardian = _cfg.superchainConfigGuardian();
   302          if (guardian.code.length == 0) {
   303              console.log("Guardian has no code: %s", guardian);
   304          }
   305  
   306          if (_isProxy) {
   307              require(address(portal.L2_ORACLE()) == _contracts.L2OutputOracle);
   308              require(address(portal.l2Oracle()) == _contracts.L2OutputOracle);
   309              require(address(portal.SYSTEM_CONFIG()) == _contracts.SystemConfig);
   310              require(address(portal.systemConfig()) == _contracts.SystemConfig);
   311              require(portal.GUARDIAN() == guardian);
   312              require(portal.guardian() == guardian);
   313              require(address(portal.superchainConfig()) == address(_contracts.SuperchainConfig));
   314              require(portal.paused() == SuperchainConfig(_contracts.SuperchainConfig).paused());
   315              require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER);
   316          } else {
   317              require(address(portal.L2_ORACLE()) == address(0));
   318              require(address(portal.l2Oracle()) == address(0));
   319              require(address(portal.SYSTEM_CONFIG()) == address(0));
   320              require(address(portal.systemConfig()) == address(0));
   321              require(address(portal.superchainConfig()) == address(0));
   322              require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER);
   323          }
   324      }
   325  
   326      /// @notice Asserts the OptimismPortal2 is setup correctly
   327      function checkOptimismPortal2(
   328          Types.ContractSet memory _contracts,
   329          DeployConfig _cfg,
   330          bool _isProxy
   331      )
   332          internal
   333          view
   334      {
   335          console.log("Running chain assertions on the OptimismPortal2");
   336  
   337          OptimismPortal2 portal = OptimismPortal2(payable(_contracts.OptimismPortal2));
   338  
   339          // Check that the contract is initialized
   340          assertSlotValueIsOne({ _contractAddress: address(portal), _slot: 0, _offset: 0 });
   341  
   342          address guardian = _cfg.superchainConfigGuardian();
   343          if (guardian.code.length == 0) {
   344              console.log("Guardian has no code: %s", guardian);
   345          }
   346  
   347          if (_isProxy) {
   348              require(address(portal.disputeGameFactory()) == _contracts.DisputeGameFactory);
   349              require(address(portal.SYSTEM_CONFIG()) == _contracts.SystemConfig);
   350              require(address(portal.systemConfig()) == _contracts.SystemConfig);
   351              require(portal.GUARDIAN() == guardian);
   352              require(portal.guardian() == guardian);
   353              require(address(portal.superchainConfig()) == address(_contracts.SuperchainConfig));
   354              require(portal.paused() == SuperchainConfig(_contracts.SuperchainConfig).paused());
   355              require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER);
   356          } else {
   357              require(address(portal.disputeGameFactory()) == address(0));
   358              require(address(portal.SYSTEM_CONFIG()) == address(0));
   359              require(address(portal.systemConfig()) == address(0));
   360              require(address(portal.superchainConfig()) == address(0));
   361              require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER);
   362          }
   363      }
   364  
   365      /// @notice Asserts that the ProtocolVersions is setup correctly
   366      function checkProtocolVersions(
   367          Types.ContractSet memory _contracts,
   368          DeployConfig _cfg,
   369          bool _isProxy
   370      )
   371          internal
   372          view
   373      {
   374          console.log("Running chain assertions on the ProtocolVersions");
   375          ProtocolVersions versions = ProtocolVersions(_contracts.ProtocolVersions);
   376  
   377          // Check that the contract is initialized
   378          assertSlotValueIsOne({ _contractAddress: address(versions), _slot: 0, _offset: 0 });
   379  
   380          if (_isProxy) {
   381              require(versions.owner() == _cfg.finalSystemOwner());
   382              require(ProtocolVersion.unwrap(versions.required()) == _cfg.requiredProtocolVersion());
   383              require(ProtocolVersion.unwrap(versions.recommended()) == _cfg.recommendedProtocolVersion());
   384          } else {
   385              require(versions.owner() == address(0xdead));
   386              require(ProtocolVersion.unwrap(versions.required()) == 0);
   387              require(ProtocolVersion.unwrap(versions.recommended()) == 0);
   388          }
   389      }
   390  
   391      /// @notice Asserts that the SuperchainConfig is setup correctly
   392      function checkSuperchainConfig(
   393          Types.ContractSet memory _contracts,
   394          DeployConfig _cfg,
   395          bool _isPaused
   396      )
   397          internal
   398          view
   399      {
   400          console.log("Running chain assertions on the SuperchainConfig");
   401          SuperchainConfig superchainConfig = SuperchainConfig(_contracts.SuperchainConfig);
   402  
   403          // Check that the contract is initialized
   404          assertSlotValueIsOne({ _contractAddress: address(superchainConfig), _slot: 0, _offset: 0 });
   405  
   406          require(superchainConfig.guardian() == _cfg.superchainConfigGuardian());
   407          require(superchainConfig.paused() == _isPaused);
   408      }
   409  
   410      /// @dev Asserts that for a given contract the value of a storage slot at an offset is 1.
   411      function assertSlotValueIsOne(address _contractAddress, uint256 _slot, uint256 _offset) internal view {
   412          bytes32 slotVal = vm.load(_contractAddress, bytes32(_slot));
   413          require(
   414              uint8((uint256(slotVal) >> (_offset * 8)) & 0xFF) == uint8(1),
   415              "Storage value is not 1 at the given slot and offset"
   416          );
   417      }
   418  }