github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/Specs.t.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity ^0.8.15;
     3  
     4  import { CommonTest } from "test/setup/CommonTest.sol";
     5  import { Executables } from "scripts/Executables.sol";
     6  import { console2 as console } from "forge-std/console2.sol";
     7  import { ProtocolVersions } from "src/L1/ProtocolVersions.sol";
     8  import { OptimismPortal } from "src/L1/OptimismPortal.sol";
     9  import { OptimismPortal2 } from "src/L1/OptimismPortal2.sol";
    10  import { SystemConfig } from "src/L1/SystemConfig.sol";
    11  import { DataAvailabilityChallenge } from "src/L1/DataAvailabilityChallenge.sol";
    12  import { ForgeArtifacts } from "scripts/ForgeArtifacts.sol";
    13  
    14  /// @title Specification_Test
    15  /// @dev Specifies common security properties of entrypoints to L1 contracts, including authorization and
    16  ///      pausability.
    17  ///      When adding new functions to the L1 system, the `setUp` function must be updated to document the security
    18  ///      properties of the new function. The `Spec` struct reppresents this documentation. However, this contract does
    19  ///      not actually test to verify these properties, only that a spec is defined.
    20  contract Specification_Test is CommonTest {
    21      struct AbiEntry {
    22          string fnName;
    23          bytes4 sel;
    24      }
    25  
    26      struct Abi {
    27          string contractName;
    28          AbiEntry[] entries;
    29      }
    30  
    31      enum Role {
    32          NOAUTH,
    33          PROPOSER,
    34          CHALLENGER,
    35          SYSTEMCONFIGOWNER,
    36          GUARDIAN,
    37          MESSENGER,
    38          L1PROXYADMINOWNER,
    39          GOVERNANCETOKENOWNER,
    40          MINTMANAGEROWNER,
    41          DATAAVAILABILITYCHALLENGEOWNER
    42      }
    43  
    44      /// @notice Represents the specification of a function.
    45      /// @custom:field name     Contract name
    46      /// @custom:field sel      Function selector
    47      /// @custom:field auth     Specifies authentication as a requirement
    48      /// @custom:field pausable Specifies that the function is pausable
    49      struct Spec {
    50          string name;
    51          bytes4 sel;
    52          Role auth;
    53          bool pausable;
    54      }
    55  
    56      mapping(string => mapping(bytes4 => Spec)) specs;
    57      mapping(string => uint256) public numEntries;
    58  
    59      function setUp() public override {
    60          super.setUp();
    61  
    62          // DataAvailabilityChallenge
    63          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("owner()") });
    64          _addSpec({
    65              _name: "DataAvailabilityChallenge",
    66              _sel: _getSel("renounceOwnership()"),
    67              _auth: Role.DATAAVAILABILITYCHALLENGEOWNER
    68          });
    69          _addSpec({
    70              _name: "DataAvailabilityChallenge",
    71              _sel: _getSel("transferOwnership(address)"),
    72              _auth: Role.DATAAVAILABILITYCHALLENGEOWNER
    73          });
    74          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("version()") });
    75          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("fixedResolutionCost()") });
    76          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("variableResolutionCost()") });
    77          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("variableResolutionCostPrecision()") });
    78          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("bondSize()") });
    79          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("challengeWindow()") });
    80          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("resolveWindow()") });
    81          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("resolverRefundPercentage()") });
    82          _addSpec({ _name: "DataAvailabilityChallenge", _sel: _getSel("balances(address)") });
    83          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.initialize.selector });
    84          _addSpec({
    85              _name: "DataAvailabilityChallenge",
    86              _sel: DataAvailabilityChallenge.setBondSize.selector,
    87              _auth: Role.DATAAVAILABILITYCHALLENGEOWNER
    88          });
    89          _addSpec({
    90              _name: "DataAvailabilityChallenge",
    91              _sel: DataAvailabilityChallenge.setResolverRefundPercentage.selector,
    92              _auth: Role.DATAAVAILABILITYCHALLENGEOWNER
    93          });
    94          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.deposit.selector });
    95          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.withdraw.selector });
    96          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.getChallenge.selector });
    97          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.getChallengeStatus.selector });
    98          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.validateCommitment.selector });
    99          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.challenge.selector });
   100          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.resolve.selector });
   101          _addSpec({ _name: "DataAvailabilityChallenge", _sel: DataAvailabilityChallenge.unlockBond.selector });
   102  
   103          // DelayedVetoable
   104          _addSpec({ _name: "DelayedVetoable", _sel: _getSel("delay()") });
   105          _addSpec({ _name: "DelayedVetoable", _sel: _getSel("initiator()") });
   106          _addSpec({ _name: "DelayedVetoable", _sel: _getSel("queuedAt(bytes32)") });
   107          _addSpec({ _name: "DelayedVetoable", _sel: _getSel("target()") });
   108          _addSpec({ _name: "DelayedVetoable", _sel: _getSel("version()") });
   109          _addSpec({ _name: "DelayedVetoable", _sel: _getSel("vetoer()") });
   110  
   111          // L1CrossDomainMessenger
   112          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("MESSAGE_VERSION()") });
   113          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("MIN_GAS_CALLDATA_OVERHEAD()") });
   114          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR()") });
   115          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR()") });
   116          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("OTHER_MESSENGER()") });
   117          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("PORTAL()") });
   118          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("RELAY_CALL_OVERHEAD()") });
   119          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("RELAY_CONSTANT_OVERHEAD()") });
   120          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("RELAY_GAS_CHECK_BUFFER()") });
   121          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("RELAY_RESERVED_GAS()") });
   122          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("baseGas(bytes,uint32)") });
   123          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("failedMessages(bytes32)") });
   124          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("initialize(address,address)") });
   125          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("messageNonce()") });
   126          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("paused()") });
   127          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("otherMessenger()") });
   128          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("portal()") });
   129          _addSpec({
   130              _name: "L1CrossDomainMessenger",
   131              _sel: _getSel("relayMessage(uint256,address,address,uint256,uint256,bytes)"),
   132              _pausable: true
   133          });
   134          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("sendMessage(address,bytes,uint32)") });
   135          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("successfulMessages(bytes32)") });
   136          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("superchainConfig()") });
   137          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("version()") });
   138          _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("xDomainMessageSender()") });
   139  
   140          // L1ERC721Bridge
   141          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("MESSENGER()") });
   142          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("OTHER_BRIDGE()") });
   143          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("bridgeERC721(address,address,uint256,uint32,bytes)") });
   144          _addSpec({
   145              _name: "L1ERC721Bridge",
   146              _sel: _getSel("bridgeERC721To(address,address,address,uint256,uint32,bytes)")
   147          });
   148          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("deposits(address,address,uint256)") });
   149          _addSpec({
   150              _name: "L1ERC721Bridge",
   151              _sel: _getSel("finalizeBridgeERC721(address,address,address,address,uint256,bytes)"),
   152              _pausable: true
   153          });
   154          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("messenger()") });
   155          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("otherBridge()") });
   156          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("version()") });
   157          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("superchainConfig()") });
   158          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("paused()") });
   159          _addSpec({ _name: "L1ERC721Bridge", _sel: _getSel("initialize(address,address)") });
   160  
   161          // L1StandardBridge
   162          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("MESSENGER()") });
   163          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("OTHER_BRIDGE()") });
   164          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("bridgeERC20(address,address,uint256,uint32,bytes)") });
   165          _addSpec({
   166              _name: "L1StandardBridge",
   167              _sel: _getSel("bridgeERC20To(address,address,address,uint256,uint32,bytes)")
   168          });
   169          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("bridgeETH(uint32,bytes)") });
   170          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("bridgeETHTo(address,uint32,bytes)") });
   171          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("depositERC20(address,address,uint256,uint32,bytes)") });
   172          _addSpec({
   173              _name: "L1StandardBridge",
   174              _sel: _getSel("depositERC20To(address,address,address,uint256,uint32,bytes)")
   175          });
   176          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("depositETH(uint32,bytes)") });
   177          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("depositETHTo(address,uint32,bytes)") });
   178          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("deposits(address,address)") });
   179          _addSpec({
   180              _name: "L1StandardBridge",
   181              _sel: _getSel("finalizeBridgeERC20(address,address,address,address,uint256,bytes)"),
   182              _auth: Role.MESSENGER,
   183              _pausable: true
   184          });
   185          _addSpec({
   186              _name: "L1StandardBridge",
   187              _sel: _getSel("finalizeBridgeETH(address,address,uint256,bytes)"),
   188              _auth: Role.MESSENGER,
   189              _pausable: true
   190          });
   191          _addSpec({
   192              _name: "L1StandardBridge",
   193              _sel: _getSel("finalizeERC20Withdrawal(address,address,address,address,uint256,bytes)"),
   194              _auth: Role.MESSENGER,
   195              _pausable: true
   196          });
   197          _addSpec({
   198              _name: "L1StandardBridge",
   199              _sel: _getSel("finalizeETHWithdrawal(address,address,uint256,bytes)"),
   200              _auth: Role.MESSENGER,
   201              _pausable: true
   202          });
   203          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("initialize(address,address)") });
   204          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("l2TokenBridge()") });
   205          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("messenger()") });
   206          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("otherBridge()") });
   207          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("paused()") });
   208          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("superchainConfig()") });
   209          _addSpec({ _name: "L1StandardBridge", _sel: _getSel("version()") });
   210  
   211          // L2OutputOracle
   212          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("CHALLENGER()") });
   213          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("FINALIZATION_PERIOD_SECONDS()") });
   214          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("L2_BLOCK_TIME()") });
   215          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("PROPOSER()") });
   216          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("SUBMISSION_INTERVAL()") });
   217          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("challenger()") });
   218          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("computeL2Timestamp(uint256)") });
   219          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("deleteL2Outputs(uint256)"), _auth: Role.CHALLENGER });
   220          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("finalizationPeriodSeconds()") });
   221          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("getL2Output(uint256)") });
   222          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("getL2OutputAfter(uint256)") });
   223          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("getL2OutputIndexAfter(uint256)") });
   224          _addSpec({
   225              _name: "L2OutputOracle",
   226              _sel: _getSel("initialize(uint256,uint256,uint256,uint256,address,address,uint256)")
   227          });
   228          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("l2BlockTime()") });
   229          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("latestBlockNumber()") });
   230          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("latestOutputIndex()") });
   231          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("nextBlockNumber()") });
   232          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("nextOutputIndex()") });
   233          _addSpec({
   234              _name: "L2OutputOracle",
   235              _sel: _getSel("proposeL2Output(bytes32,uint256,bytes32,uint256)"),
   236              _auth: Role.PROPOSER
   237          });
   238          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("proposer()") });
   239          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("startingBlockNumber()") });
   240          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("startingTimestamp()") });
   241          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("submissionInterval()") });
   242          _addSpec({ _name: "L2OutputOracle", _sel: _getSel("version()") });
   243  
   244          // OptimismPortal
   245          _addSpec({ _name: "OptimismPortal", _sel: _getSel("GUARDIAN()") });
   246          _addSpec({ _name: "OptimismPortal", _sel: _getSel("L2_ORACLE()") });
   247          _addSpec({ _name: "OptimismPortal", _sel: _getSel("SYSTEM_CONFIG()") });
   248          _addSpec({ _name: "OptimismPortal", _sel: _getSel("depositTransaction(address,uint256,uint64,bool,bytes)") });
   249          _addSpec({ _name: "OptimismPortal", _sel: _getSel("donateETH()") });
   250          _addSpec({
   251              _name: "OptimismPortal",
   252              _sel: OptimismPortal.finalizeWithdrawalTransaction.selector,
   253              _pausable: true
   254          });
   255          _addSpec({ _name: "OptimismPortal", _sel: _getSel("finalizedWithdrawals(bytes32)") });
   256          _addSpec({ _name: "OptimismPortal", _sel: _getSel("guardian()") });
   257          _addSpec({ _name: "OptimismPortal", _sel: _getSel("initialize(address,address,address)") });
   258          _addSpec({ _name: "OptimismPortal", _sel: _getSel("isOutputFinalized(uint256)") });
   259          _addSpec({ _name: "OptimismPortal", _sel: _getSel("l2Oracle()") });
   260          _addSpec({ _name: "OptimismPortal", _sel: _getSel("l2Sender()") });
   261          _addSpec({ _name: "OptimismPortal", _sel: _getSel("minimumGasLimit(uint64)") });
   262          _addSpec({ _name: "OptimismPortal", _sel: _getSel("params()") });
   263          _addSpec({ _name: "OptimismPortal", _sel: _getSel("paused()") });
   264          _addSpec({ _name: "OptimismPortal", _sel: OptimismPortal.proveWithdrawalTransaction.selector, _pausable: true });
   265          _addSpec({ _name: "OptimismPortal", _sel: _getSel("provenWithdrawals(bytes32)") });
   266          _addSpec({ _name: "OptimismPortal", _sel: _getSel("superchainConfig()") });
   267          _addSpec({ _name: "OptimismPortal", _sel: _getSel("systemConfig()") });
   268          _addSpec({ _name: "OptimismPortal", _sel: _getSel("version()") });
   269  
   270          // OptimismPortal2
   271          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("GUARDIAN()") });
   272          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("SYSTEM_CONFIG()") });
   273          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("depositTransaction(address,uint256,uint64,bool,bytes)") });
   274          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("donateETH()") });
   275          _addSpec({
   276              _name: "OptimismPortal2",
   277              _sel: OptimismPortal2.finalizeWithdrawalTransaction.selector,
   278              _pausable: true
   279          });
   280          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("finalizedWithdrawals(bytes32)") });
   281          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("guardian()") });
   282          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("initialize(address,address,address)") });
   283          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("l2Sender()") });
   284          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("minimumGasLimit(uint64)") });
   285          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("params()") });
   286          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("paused()") });
   287          _addSpec({ _name: "OptimismPortal2", _sel: OptimismPortal2.proveWithdrawalTransaction.selector, _pausable: true });
   288          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("provenWithdrawals(bytes32)") });
   289          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("superchainConfig()") });
   290          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("systemConfig()") });
   291          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("version()") });
   292          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("disputeGameFactory()") });
   293          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("disputeGameBlacklist(address)") });
   294          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("respectedGameType()") });
   295          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("blacklistDisputeGame(address)"), _auth: Role.GUARDIAN });
   296          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("setRespectedGameType(uint32)"), _auth: Role.GUARDIAN });
   297          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("checkWithdrawal(bytes32)") });
   298          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("proofMaturityDelaySeconds()") });
   299          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("disputeGameFinalityDelaySeconds()") });
   300          _addSpec({ _name: "OptimismPortal2", _sel: _getSel("respectedGameTypeUpdatedAt()") });
   301  
   302          // ProtocolVersions
   303          _addSpec({ _name: "ProtocolVersions", _sel: _getSel("RECOMMENDED_SLOT()") });
   304          _addSpec({ _name: "ProtocolVersions", _sel: _getSel("REQUIRED_SLOT()") });
   305          _addSpec({ _name: "ProtocolVersions", _sel: _getSel("VERSION()") });
   306          _addSpec({ _name: "ProtocolVersions", _sel: ProtocolVersions.initialize.selector });
   307          _addSpec({ _name: "ProtocolVersions", _sel: _getSel("owner()") });
   308          _addSpec({ _name: "ProtocolVersions", _sel: ProtocolVersions.recommended.selector });
   309          _addSpec({ _name: "ProtocolVersions", _sel: _getSel("renounceOwnership()"), _auth: Role.SYSTEMCONFIGOWNER });
   310          _addSpec({ _name: "ProtocolVersions", _sel: ProtocolVersions.required.selector });
   311          _addSpec({
   312              _name: "ProtocolVersions",
   313              _sel: ProtocolVersions.setRequired.selector,
   314              _auth: Role.SYSTEMCONFIGOWNER
   315          });
   316          _addSpec({
   317              _name: "ProtocolVersions",
   318              _sel: ProtocolVersions.setRecommended.selector,
   319              _auth: Role.SYSTEMCONFIGOWNER
   320          });
   321          _addSpec({ _name: "ProtocolVersions", _sel: _getSel("transferOwnership(address)") });
   322          _addSpec({ _name: "ProtocolVersions", _sel: _getSel("version()") });
   323  
   324          // ResourceMetering
   325          _addSpec({ _name: "ResourceMetering", _sel: _getSel("params()") });
   326  
   327          // SuperchainConfig
   328          _addSpec({ _name: "SuperchainConfig", _sel: _getSel("GUARDIAN_SLOT()") });
   329          _addSpec({ _name: "SuperchainConfig", _sel: _getSel("PAUSED_SLOT()") });
   330          _addSpec({ _name: "SuperchainConfig", _sel: _getSel("guardian()") });
   331          _addSpec({ _name: "SuperchainConfig", _sel: _getSel("initialize(address,bool)") });
   332          _addSpec({ _name: "SuperchainConfig", _sel: _getSel("pause(string)"), _auth: Role.GUARDIAN });
   333          _addSpec({ _name: "SuperchainConfig", _sel: _getSel("paused()") });
   334          _addSpec({ _name: "SuperchainConfig", _sel: _getSel("unpause()"), _auth: Role.GUARDIAN });
   335          _addSpec({ _name: "SuperchainConfig", _sel: _getSel("version()") });
   336  
   337          // SystemConfig
   338          _addSpec({ _name: "SystemConfig", _sel: _getSel("UNSAFE_BLOCK_SIGNER_SLOT()") });
   339          _addSpec({ _name: "SystemConfig", _sel: _getSel("START_BLOCK_SLOT()") });
   340          _addSpec({ _name: "SystemConfig", _sel: _getSel("VERSION()") });
   341          _addSpec({ _name: "SystemConfig", _sel: _getSel("batcherHash()") });
   342          _addSpec({ _name: "SystemConfig", _sel: _getSel("gasLimit()") });
   343          _addSpec({ _name: "SystemConfig", _sel: SystemConfig.initialize.selector });
   344          _addSpec({ _name: "SystemConfig", _sel: SystemConfig.minimumGasLimit.selector });
   345          _addSpec({ _name: "SystemConfig", _sel: _getSel("overhead()") });
   346          _addSpec({ _name: "SystemConfig", _sel: _getSel("owner()") });
   347          _addSpec({ _name: "SystemConfig", _sel: _getSel("renounceOwnership()"), _auth: Role.SYSTEMCONFIGOWNER });
   348          _addSpec({ _name: "SystemConfig", _sel: SystemConfig.resourceConfig.selector });
   349          _addSpec({ _name: "SystemConfig", _sel: _getSel("scalar()") });
   350          _addSpec({ _name: "SystemConfig", _sel: SystemConfig.setBatcherHash.selector, _auth: Role.SYSTEMCONFIGOWNER });
   351          _addSpec({ _name: "SystemConfig", _sel: SystemConfig.setGasConfig.selector, _auth: Role.SYSTEMCONFIGOWNER });
   352          _addSpec({ _name: "SystemConfig", _sel: SystemConfig.setGasLimit.selector, _auth: Role.SYSTEMCONFIGOWNER });
   353          _addSpec({ _name: "SystemConfig", _sel: SystemConfig.setResourceConfig.selector, _auth: Role.SYSTEMCONFIGOWNER });
   354          _addSpec({
   355              _name: "SystemConfig",
   356              _sel: SystemConfig.setUnsafeBlockSigner.selector,
   357              _auth: Role.SYSTEMCONFIGOWNER
   358          });
   359          _addSpec({ _name: "SystemConfig", _sel: _getSel("transferOwnership(address)"), _auth: Role.SYSTEMCONFIGOWNER });
   360          _addSpec({ _name: "SystemConfig", _sel: SystemConfig.unsafeBlockSigner.selector });
   361          _addSpec({ _name: "SystemConfig", _sel: _getSel("version()") });
   362          _addSpec({ _name: "SystemConfig", _sel: _getSel("l1CrossDomainMessenger()") });
   363          _addSpec({ _name: "SystemConfig", _sel: _getSel("l1ERC721Bridge()") });
   364          _addSpec({ _name: "SystemConfig", _sel: _getSel("l1StandardBridge()") });
   365          _addSpec({ _name: "SystemConfig", _sel: _getSel("l2OutputOracle()") });
   366          _addSpec({ _name: "SystemConfig", _sel: _getSel("optimismPortal()") });
   367          _addSpec({ _name: "SystemConfig", _sel: _getSel("optimismMintableERC20Factory()") });
   368          _addSpec({ _name: "SystemConfig", _sel: _getSel("batchInbox()") });
   369          _addSpec({ _name: "SystemConfig", _sel: _getSel("startBlock()") });
   370          _addSpec({ _name: "SystemConfig", _sel: _getSel("L1_CROSS_DOMAIN_MESSENGER_SLOT()") });
   371          _addSpec({ _name: "SystemConfig", _sel: _getSel("L1_ERC_721_BRIDGE_SLOT()") });
   372          _addSpec({ _name: "SystemConfig", _sel: _getSel("L1_STANDARD_BRIDGE_SLOT()") });
   373          _addSpec({ _name: "SystemConfig", _sel: _getSel("L2_OUTPUT_ORACLE_SLOT()") });
   374          _addSpec({ _name: "SystemConfig", _sel: _getSel("OPTIMISM_PORTAL_SLOT()") });
   375          _addSpec({ _name: "SystemConfig", _sel: _getSel("OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT()") });
   376          _addSpec({ _name: "SystemConfig", _sel: _getSel("BATCH_INBOX_SLOT()") });
   377  
   378          // ProxyAdmin
   379          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("addressManager()") });
   380          _addSpec({
   381              _name: "ProxyAdmin",
   382              _sel: _getSel("changeProxyAdmin(address,address)"),
   383              _auth: Role.L1PROXYADMINOWNER
   384          });
   385          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("getProxyAdmin(address)") });
   386          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("getProxyImplementation(address)") });
   387          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("implementationName(address)") });
   388          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("isUpgrading()") });
   389          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("owner()") });
   390          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("proxyType(address)") });
   391          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("renounceOwnership()"), _auth: Role.L1PROXYADMINOWNER });
   392          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("setAddress(string,address)"), _auth: Role.L1PROXYADMINOWNER });
   393          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("setAddressManager(address)"), _auth: Role.L1PROXYADMINOWNER });
   394          _addSpec({
   395              _name: "ProxyAdmin",
   396              _sel: _getSel("setImplementationName(address,string)"),
   397              _auth: Role.L1PROXYADMINOWNER
   398          });
   399          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("setProxyType(address,uint8)"), _auth: Role.L1PROXYADMINOWNER });
   400          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("setUpgrading(bool)") });
   401          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("transferOwnership(address)"), _auth: Role.L1PROXYADMINOWNER });
   402          _addSpec({ _name: "ProxyAdmin", _sel: _getSel("upgrade(address,address)") });
   403          _addSpec({
   404              _name: "ProxyAdmin",
   405              _sel: _getSel("upgradeAndCall(address,address,bytes)"),
   406              _auth: Role.L1PROXYADMINOWNER
   407          });
   408  
   409          // GovernanceToken
   410          _addSpec({ _name: "GovernanceToken", _sel: _getSel("DOMAIN_SEPARATOR()") });
   411          _addSpec({ _name: "GovernanceToken", _sel: _getSel("allowance(address,address)") });
   412          _addSpec({ _name: "GovernanceToken", _sel: _getSel("approve(address,uint256)") });
   413          _addSpec({ _name: "GovernanceToken", _sel: _getSel("balanceOf(address)") });
   414          _addSpec({ _name: "GovernanceToken", _sel: _getSel("burn(uint256)") });
   415          _addSpec({ _name: "GovernanceToken", _sel: _getSel("burnFrom(address,uint256)") });
   416          _addSpec({ _name: "GovernanceToken", _sel: _getSel("checkpoints(address,uint32)") });
   417          _addSpec({ _name: "GovernanceToken", _sel: _getSel("decimals()") });
   418          _addSpec({ _name: "GovernanceToken", _sel: _getSel("decreaseAllowance(address,uint256)") });
   419          _addSpec({ _name: "GovernanceToken", _sel: _getSel("delegate(address)") });
   420          _addSpec({
   421              _name: "GovernanceToken",
   422              _sel: _getSel("delegateBySig(address,uint256,uint256,uint8,bytes32,bytes32)")
   423          });
   424          _addSpec({ _name: "GovernanceToken", _sel: _getSel("delegates(address)") });
   425          _addSpec({ _name: "GovernanceToken", _sel: _getSel("getPastTotalSupply(uint256)") });
   426          _addSpec({ _name: "GovernanceToken", _sel: _getSel("getPastVotes(address,uint256)") });
   427          _addSpec({ _name: "GovernanceToken", _sel: _getSel("getVotes(address)") });
   428          _addSpec({ _name: "GovernanceToken", _sel: _getSel("increaseAllowance(address,uint256)") });
   429          _addSpec({ _name: "GovernanceToken", _sel: _getSel("mint(address,uint256)"), _auth: Role.GOVERNANCETOKENOWNER });
   430          _addSpec({ _name: "GovernanceToken", _sel: _getSel("name()") });
   431          _addSpec({ _name: "GovernanceToken", _sel: _getSel("nonces(address)") });
   432          _addSpec({ _name: "GovernanceToken", _sel: _getSel("numCheckpoints(address)") });
   433          _addSpec({ _name: "GovernanceToken", _sel: _getSel("owner()") });
   434          _addSpec({
   435              _name: "GovernanceToken",
   436              _sel: _getSel("permit(address,address,uint256,uint256,uint8,bytes32,bytes32)")
   437          });
   438          _addSpec({ _name: "GovernanceToken", _sel: _getSel("renounceOwnership()") });
   439          _addSpec({ _name: "GovernanceToken", _sel: _getSel("symbol()") });
   440          _addSpec({ _name: "GovernanceToken", _sel: _getSel("totalSupply()") });
   441          _addSpec({ _name: "GovernanceToken", _sel: _getSel("transfer(address,uint256)") });
   442          _addSpec({ _name: "GovernanceToken", _sel: _getSel("transferFrom(address,address,uint256)") });
   443          _addSpec({ _name: "GovernanceToken", _sel: _getSel("transferOwnership(address)") });
   444  
   445          // MintManager
   446          _addSpec({ _name: "MintManager", _sel: _getSel("DENOMINATOR()") });
   447          _addSpec({ _name: "MintManager", _sel: _getSel("MINT_CAP()") });
   448          _addSpec({ _name: "MintManager", _sel: _getSel("MINT_PERIOD()") });
   449          _addSpec({ _name: "MintManager", _sel: _getSel("governanceToken()") });
   450          _addSpec({ _name: "MintManager", _sel: _getSel("mint(address,uint256)"), _auth: Role.MINTMANAGEROWNER });
   451          _addSpec({ _name: "MintManager", _sel: _getSel("mintPermittedAfter()") });
   452          _addSpec({ _name: "MintManager", _sel: _getSel("owner()") });
   453          _addSpec({ _name: "MintManager", _sel: _getSel("renounceOwnership()"), _auth: Role.MINTMANAGEROWNER });
   454          _addSpec({ _name: "MintManager", _sel: _getSel("transferOwnership(address)"), _auth: Role.MINTMANAGEROWNER });
   455          _addSpec({ _name: "MintManager", _sel: _getSel("upgrade(address)"), _auth: Role.MINTMANAGEROWNER });
   456      }
   457  
   458      /// @dev Computes the selector from a function signature.
   459      function _getSel(string memory _name) internal pure returns (bytes4) {
   460          return bytes4(keccak256(abi.encodePacked(_name)));
   461      }
   462  
   463      /// @dev Adds a spec for a function.
   464      function _addSpec(string memory _name, bytes4 _sel, Role _auth, bool _pausable) internal {
   465          specs[_name][_sel] = Spec({ name: _name, sel: _sel, auth: _auth, pausable: _pausable });
   466          numEntries[_name]++;
   467      }
   468  
   469      /// @dev Adds a spec for a function with no auth.
   470      function _addSpec(string memory _name, bytes4 _sel, bool _pausable) internal {
   471          _addSpec({ _name: _name, _sel: _sel, _auth: Role.NOAUTH, _pausable: _pausable });
   472      }
   473  
   474      /// @dev Adds a spec for a function with no pausability.
   475      function _addSpec(string memory _name, bytes4 _sel, Role _auth) internal {
   476          _addSpec({ _name: _name, _sel: _sel, _auth: _auth, _pausable: false });
   477      }
   478  
   479      /// @dev Adds a spec for a function with no auth and no pausability.
   480      function _addSpec(string memory _name, bytes4 _sel) internal {
   481          _addSpec({ _name: _name, _sel: _sel, _auth: Role.NOAUTH, _pausable: false });
   482      }
   483  
   484      /// @notice Ensures that there's an auth spec for every L1 contract function.
   485      function testContractAuth() public {
   486          Abi[] memory abis = _getL1ContractFunctionAbis();
   487  
   488          for (uint256 i = 0; i < abis.length; i++) {
   489              string memory contractName = abis[i].contractName;
   490              assertEq(
   491                  abis[i].entries.length, numEntries[contractName], "Specification_Test: invalid number of ABI entries"
   492              );
   493  
   494              for (uint256 j = 0; j < abis[i].entries.length; j++) {
   495                  AbiEntry memory abiEntry = abis[i].entries[j];
   496                  console.log(
   497                      "Checking auth spec for %s: %s(%x)", contractName, abiEntry.fnName, uint256(uint32(abiEntry.sel))
   498                  );
   499                  Spec memory spec = specs[contractName][abiEntry.sel];
   500                  assertTrue(spec.sel != bytes4(0), "Specification_Test: missing spec definition");
   501                  assertEq(abiEntry.sel, spec.sel, "Specification_Test: invalid ABI");
   502              }
   503          }
   504      }
   505  
   506      /// @dev Returns the function ABIs of all L1 contracts.
   507      function _getL1ContractFunctionAbis() internal returns (Abi[] memory abis_) {
   508          string[] memory command = new string[](3);
   509          command[0] = Executables.bash;
   510          command[1] = "-c";
   511          command[2] = string.concat(
   512              Executables.find,
   513              " src/{L1,governance,universal/ProxyAdmin.sol} -type f -exec basename {} \\;",
   514              " | ",
   515              Executables.sed,
   516              " 's/\\.[^.]*$//'",
   517              " | ",
   518              Executables.jq,
   519              " -R -s 'split(\"\n\")[:-1]'"
   520          );
   521          string[] memory contractNames = abi.decode(vm.parseJson(string(vm.ffi(command))), (string[]));
   522  
   523          abis_ = new Abi[](contractNames.length);
   524  
   525          for (uint256 i; i < contractNames.length; i++) {
   526              string memory contractName = contractNames[i];
   527              string[] memory methodIdentifiers = ForgeArtifacts.getMethodIdentifiers(contractName);
   528              abis_[i].contractName = contractName;
   529              abis_[i].entries = new AbiEntry[](methodIdentifiers.length);
   530              for (uint256 j; j < methodIdentifiers.length; j++) {
   531                  string memory fnName = methodIdentifiers[j];
   532                  bytes4 sel = bytes4(keccak256(abi.encodePacked(fnName)));
   533                  abis_[i].entries[j] = AbiEntry({ fnName: fnName, sel: sel });
   534              }
   535          }
   536      }
   537  }