diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index 7d4568653936..1b766c55af6a 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -356,7 +356,12 @@ contract L2Genesis is Deployer { /// @notice This predeploy is following the safety invariant #1. function setL1Block() public { - if (cfg.useInterop()) { + if (cfg.useHolocene()) { + string memory cname = "L1BlockHolocene"; + address impl = Predeploys.predeployToCodeNamespace(Predeploys.L1_BLOCK_ATTRIBUTES); + console.log("Setting %s implementation at: %s", cname, impl); + vm.etch(impl, vm.getDeployedCode(string.concat(cname, ".sol:", cname))); + } else if (cfg.useInterop()) { string memory cname = "L1BlockInterop"; address impl = Predeploys.predeployToCodeNamespace(Predeploys.L1_BLOCK_ATTRIBUTES); console.log("Setting %s implementation at: %s", cname, impl); diff --git a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol index 6c70faab1e79..9b2d2a5c8f17 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol @@ -30,6 +30,7 @@ import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC2 import { SuperchainConfig } from "src/L1/SuperchainConfig.sol"; import { SystemConfig } from "src/L1/SystemConfig.sol"; import { SystemConfigInterop } from "src/L1/SystemConfigInterop.sol"; +import { SystemConfigHolocene } from "src/L1/SystemConfigHolocene.sol"; import { ResourceMetering } from "src/L1/ResourceMetering.sol"; import { DataAvailabilityChallenge } from "src/L1/DataAvailabilityChallenge.sol"; import { Constants } from "src/libraries/Constants.sol"; @@ -827,7 +828,9 @@ contract Deploy is Deployer { /// @notice Deploy the SystemConfig function deploySystemConfig() public broadcast returns (address addr_) { console.log("Deploying SystemConfig implementation"); - if (cfg.useInterop()) { + if (cfg.useHolocene()) { + addr_ = address(new SystemConfigHolocene{ salt: _implSalt() }()); + } else if (cfg.useInterop()) { addr_ = address(new SystemConfigInterop{ salt: _implSalt() }()); } else { addr_ = address(new SystemConfig{ salt: _implSalt() }()); diff --git a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol index 6433509f6764..6f4d7de34ea9 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol @@ -91,6 +91,7 @@ contract DeployConfig is Script { address public customGasTokenAddress; bool public useInterop; + bool public useHolocene; function read(string memory _path) public { console.log("DeployConfig: reading file %s", _path); @@ -176,6 +177,7 @@ contract DeployConfig is Script { customGasTokenAddress = _readOr(_json, "$.customGasTokenAddress", address(0)); useInterop = _readOr(_json, "$.useInterop", false); + useHolocene = _readOr(_json, "$.useHolocene", false); } function fork() public view returns (Fork fork_) { diff --git a/packages/contracts-bedrock/src/L1/SystemConfig.sol b/packages/contracts-bedrock/src/L1/SystemConfig.sol index 3d00077527a8..d9e47e3fc170 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfig.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfig.sol @@ -349,7 +349,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { /// @notice Internal function for updating the batcher hash. /// @param _batcherHash New batcher hash. - function _setBatcherHash(bytes32 _batcherHash) internal { + function _setBatcherHash(bytes32 _batcherHash) internal virtual { batcherHash = _batcherHash; bytes memory data = abi.encode(_batcherHash); @@ -367,7 +367,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { /// @notice Internal function for updating the gas config. /// @param _overhead New overhead value. /// @param _scalar New scalar value. - function _setGasConfig(uint256 _overhead, uint256 _scalar) internal { + function _setGasConfig(uint256 _overhead, uint256 _scalar) internal virtual { require((uint256(0xff) << 248) & _scalar == 0, "SystemConfig: scalar exceeds max."); overhead = _overhead; @@ -387,7 +387,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { /// @notice Internal function for updating the fee scalars as of the Ecotone upgrade. /// @param _basefeeScalar New basefeeScalar value. /// @param _blobbasefeeScalar New blobbasefeeScalar value. - function _setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) internal { + function _setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) internal virtual { basefeeScalar = _basefeeScalar; blobbasefeeScalar = _blobbasefeeScalar; @@ -405,7 +405,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { /// @notice Internal function for updating the L2 gas limit. /// @param _gasLimit New gas limit. - function _setGasLimit(uint64 _gasLimit) internal { + function _setGasLimit(uint64 _gasLimit) internal virtual { require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low"); require(_gasLimit <= maximumGasLimit(), "SystemConfig: gas limit too high"); gasLimit = _gasLimit; diff --git a/packages/contracts-bedrock/src/L1/SystemConfigHolocene.sol b/packages/contracts-bedrock/src/L1/SystemConfigHolocene.sol new file mode 100644 index 000000000000..764042d84946 --- /dev/null +++ b/packages/contracts-bedrock/src/L1/SystemConfigHolocene.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { OptimismPortalInterop as OptimismPortal } from "src/L1/OptimismPortalInterop.sol"; +import { SystemConfig } from "src/L1/SystemConfig.sol"; +import { ConfigType } from "src/L2/L1BlockInterop.sol"; +import { StaticConfig } from "src/libraries/StaticConfig.sol"; + +/// @title SystemConfigHolocene +/// @notice The SystemConfig contract is used to manage configuration of an Optimism network. +/// All configuration is stored on L1 and picked up by L2 as part of the derviation of +/// the L2 chain. +contract SystemConfigHolocene is SystemConfig { + error Deprecated(); + + /// @notice Internal function for updating the gas config. + /// `setGasConfig` is deprecated, use `setFeeScalars` instead. + /// `setGasConfig` will be removed when SystemConfigHolocene is + /// pulled into SystemConfig. + function _setGasConfig(uint256, uint256) internal pure override { + revert Deprecated(); + } + + /// @notice Internal function for updating the fee scalars as of the Ecotone upgrade. + /// Deprecated, use `setFeeScalars` instead. + /// @param _basefeeScalar New basefeeScalar value. + /// @param _blobBasefeeScalar New blobBasefeeScalar value. + function _setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobBasefeeScalar) internal override { + _setFeeScalars(_basefeeScalar, _blobBasefeeScalar); + } + + /// @notice Updates the fee scalars. Can only be called by the owner. + /// @param _basefeeScalar New basefeeScalar value. + /// @param _blobBasefeeScalar New blobBasefeeScalar value. + function setFeeScalars(uint32 _basefeeScalar, uint32 _blobBasefeeScalar) external onlyOwner { + _setFeeScalars(_basefeeScalar, _blobBasefeeScalar); + } + + /// @notice Internal function for updating the fee scalars. + /// @param _basefeeScalar New basefeeScalar value. + /// @param _blobBasefeeScalar New blobBasefeeScalar value. + function _setFeeScalars(uint32 _basefeeScalar, uint32 _blobBasefeeScalar) internal { + basefeeScalar = _basefeeScalar; + blobbasefeeScalar = _blobBasefeeScalar; + + uint256 _scalar = StaticConfig.packScalar(_basefeeScalar, _blobBasefeeScalar); + scalar = _scalar; + + OptimismPortal(payable(optimismPortal())).setConfig( + ConfigType.SET_FEE_SCALARS, StaticConfig.encodeSetFeeScalars({ _scalar: _scalar }) + ); + } + + /// @notice Internal setter for the batcher hash. + /// @param _batcherHash New batcher hash. + function _setBatcherHash(bytes32 _batcherHash) internal override { + if (batcherHash != _batcherHash) { + batcherHash = _batcherHash; + OptimismPortal(payable(optimismPortal())).setConfig( + ConfigType.SET_BATCHER_HASH, StaticConfig.encodeSetBatcherHash({ _batcherHash: _batcherHash }) + ); + } + } + + /// @notice Internal function for updating the L2 gas limit. + /// @param _gasLimit New gas limit. + function _setGasLimit(uint64 _gasLimit) internal override { + require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low"); + require(_gasLimit <= maximumGasLimit(), "SystemConfig: gas limit too high"); + gasLimit = _gasLimit; + + OptimismPortal(payable(optimismPortal())).setConfig( + ConfigType.SET_GAS_LIMIT, StaticConfig.encodeSetGasLimit({ _gasLimit: _gasLimit }) + ); + } +} diff --git a/packages/contracts-bedrock/src/L2/L1Block.sol b/packages/contracts-bedrock/src/L2/L1Block.sol index 8cfbb391f0f5..90b5f2b71c3f 100644 --- a/packages/contracts-bedrock/src/L2/L1Block.sol +++ b/packages/contracts-bedrock/src/L2/L1Block.sol @@ -6,6 +6,19 @@ import { Constants } from "src/libraries/Constants.sol"; import { GasPayingToken, IGasToken } from "src/libraries/GasPayingToken.sol"; import "src/libraries/L1BlockErrors.sol"; +/// @notice Enum representing different types of configurations that can be set on L1Block. +/// @custom:value SET_GAS_PAYING_TOKEN Represents the config type for setting the gas paying token. +/// @custom:value ADD_DEPENDENCY Represents the config type for adding a chain to the interop dependency set. +/// @custom:value REMOVE_DEPENDENCY Represents the config type for removing a chain from the interop dependency set. +enum ConfigType { + SET_GAS_PAYING_TOKEN, + ADD_DEPENDENCY, + REMOVE_DEPENDENCY, + SET_BATCHER_HASH, + SET_FEE_SCALARS, + SET_GAS_LIMIT +} + /// @custom:proxied /// @custom:predeploy 0x4200000000000000000000000000000000000015 /// @title L1Block @@ -162,4 +175,10 @@ contract L1Block is ISemver, IGasToken { emit GasPayingTokenSet({ token: _token, decimals: _decimals, name: _name, symbol: _symbol }); } + + /// @notice Sets static configuration options for the L2 system. Can only be called by the special + /// depositor account. + /// @param _type The type of configuration to set. + /// @param _value The encoded value with which to set the configuration. + function setConfig(ConfigType _type, bytes calldata _value) public virtual { } } diff --git a/packages/contracts-bedrock/src/L2/L1BlockHolocene.sol b/packages/contracts-bedrock/src/L2/L1BlockHolocene.sol new file mode 100644 index 000000000000..420bc239183b --- /dev/null +++ b/packages/contracts-bedrock/src/L2/L1BlockHolocene.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { L1Block, ConfigType } from "src/L2/L1Block.sol"; +import { StaticConfig } from "src/libraries/StaticConfig.sol"; +import "src/libraries/L1BlockErrors.sol"; + +/// @custom:proxied +/// @custom:predeploy 0x4200000000000000000000000000000000000015 +/// @title L1BlockHolocene +/// @notice Holocene extenstions of L1Block. +contract L1BlockHolocene is L1Block { + /// @notice Event emitted when a new batcher hash is set. + event BatcherHashSet(bytes32 indexed batcherHash); + + /// @notice Event emitted when new fee scalars are set. + event FeeScalarsSet(uint32 indexed blobBasefeeScalar, uint32 indexed basefeeScalar); + + /// @notice Event emitted when a new gas limit is set. + event GasLimitSet(uint64 indexed gasLimit); + + /// @notice The gas limit of L2 blocks in the same epoch. + uint64 public gasLimit; + + /// @notice Sets static configuration options for the L2 system. Can only be called by the special + /// depositor account. + /// @param _type The type of configuration to set. + /// @param _value The encoded value with which to set the configuration. + function setConfig(ConfigType _type, bytes calldata _value) public override { + if (msg.sender != DEPOSITOR_ACCOUNT()) revert NotDepositor(); + + if (_type == ConfigType.SET_BATCHER_HASH) { + _setBatcherHash(_value); + } else if (_type == ConfigType.SET_FEE_SCALARS) { + _setFeeScalars(_value); + } else if (_type == ConfigType.SET_GAS_LIMIT) { + _setGasLimit(_value); + } else { + super.setConfig(_type, _value); + } + } + + /// @notice Internal method to set new batcher hash. + /// @param _value The encoded value with which to set the new batcher hash. + function _setBatcherHash(bytes calldata _value) internal { + bytes32 _batcherHash = StaticConfig.decodeSetBatcherHash(_value); + + batcherHash = _batcherHash; + + emit BatcherHashSet(_batcherHash); + } + + /// @notice Internal method to set new fee scalars. + /// @param _value The encoded value with which to set the new fee scalars. + function _setFeeScalars(bytes calldata _value) internal { + uint256 _scalar = StaticConfig.decodeSetFeeScalars(_value); + + (uint32 _basefeeScalar, uint32 _blobBasefeeScalar) = StaticConfig.unpackScalar(_scalar); + + blobBaseFeeScalar = _blobBasefeeScalar; + baseFeeScalar = _basefeeScalar; + + emit FeeScalarsSet(_blobBasefeeScalar, _basefeeScalar); + } + + /// @notice Internal method to set new gas limit. + /// @param _value The encoded value with which to set the new gas limit. + function _setGasLimit(bytes calldata _value) internal { + uint64 _gasLimit = StaticConfig.decodeSetGasLimit(_value); + gasLimit = _gasLimit; + emit GasLimitSet(_gasLimit); + } + + /// @notice Updates the L1 block values for an Holocene upgraded chain. + /// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size. + /// Params are expected to be in the following order: + /// 1. _sequenceNumber Number of L2 blocks since epoch start. + /// 2. _timestamp L1 timestamp. + /// 3. _number L1 blocknumber. + /// 4. _basefee L1 base fee. + /// 5. _blobBaseFee L1 blob base fee. + /// 6. _hash L1 blockhash. + function setL1BlockValuesHolocene() external { + address depositor = DEPOSITOR_ACCOUNT(); + uint64 _sequenceNumber; + assembly { + // Revert if the caller is not the depositor account. + if xor(caller(), depositor) { + mstore(0x00, 0x3cc50b45) // 0x3cc50b45 is the 4-byte selector of "NotDepositor()" + revert(0x1C, 0x04) // returns the stored 4-byte selector from above + } + // sequencenum (uint64) + _sequenceNumber := shr(192, calldataload(4)) + } + + sequenceNumber = _sequenceNumber; + + // for each L2 block, include only the sequence number, except for L2 blocks with sequencer #0, + // and they'd have all the L1 origin related attributes following the 0 sequence number. + if (_sequenceNumber != 0) return; + + assembly { + // number (uint64) and timestamp (uint64) + sstore(number.slot, shr(128, calldataload(12))) + sstore(basefee.slot, calldataload(28)) // uint256 + sstore(blobBaseFee.slot, calldataload(60)) // uint256 + sstore(hash.slot, calldataload(92)) // bytes32 + } + } +} diff --git a/packages/contracts-bedrock/src/L2/L1BlockInterop.sol b/packages/contracts-bedrock/src/L2/L1BlockInterop.sol index 8dbf986fb7e6..80d39390c321 100644 --- a/packages/contracts-bedrock/src/L2/L1BlockInterop.sol +++ b/packages/contracts-bedrock/src/L2/L1BlockInterop.sol @@ -1,22 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { L1Block } from "src/L2/L1Block.sol"; +import { L1Block, ConfigType } from "src/L2/L1Block.sol"; import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { GasPayingToken } from "src/libraries/GasPayingToken.sol"; import { StaticConfig } from "src/libraries/StaticConfig.sol"; import "src/libraries/L1BlockErrors.sol"; -/// @notice Enum representing different types of configurations that can be set on L1BlockInterop. -/// @custom:value SET_GAS_PAYING_TOKEN Represents the config type for setting the gas paying token. -/// @custom:value ADD_DEPENDENCY Represents the config type for adding a chain to the interop dependency set. -/// @custom:value REMOVE_DEPENDENCY Represents the config type for removing a chain from the interop dependency set. -enum ConfigType { - SET_GAS_PAYING_TOKEN, - ADD_DEPENDENCY, - REMOVE_DEPENDENCY -} - /// @custom:proxied /// @custom:predeploy 0x4200000000000000000000000000000000000015 /// @title L1BlockInterop @@ -56,7 +46,7 @@ contract L1BlockInterop is L1Block { /// depositor account. /// @param _type The type of configuration to set. /// @param _value The encoded value with which to set the configuration. - function setConfig(ConfigType _type, bytes calldata _value) external { + function setConfig(ConfigType _type, bytes calldata _value) public override { if (msg.sender != DEPOSITOR_ACCOUNT()) revert NotDepositor(); if (_type == ConfigType.SET_GAS_PAYING_TOKEN) { @@ -65,6 +55,8 @@ contract L1BlockInterop is L1Block { _addDependency(_value); } else if (_type == ConfigType.REMOVE_DEPENDENCY) { _removeDependency(_value); + } else { + super.setConfig(_type, _value); } } diff --git a/packages/contracts-bedrock/src/libraries/StaticConfig.sol b/packages/contracts-bedrock/src/libraries/StaticConfig.sol index ffaa0b4e5535..5ef169cbc113 100644 --- a/packages/contracts-bedrock/src/libraries/StaticConfig.sol +++ b/packages/contracts-bedrock/src/libraries/StaticConfig.sol @@ -57,4 +57,64 @@ library StaticConfig { function decodeRemoveDependency(bytes memory _data) internal pure returns (uint256) { return abi.decode(_data, (uint256)); } + + /// @notice Encodes the static configuration data for setting batcher hash. + /// @param _batcherHash New batcher hash. + /// @return Encoded static configuration data. + function encodeSetBatcherHash(bytes32 _batcherHash) internal pure returns (bytes memory) { + return abi.encode(_batcherHash); + } + + /// @notice Decodes the static configuration data for setting batcher hash. + /// @param _data Encoded static configuration data. + /// @return Decoded batcher hash to set. + function decodeSetBatcherHash(bytes memory _data) internal pure returns (bytes32) { + return abi.decode(_data, (bytes32)); + } + + /// @notice Encodes the static configuration data for setting the fee scalars. + /// @param _scalar New scalar value. + /// @return Encoded static configuration data. + function encodeSetFeeScalars(uint256 _scalar) internal pure returns (bytes memory) { + return abi.encode(_scalar); + } + + /// @notice Decodes the static configuration data for setting the fee scalars. + /// @param _data Encoded static configuration data. + /// @return Decoded fee scalars to set. + function decodeSetFeeScalars(bytes memory _data) internal pure returns (uint256) { + return abi.decode(_data, (uint256)); + } + + /// @notice Encodes the static configuration data for setting the gas limit. + /// @param _gasLimit New gas limit. + function encodeSetGasLimit(uint64 _gasLimit) internal pure returns (bytes memory) { + return abi.encode(_gasLimit); + } + + /// @notice Decodes the static configuration data for setting the gas limit. + /// @param _data Encoded static configuration data. + /// @return Decoded gas limit to set. + function decodeSetGasLimit(bytes memory _data) internal pure returns (uint64) { + return abi.decode(_data, (uint64)); + } + + /// @notice Packs _basefeeScalar and _blobBasefeeScalar into a single uint256 + /// @param _basefeeScalar New basefeeScalar value. + /// @param _blobBasefeeScalar New blobBasefeeScalar value. + /// @return Packed scalar as a uint256. + function packScalar(uint32 _basefeeScalar, uint32 _blobBasefeeScalar) internal pure returns (uint256) { + return (uint256(0x01) << 248) | (uint256(_blobBasefeeScalar) << 32) | _basefeeScalar; + } + + /// @notice Unpacks _basefeeScalar and _blobBasefeeScalar from a single uint256 + /// @param _scalar Packs uint256 scalar. + /// @return Unpacked _basefeeScalar and _blobBasefeeScalar. + function unpackScalar(uint256 _scalar) internal pure returns (uint32, uint32) { + require(0x01 == _scalar >> 248, "invalid _scalar"); + + uint32 _blobBasefeeScalar = uint32((_scalar >> 32) & 0xffffffff); + uint32 _basefeeScalar = uint32(_scalar & 0xffffffff); + return (_basefeeScalar, _blobBasefeeScalar); + } } diff --git a/packages/contracts-bedrock/test/Specs.t.sol b/packages/contracts-bedrock/test/Specs.t.sol index ecba915d9cf2..374d726ed3ef 100644 --- a/packages/contracts-bedrock/test/Specs.t.sol +++ b/packages/contracts-bedrock/test/Specs.t.sol @@ -466,6 +466,75 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SystemConfig", _sel: _getSel("blobbasefeeScalar()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("maximumGasLimit()") }); + // SystemConfigHolocene + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("UNSAFE_BLOCK_SIGNER_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("START_BLOCK_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("VERSION()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("batcherHash()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("gasLimit()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: SystemConfig.initialize.selector }); + _addSpec({ _name: "SystemConfigHolocene", _sel: SystemConfig.minimumGasLimit.selector }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("overhead()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("owner()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("renounceOwnership()"), _auth: Role.SYSTEMCONFIGOWNER }); + _addSpec({ _name: "SystemConfigHolocene", _sel: SystemConfig.resourceConfig.selector }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("scalar()") }); + _addSpec({ + _name: "SystemConfigHolocene", + _sel: SystemConfig.setBatcherHash.selector, + _auth: Role.SYSTEMCONFIGOWNER + }); + _addSpec({ + _name: "SystemConfigHolocene", + _sel: SystemConfig.setGasConfig.selector, + _auth: Role.SYSTEMCONFIGOWNER + }); + _addSpec({ + _name: "SystemConfigHolocene", + _sel: SystemConfig.setGasLimit.selector, + _auth: Role.SYSTEMCONFIGOWNER + }); + _addSpec({ + _name: "SystemConfigHolocene", + _sel: SystemConfig.setUnsafeBlockSigner.selector, + _auth: Role.SYSTEMCONFIGOWNER + }); + _addSpec({ + _name: "SystemConfigHolocene", + _sel: _getSel("transferOwnership(address)"), + _auth: Role.SYSTEMCONFIGOWNER + }); + _addSpec({ _name: "SystemConfigHolocene", _sel: SystemConfig.unsafeBlockSigner.selector }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("version()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("l1CrossDomainMessenger()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("l1ERC721Bridge()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("l1StandardBridge()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("optimismPortal()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("optimismMintableERC20Factory()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("batchInbox()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("startBlock()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("L1_CROSS_DOMAIN_MESSENGER_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("L1_ERC_721_BRIDGE_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("L1_STANDARD_BRIDGE_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("OPTIMISM_PORTAL_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("BATCH_INBOX_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("gasPayingToken()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("gasPayingTokenName()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("gasPayingTokenSymbol()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("isCustomGasToken()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("DISPUTE_GAME_FACTORY_SLOT()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("disputeGameFactory()") }); + _addSpec({ + _name: "SystemConfigHolocene", + _sel: _getSel("setGasConfigEcotone(uint32,uint32)"), + _auth: Role.SYSTEMCONFIGOWNER + }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("basefeeScalar()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("blobbasefeeScalar()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("maximumGasLimit()") }); + _addSpec({ _name: "SystemConfigHolocene", _sel: _getSel("setFeeScalars(uint32,uint32)") }); + // SystemConfigInterop _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("UNSAFE_BLOCK_SIGNER_SLOT()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("START_BLOCK_SLOT()") });