diff --git a/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol b/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol index 837ca4e7cc1..881a0a5d298 100644 --- a/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol +++ b/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol @@ -24,6 +24,7 @@ interface ISystemConfig is IProxyAdminOwnedBase { address optimismPortal; address optimismMintableERC20Factory; address delayedWETH; + address opcm; } error ReinitializableBase_ZeroInitVersion(); @@ -43,6 +44,7 @@ interface ISystemConfig is IProxyAdminOwnedBase { function DELAYED_WETH_SLOT() external view returns (bytes32); function START_BLOCK_SLOT() external view returns (bytes32); function UNSAFE_BLOCK_SIGNER_SLOT() external view returns (bytes32); + function OPCM_SLOT() external view returns (bytes32); function VERSION() external view returns (uint256); function basefeeScalar() external view returns (uint32); function batchInbox() external view returns (address addr_); @@ -81,6 +83,8 @@ interface ISystemConfig is IProxyAdminOwnedBase { function optimismMintableERC20Factory() external view returns (address addr_); function optimismPortal() external view returns (address addr_); function delayedWETH() external view returns (address addr_); + function lastUsedOPCM() external view returns (address addr_); + function lastUsedOPCMVersion() external view returns (string memory version_); function overhead() external view returns (uint256); function owner() external view returns (address); function renounceOwnership() external; diff --git a/packages/contracts-bedrock/interfaces/L1/opcm/IOPContractsManagerV2.sol b/packages/contracts-bedrock/interfaces/L1/opcm/IOPContractsManagerV2.sol index 4185cb8aa78..9d35fe23920 100644 --- a/packages/contracts-bedrock/interfaces/L1/opcm/IOPContractsManagerV2.sol +++ b/packages/contracts-bedrock/interfaces/L1/opcm/IOPContractsManagerV2.sol @@ -124,6 +124,8 @@ interface IOPContractsManagerV2 { function standardValidator() external view returns (IOPContractsManagerStandardValidator); + function thisOPCM() external view returns (IOPContractsManagerV2); + function utils() external view returns (IOPContractsManagerUtils); function version() external view returns (string memory); diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerV2.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerV2.json index 3296b525c66..55019089504 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerV2.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerV2.json @@ -454,6 +454,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "thisOPCM", + "outputs": [ + { + "internalType": "contract OPContractsManagerV2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { diff --git a/packages/contracts-bedrock/snapshots/abi/SystemConfig.json b/packages/contracts-bedrock/snapshots/abi/SystemConfig.json index 826bfbcd9cb..3eb8330144d 100644 --- a/packages/contracts-bedrock/snapshots/abi/SystemConfig.json +++ b/packages/contracts-bedrock/snapshots/abi/SystemConfig.json @@ -69,6 +69,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "OPCM_SLOT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT", @@ -299,6 +312,11 @@ "internalType": "address", "name": "delayedWETH", "type": "address" + }, + { + "internalType": "address", + "name": "opcm", + "type": "address" } ], "internalType": "struct SystemConfig.Addresses", @@ -440,6 +458,11 @@ "internalType": "address", "name": "delayedWETH", "type": "address" + }, + { + "internalType": "address", + "name": "opcm", + "type": "address" } ], "internalType": "struct SystemConfig.Addresses", @@ -546,6 +569,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "lastUsedOPCM", + "outputs": [ + { + "internalType": "address", + "name": "addr_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastUsedOPCMVersion", + "outputs": [ + { + "internalType": "string", + "name": "version_", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "maximumGasLimit", diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index a3e0b43fe9f..4b748b3cd1e 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -24,8 +24,8 @@ "sourceCodeHash": "0xfca613b5d055ffc4c3cbccb0773ddb9030abedc1aa6508c9e2e7727cc0cd617b" }, "src/L1/OPContractsManager.sol:OPContractsManager": { - "initCodeHash": "0x6fd82aaec43858b34bd093e29bbacb659a95817d506de948aebd3c84e6d2a00a", - "sourceCodeHash": "0x5f63555e12cb8e27ce5c1511e986550bf2f1b9769e314223a7324b8dcfa29523" + "initCodeHash": "0x0cb3dfc803e34cd2cae5798e17f29bebbbb861c82cbe8258d6677aedcebcda74", + "sourceCodeHash": "0xb1dffb96b3ba20aaaadaf1110be06540ab03be79b7c6603e0b1ff3486957c8fc" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0x0c8b15453d0f0bc5d9af07f104505e0bbb2b358f0df418289822fb73a8652b30", @@ -48,12 +48,12 @@ "sourceCodeHash": "0xbf344c4369b8cb00ec7a3108f72795747f3bc59ab5b37ac18cf21e72e2979dbf" }, "src/L1/SystemConfig.sol:SystemConfig": { - "initCodeHash": "0x5ff0f79914999b54daeb3e3f38a1e2275f286e005a9e52055d169282605fec81", - "sourceCodeHash": "0xc2b530bf529ac23d1ba1adf67eedcc5d95e25c2919e1d97f4f2bba4823303b17" + "initCodeHash": "0xd4ec112de4cf7173668374479b7405bab9c828e5b32c946ef8ab5cd021f9703b", + "sourceCodeHash": "0xb3184aa5d95a82109e7134d1f61941b30e25f655b9849a0e303d04bbce0cde0b" }, "src/L1/opcm/OPContractsManagerV2.sol:OPContractsManagerV2": { - "initCodeHash": "0xa288a8ea1931f665b15d2156c7d6758eae2099817195139d6f76acd5fc7fdbab", - "sourceCodeHash": "0x04afece9acbb0b2600aceff910f9d5897e52eb0830a7238cf9ddd219954a8cfe" + "initCodeHash": "0x9b6b84f8b87f60c5a38460e78aa6768205f741b17fa60c6d93a1094a8681bd79", + "sourceCodeHash": "0x846dca230392d8e378a2e208a708fc9be342715fd1ca3e3d7c1700f667e25fff" }, "src/L2/BaseFeeVault.sol:BaseFeeVault": { "initCodeHash": "0x838bbd7f381e84e21887f72bd1da605bfc4588b3c39aed96cbce67c09335b3ee", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index 31bfb0989e8..20ab0f10f79 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -1584,7 +1584,8 @@ contract OPContractsManagerDeployer is OPContractsManagerBase { l1StandardBridge: address(_output.l1StandardBridgeProxy), optimismPortal: address(_output.optimismPortalProxy), optimismMintableERC20Factory: address(_output.optimismMintableERC20FactoryProxy), - delayedWETH: address(0) // Will be used in OPCMv2. + delayedWETH: address(0), // Will be used in OPCMv2. + opcm: address(0) // Unsupported for V1. }); assertValidContractAddress(opChainAddrs_.l1CrossDomainMessenger); @@ -2236,9 +2237,9 @@ contract OPContractsManager is ISemver { // -------- Constants and Variables -------- - /// @custom:semver 5.7.1 + /// @custom:semver 5.8.0 function version() public pure virtual returns (string memory) { - return "5.7.1"; + return "5.8.0"; } OPContractsManagerGameTypeAdder public immutable opcmGameTypeAdder; diff --git a/packages/contracts-bedrock/src/L1/SystemConfig.sol b/packages/contracts-bedrock/src/L1/SystemConfig.sol index 9dc554e4053..8aadc105fcd 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfig.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfig.sol @@ -53,6 +53,7 @@ contract SystemConfig is ProxyAdminOwnedBase, OwnableUpgradeable, Reinitializabl address optimismPortal; address optimismMintableERC20Factory; address delayedWETH; + address opcm; } /// @notice Version identifier, used for upgrades. @@ -88,6 +89,9 @@ contract SystemConfig is ProxyAdminOwnedBase, OwnableUpgradeable, Reinitializabl /// @notice Storage slot that the DelayedWETH address is stored at. bytes32 public constant DELAYED_WETH_SLOT = bytes32(uint256(keccak256("systemconfig.delayedweth")) - 1); + /// @notice Storage slot that the OPCM address is stored at. + bytes32 public constant OPCM_SLOT = bytes32(uint256(keccak256("systemconfig.opcm")) - 1); + /// @notice Storage slot that the batch inbox address is stored at. bytes32 public constant BATCH_INBOX_SLOT = bytes32(uint256(keccak256("systemconfig.batchinbox")) - 1); @@ -170,9 +174,9 @@ contract SystemConfig is ProxyAdminOwnedBase, OwnableUpgradeable, Reinitializabl error SystemConfig_InvalidFeatureState(); /// @notice Semantic version. - /// @custom:semver 3.13.1 + /// @custom:semver 3.14.0 function version() public pure virtual returns (string memory) { - return "3.13.1"; + return "3.14.0"; } /// @notice Constructs the SystemConfig contract. @@ -233,6 +237,7 @@ contract SystemConfig is ProxyAdminOwnedBase, OwnableUpgradeable, Reinitializabl Storage.setAddress(OPTIMISM_PORTAL_SLOT, _addresses.optimismPortal); Storage.setAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT, _addresses.optimismMintableERC20Factory); Storage.setAddress(DELAYED_WETH_SLOT, _addresses.delayedWETH); + Storage.setAddress(OPCM_SLOT, _addresses.opcm); _setStartBlock(); _setResourceConfig(_config); @@ -303,6 +308,16 @@ contract SystemConfig is ProxyAdminOwnedBase, OwnableUpgradeable, Reinitializabl addr_ = Storage.getAddress(DELAYED_WETH_SLOT); } + /// @notice Getter for the OPCM address. + function lastUsedOPCM() public view returns (address addr_) { + addr_ = Storage.getAddress(OPCM_SLOT); + } + + /// @notice Getter for the version of the last used OPCM. + function lastUsedOPCMVersion() public view returns (string memory version_) { + version_ = ISemver(lastUsedOPCM()).version(); + } + /// @notice Consolidated getter for the Addresses struct. function getAddresses() external view returns (Addresses memory) { return Addresses({ @@ -311,7 +326,8 @@ contract SystemConfig is ProxyAdminOwnedBase, OwnableUpgradeable, Reinitializabl l1StandardBridge: l1StandardBridge(), optimismPortal: optimismPortal(), optimismMintableERC20Factory: optimismMintableERC20Factory(), - delayedWETH: delayedWETH() + delayedWETH: delayedWETH(), + opcm: lastUsedOPCM() }); } diff --git a/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol b/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol index 49bf1d42eeb..9bdb7daa69c 100644 --- a/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol +++ b/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol @@ -152,13 +152,17 @@ contract OPContractsManagerV2 is ISemver, OPContractsManagerUtilsCaller { /// @notice Address of the Standard Validator for this OPCM release. IOPContractsManagerStandardValidator public immutable standardValidator; + /// @notice Immutable reference to this OPCM contract so that the address of this contract can + /// be used when this contract is DELEGATECALLed. + OPContractsManagerV2 public immutable thisOPCM; + /// @notice The version of the OPCM contract. /// WARNING: OPCM versioning rules differ from other contracts: /// - Major bump: New required sequential upgrade /// - Minor bump: Replacement OPCM for same upgrade /// - Patch bump: Development changes (expected for normal dev work) - /// @custom:semver 6.0.3 - string public constant version = "6.0.3"; + /// @custom:semver 6.0.4 + string public constant version = "6.0.4"; /// @param _contractsContainer The container of blueprint and implementation contract addresses. /// @param _standardValidator The standard validator for this OPCM release. @@ -172,6 +176,7 @@ contract OPContractsManagerV2 is ISemver, OPContractsManagerUtilsCaller { { contractsContainer = _contractsContainer; standardValidator = _standardValidator; + thisOPCM = this; } /////////////////////////////////////////////////////////////////////////// @@ -850,7 +855,8 @@ contract OPContractsManagerV2 is ISemver, OPContractsManagerUtilsCaller { l1StandardBridge: address(_cts.l1StandardBridge), optimismPortal: address(_cts.optimismPortal), optimismMintableERC20Factory: address(_cts.optimismMintableERC20Factory), - delayedWETH: address(_cts.delayedWETH) + delayedWETH: address(_cts.delayedWETH), + opcm: address(thisOPCM) }); // Generate the initializer arguments. diff --git a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol index 9a2fac9c1d0..69e1fcf6ea1 100644 --- a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol +++ b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol @@ -11,6 +11,7 @@ import { ForgeArtifacts, StorageSlot } from "scripts/libraries/ForgeArtifacts.so import { Constants } from "src/libraries/Constants.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; import { Features } from "src/libraries/Features.sol"; +import { DevFeatures } from "src/libraries/DevFeatures.sol"; // Interfaces import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol"; @@ -165,7 +166,8 @@ contract SystemConfig_Initialize_Test is SystemConfig_TestInit { l1StandardBridge: address(0), optimismPortal: address(0), optimismMintableERC20Factory: address(0), - delayedWETH: address(0) + delayedWETH: address(0), + opcm: address(0) }), _l2ChainId: 1234, _superchainConfig: ISuperchainConfig(address(0)) @@ -222,7 +224,8 @@ contract SystemConfig_Initialize_Test is SystemConfig_TestInit { l1StandardBridge: address(0), optimismPortal: address(0), optimismMintableERC20Factory: address(0), - delayedWETH: address(0) + delayedWETH: address(0), + opcm: address(0) }), _l2ChainId: 1234, _superchainConfig: ISuperchainConfig(address(0)) @@ -257,7 +260,8 @@ contract SystemConfig_StartBlock_Test is SystemConfig_TestInit { l1StandardBridge: address(0), optimismPortal: address(0), optimismMintableERC20Factory: address(0), - delayedWETH: address(0) + delayedWETH: address(0), + opcm: address(0) }), _l2ChainId: 1234, _superchainConfig: ISuperchainConfig(address(0)) @@ -289,7 +293,8 @@ contract SystemConfig_StartBlock_Test is SystemConfig_TestInit { l1StandardBridge: address(0), optimismPortal: address(0), optimismMintableERC20Factory: address(0), - delayedWETH: address(0) + delayedWETH: address(0), + opcm: address(0) }), _l2ChainId: 1234, _superchainConfig: ISuperchainConfig(address(0)) @@ -605,7 +610,8 @@ contract SystemConfig_SetResourceConfig_Test is SystemConfig_TestInit { l1StandardBridge: address(0), optimismPortal: address(0), optimismMintableERC20Factory: address(0), - delayedWETH: address(0) + delayedWETH: address(0), + opcm: address(0) }), _l2ChainId: 1234, _superchainConfig: ISuperchainConfig(address(0)) @@ -867,15 +873,17 @@ contract SystemConfig_IsFeatureEnabled_Test is SystemConfig_TestInit { /// @notice Tests that `isFeatureEnabled` returns false for unset features. /// @param _feature The feature to check. function testFuzz_isFeatureEnabled_unsetFeature_succeeds(bytes32 _feature) external { - vm.startPrank(address(systemConfig.proxyAdmin())); + if (_feature == Features.ETH_LOCKBOX && systemConfig.isFeatureEnabled(Features.ETH_LOCKBOX)) { + // Needs to be anything but ETH_LOCKBOX because we can't turn that feature off if it's on. + vm.skip(true); + } // Normalize CUSTOM_GAS_TOKEN to avoid environment-dependent state if (systemConfig.isFeatureEnabled(Features.CUSTOM_GAS_TOKEN)) { + vm.prank(address(systemConfig.proxyAdmin())); systemConfig.setFeature(Features.CUSTOM_GAS_TOKEN, false); } - vm.stopPrank(); - assertFalse(systemConfig.isFeatureEnabled(_feature)); } @@ -975,3 +983,19 @@ contract SystemConfig_IsCustomGasToken_Test is SystemConfig_TestInit { assertFalse(systemConfig.isCustomGasToken()); } } + +/// @title SystemConfig_LastUsedOPCM_Test +/// @notice Test contract for SystemConfig `lastUsedOPCM` and `lastUsedOPCMVersion` functions. +contract SystemConfig_LastUsedOPCM_Test is SystemConfig_TestInit { + /// @notice Tests that `lastUsedOPCM` returns the correct OPCM V2 address and that + /// `lastUsedOPCMVersion` matches the OPCM V2 version. + function test_lastUsedOPCM_opcmV2_succeeds() external { + skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); + + // Verify that the lastUsedOPCM address matches the deployed OPCM V2 address + assertEq(systemConfig.lastUsedOPCM(), address(opcmV2)); + + // Verify that the lastUsedOPCMVersion matches the OPCM V2 version + assertEq(systemConfig.lastUsedOPCMVersion(), opcmV2.version()); + } +} diff --git a/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol b/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol index 281c01e2511..8dcd0da95a5 100644 --- a/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol +++ b/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol @@ -45,7 +45,8 @@ contract SystemConfig_GasLimitBoundaries_Invariant is Test { l1StandardBridge: address(0), optimismPortal: address(0), optimismMintableERC20Factory: address(0), - delayedWETH: address(0) + delayedWETH: address(0), + opcm: address(0) }), 1234, // _l2ChainId ISuperchainConfig(address(0)) // _superchainConfig diff --git a/packages/contracts-bedrock/test/opcm/SetDisputeGameImpl.t.sol b/packages/contracts-bedrock/test/opcm/SetDisputeGameImpl.t.sol index 1de4796463e..ad266dccd79 100644 --- a/packages/contracts-bedrock/test/opcm/SetDisputeGameImpl.t.sol +++ b/packages/contracts-bedrock/test/opcm/SetDisputeGameImpl.t.sol @@ -193,7 +193,8 @@ contract SetDisputeGameImpl_Test is Test { l1StandardBridge: address(5), optimismPortal: address(6), optimismMintableERC20Factory: address(7), - delayedWETH: address(8) + delayedWETH: address(8), + opcm: address(0) }), 10, ISuperchainConfig(address(supConfigProxy)) diff --git a/packages/contracts-bedrock/test/vendor/Initializable.t.sol b/packages/contracts-bedrock/test/vendor/Initializable.t.sol index 80398b34bab..6bde0b7ccbb 100644 --- a/packages/contracts-bedrock/test/vendor/Initializable.t.sol +++ b/packages/contracts-bedrock/test/vendor/Initializable.t.sol @@ -192,7 +192,8 @@ contract Initializer_Test is CommonTest { l1StandardBridge: address(0), optimismPortal: address(0), optimismMintableERC20Factory: address(0), - delayedWETH: address(0) + delayedWETH: address(0), + opcm: address(0) }), 0, ISuperchainConfig(address(0)) @@ -229,7 +230,8 @@ contract Initializer_Test is CommonTest { l1StandardBridge: address(0), optimismPortal: address(0), optimismMintableERC20Factory: address(0), - delayedWETH: address(0) + delayedWETH: address(0), + opcm: address(0) }), 0, ISuperchainConfig(address(0))