Commit e90ae518 authored by Maurelian's avatar Maurelian Committed by GitHub

OPCM upgrade full PoC (#13574)

* feat: Implement OPCM upgrade

* feat: better comment

* feat: Move vars to Setup where they belong

* gas snapshot
parent bcf59234
...@@ -44,6 +44,7 @@ interface ISystemConfig { ...@@ -44,6 +44,7 @@ interface ISystemConfig {
function gasLimit() external view returns (uint64); function gasLimit() external view returns (uint64);
function eip1559Denominator() external view returns (uint32); function eip1559Denominator() external view returns (uint32);
function eip1559Elasticity() external view returns (uint32); function eip1559Elasticity() external view returns (uint32);
function getAddresses() external view returns (Addresses memory);
function initialize( function initialize(
address _owner, address _owner,
uint32 _basefeeScalar, uint32 _basefeeScalar,
......
...@@ -89,6 +89,7 @@ contract DeployConfig is Script { ...@@ -89,6 +89,7 @@ contract DeployConfig is Script {
address public customGasTokenAddress; address public customGasTokenAddress;
bool public useInterop; bool public useInterop;
bool public useUpgradedFork;
function read(string memory _path) public { function read(string memory _path) public {
console.log("DeployConfig: reading file %s", _path); console.log("DeployConfig: reading file %s", _path);
...@@ -174,6 +175,7 @@ contract DeployConfig is Script { ...@@ -174,6 +175,7 @@ contract DeployConfig is Script {
customGasTokenAddress = _readOr(_json, "$.customGasTokenAddress", address(0)); customGasTokenAddress = _readOr(_json, "$.customGasTokenAddress", address(0));
useInterop = _readOr(_json, "$.useInterop", false); useInterop = _readOr(_json, "$.useInterop", false);
useUpgradedFork;
} }
function fork() public view returns (Fork fork_) { function fork() public view returns (Fork fork_) {
...@@ -236,6 +238,17 @@ contract DeployConfig is Script { ...@@ -236,6 +238,17 @@ contract DeployConfig is Script {
customGasTokenAddress = _token; customGasTokenAddress = _token;
} }
/// @notice Allow the `useUpgradedFork` config to be overridden in testing environments
/// @dev When true, the forked system WILL be upgraded in setUp().
/// When false, the forked system WILL NOT be upgraded in setUp().
/// This function does nothing when not testing in a forked environment.
/// Generally the only time you should call this function is if you want to
/// call opcm.upgrade() in the test itself, rather than have the upgraded
/// system be deployed in setUp().
function setUseUpgradedFork(bool _useUpgradedFork) public {
useUpgradedFork = _useUpgradedFork;
}
function latestGenesisFork() internal view returns (Fork) { function latestGenesisFork() internal view returns (Fork) {
if (l2GenesisHoloceneTimeOffset == 0) { if (l2GenesisHoloceneTimeOffset == 0) {
return Fork.HOLOCENE; return Fork.HOLOCENE;
......
GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7567) GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7589)
GasBenchMark_L1BlockInterop_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5567) GasBenchMark_L1BlockInterop_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5589)
GasBenchMark_L1BlockInterop_SetValuesInterop:test_setL1BlockValuesInterop_benchmark() (gas: 175722) GasBenchMark_L1BlockInterop_SetValuesInterop:test_setL1BlockValuesInterop_benchmark() (gas: 175722)
GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_benchmark() (gas: 5144) GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_benchmark() (gas: 5144)
GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158531) GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158553)
GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597) GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7619)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 356487) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 356487)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2954716) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2954716)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 551591) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 551627)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4063784) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4063775)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 450277) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 450267)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3496176) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3496188)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 59849) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 59798)
\ No newline at end of file \ No newline at end of file
...@@ -600,6 +600,31 @@ ...@@ -600,6 +600,31 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [
{
"components": [
{
"internalType": "contract ISystemConfig",
"name": "systemConfigProxy",
"type": "address"
},
{
"internalType": "contract IProxyAdmin",
"name": "proxyAdmin",
"type": "address"
}
],
"internalType": "struct OPContractsManager.OpChain[]",
"name": "_opChains",
"type": "tuple[]"
}
],
"name": "upgrade",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "version", "name": "version",
...@@ -610,7 +635,7 @@ ...@@ -610,7 +635,7 @@
"type": "string" "type": "string"
} }
], ],
"stateMutability": "view", "stateMutability": "pure",
"type": "function" "type": "function"
}, },
{ {
...@@ -638,6 +663,31 @@ ...@@ -638,6 +663,31 @@
"name": "Deployed", "name": "Deployed",
"type": "event" "type": "event"
}, },
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "l2ChainId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "upgrader",
"type": "address"
}
],
"name": "Upgraded",
"type": "event"
},
{ {
"inputs": [ "inputs": [
{ {
...@@ -731,6 +781,17 @@ ...@@ -731,6 +781,17 @@
"name": "ReservedBitsSet", "name": "ReservedBitsSet",
"type": "error" "type": "error"
}, },
{
"inputs": [
{
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
}
],
"name": "SuperchainConfigMismatch",
"type": "error"
},
{ {
"inputs": [ "inputs": [
{ {
......
...@@ -600,6 +600,31 @@ ...@@ -600,6 +600,31 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [
{
"components": [
{
"internalType": "contract ISystemConfig",
"name": "systemConfigProxy",
"type": "address"
},
{
"internalType": "contract IProxyAdmin",
"name": "proxyAdmin",
"type": "address"
}
],
"internalType": "struct OPContractsManager.OpChain[]",
"name": "_opChains",
"type": "tuple[]"
}
],
"name": "upgrade",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "version", "name": "version",
...@@ -610,7 +635,7 @@ ...@@ -610,7 +635,7 @@
"type": "string" "type": "string"
} }
], ],
"stateMutability": "view", "stateMutability": "pure",
"type": "function" "type": "function"
}, },
{ {
...@@ -638,6 +663,31 @@ ...@@ -638,6 +663,31 @@
"name": "Deployed", "name": "Deployed",
"type": "event" "type": "event"
}, },
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "l2ChainId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "upgrader",
"type": "address"
}
],
"name": "Upgraded",
"type": "event"
},
{ {
"inputs": [ "inputs": [
{ {
...@@ -731,6 +781,17 @@ ...@@ -731,6 +781,17 @@
"name": "ReservedBitsSet", "name": "ReservedBitsSet",
"type": "error" "type": "error"
}, },
{
"inputs": [
{
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
}
],
"name": "SuperchainConfigMismatch",
"type": "error"
},
{ {
"inputs": [ "inputs": [
{ {
......
...@@ -238,6 +238,51 @@ ...@@ -238,6 +238,51 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "getAddresses",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "l1CrossDomainMessenger",
"type": "address"
},
{
"internalType": "address",
"name": "l1ERC721Bridge",
"type": "address"
},
{
"internalType": "address",
"name": "l1StandardBridge",
"type": "address"
},
{
"internalType": "address",
"name": "disputeGameFactory",
"type": "address"
},
{
"internalType": "address",
"name": "optimismPortal",
"type": "address"
},
{
"internalType": "address",
"name": "optimismMintableERC20Factory",
"type": "address"
}
],
"internalType": "struct SystemConfig.Addresses",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
......
...@@ -259,6 +259,51 @@ ...@@ -259,6 +259,51 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "getAddresses",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "l1CrossDomainMessenger",
"type": "address"
},
{
"internalType": "address",
"name": "l1ERC721Bridge",
"type": "address"
},
{
"internalType": "address",
"name": "l1StandardBridge",
"type": "address"
},
{
"internalType": "address",
"name": "disputeGameFactory",
"type": "address"
},
{
"internalType": "address",
"name": "optimismPortal",
"type": "address"
},
{
"internalType": "address",
"name": "optimismMintableERC20Factory",
"type": "address"
}
],
"internalType": "struct SystemConfig.Addresses",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
......
...@@ -16,8 +16,12 @@ ...@@ -16,8 +16,12 @@
"sourceCodeHash": "0xc6613d35d1ad95cbef26a503a10b5dd8663ceb80426f8c528835d39f79e4b4cf" "sourceCodeHash": "0xc6613d35d1ad95cbef26a503a10b5dd8663ceb80426f8c528835d39f79e4b4cf"
}, },
"src/L1/OPContractsManager.sol": { "src/L1/OPContractsManager.sol": {
"initCodeHash": "0xd523359106bfdca4189401bba564d2856a7122b705f9ad2698b8b43bb28169c8", "initCodeHash": "0xa277d25e1aae34f68e9e8a0814c34f6adada5248992dc5e62831ef0082f130fb",
"sourceCodeHash": "0x823041c951d9df921295b25f9151b57292a64de98fec2c12849e9fe6a3fb635d" "sourceCodeHash": "0xaa2c1ae210bf8c53b21e8fe3280bf17040118530eafd1f33e8ed64bc17ee4a17"
},
"src/L1/OPContractsManagerInterop.sol": {
"initCodeHash": "0x5cbfb22cb4ca0465a0bc8d87034763f9a103384ff60ac88af8a4c2ced7c96b7d",
"sourceCodeHash": "0x1bbe8f918f1d5b1cc75924cdf23b10664b890fd306c2aa5d195a7b4177670431"
}, },
"src/L1/OptimismPortal2.sol": { "src/L1/OptimismPortal2.sol": {
"initCodeHash": "0x969e3687d4497cc168af61e610ba0ae187e80f86aaa7b5d5bb598de19f279f08", "initCodeHash": "0x969e3687d4497cc168af61e610ba0ae187e80f86aaa7b5d5bb598de19f279f08",
...@@ -36,12 +40,12 @@ ...@@ -36,12 +40,12 @@
"sourceCodeHash": "0xafa784ea78818a382ff3a61e2d84be58c7978110c06b9273db68c0213ead02d3" "sourceCodeHash": "0xafa784ea78818a382ff3a61e2d84be58c7978110c06b9273db68c0213ead02d3"
}, },
"src/L1/SystemConfig.sol": { "src/L1/SystemConfig.sol": {
"initCodeHash": "0xf0bfbb889687af7d4e006f40b269bbd9e4d967cdd9c1f29900017ff11b1f5095", "initCodeHash": "0x48e379dbb7a457ea5d7ab11e42b7b30377de9fe4bcc8a0a4b1ce8591652da6f4",
"sourceCodeHash": "0x2dde897735c0cd699f15a1927bf6f75c2da220c1934021ee93315708d5b5f995" "sourceCodeHash": "0x0cfa6d791e217bd6650e1155ead95781505cd364b698cbea44c7684b1e506d57"
}, },
"src/L1/SystemConfigInterop.sol": { "src/L1/SystemConfigInterop.sol": {
"initCodeHash": "0xd89526ba331c24f8ca5ce1eef1554ad573e3aa9e6845a5b0ec23ee8f3497a84a", "initCodeHash": "0xa5a43846dbf17233c3ac5bb845798b3dbb95e4773249e9b74cb88626a5e77132",
"sourceCodeHash": "0x10806bbaa0d0e1dca571b720bd9690dd55cbf57038ab5887ecfdce689b0ae94e" "sourceCodeHash": "0x893478f9816eb4e0764ed275a3ff27d8b9aa264ce5c5f4f0011cecfcc3638e47"
}, },
"src/L2/BaseFeeVault.sol": { "src/L2/BaseFeeVault.sol": {
"initCodeHash": "0xc403d4c555d8e69a2699e01d192ae7327136701fa02da10a6d75a584b3c364c9", "initCodeHash": "0xc403d4c555d8e69a2699e01d192ae7327136701fa02da10a6d75a584b3c364c9",
......
...@@ -12,6 +12,11 @@ import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; ...@@ -12,6 +12,11 @@ import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { ISystemConfigInterop } from "interfaces/L1/ISystemConfigInterop.sol"; import { ISystemConfigInterop } from "interfaces/L1/ISystemConfigInterop.sol";
contract OPContractsManagerInterop is OPContractsManager { contract OPContractsManagerInterop is OPContractsManager {
/// @custom:semver +interop-beta.1
function version() public pure override returns (string memory) {
return string.concat(super.version(), "+interop-beta.1");
}
constructor( constructor(
ISuperchainConfig _superchainConfig, ISuperchainConfig _superchainConfig,
IProtocolVersions _protocolVersions, IProtocolVersions _protocolVersions,
......
...@@ -129,9 +129,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver { ...@@ -129,9 +129,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver {
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data); event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
/// @notice Semantic version. /// @notice Semantic version.
/// @custom:semver 2.3.0-beta.11 /// @custom:semver 2.3.0-beta.12
function version() public pure virtual returns (string memory) { function version() public pure virtual returns (string memory) {
return "2.3.0-beta.11"; return "2.3.0-beta.12";
} }
/// @notice Constructs the SystemConfig contract. /// @notice Constructs the SystemConfig contract.
...@@ -217,22 +217,22 @@ contract SystemConfig is OwnableUpgradeable, ISemver { ...@@ -217,22 +217,22 @@ contract SystemConfig is OwnableUpgradeable, ISemver {
} }
/// @notice Getter for the L1CrossDomainMessenger address. /// @notice Getter for the L1CrossDomainMessenger address.
function l1CrossDomainMessenger() external view returns (address addr_) { function l1CrossDomainMessenger() public view returns (address addr_) {
addr_ = Storage.getAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT); addr_ = Storage.getAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT);
} }
/// @notice Getter for the L1ERC721Bridge address. /// @notice Getter for the L1ERC721Bridge address.
function l1ERC721Bridge() external view returns (address addr_) { function l1ERC721Bridge() public view returns (address addr_) {
addr_ = Storage.getAddress(L1_ERC_721_BRIDGE_SLOT); addr_ = Storage.getAddress(L1_ERC_721_BRIDGE_SLOT);
} }
/// @notice Getter for the L1StandardBridge address. /// @notice Getter for the L1StandardBridge address.
function l1StandardBridge() external view returns (address addr_) { function l1StandardBridge() public view returns (address addr_) {
addr_ = Storage.getAddress(L1_STANDARD_BRIDGE_SLOT); addr_ = Storage.getAddress(L1_STANDARD_BRIDGE_SLOT);
} }
/// @notice Getter for the DisputeGameFactory address. /// @notice Getter for the DisputeGameFactory address.
function disputeGameFactory() external view returns (address addr_) { function disputeGameFactory() public view returns (address addr_) {
addr_ = Storage.getAddress(DISPUTE_GAME_FACTORY_SLOT); addr_ = Storage.getAddress(DISPUTE_GAME_FACTORY_SLOT);
} }
...@@ -242,10 +242,22 @@ contract SystemConfig is OwnableUpgradeable, ISemver { ...@@ -242,10 +242,22 @@ contract SystemConfig is OwnableUpgradeable, ISemver {
} }
/// @notice Getter for the OptimismMintableERC20Factory address. /// @notice Getter for the OptimismMintableERC20Factory address.
function optimismMintableERC20Factory() external view returns (address addr_) { function optimismMintableERC20Factory() public view returns (address addr_) {
addr_ = Storage.getAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT); addr_ = Storage.getAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT);
} }
/// @notice Consolidated getter for the Addresses struct.
function getAddresses() external view returns (Addresses memory) {
return Addresses({
l1CrossDomainMessenger: l1CrossDomainMessenger(),
l1ERC721Bridge: l1ERC721Bridge(),
l1StandardBridge: l1StandardBridge(),
disputeGameFactory: disputeGameFactory(),
optimismPortal: optimismPortal(),
optimismMintableERC20Factory: optimismMintableERC20Factory()
});
}
/// @notice Getter for the BatchInbox address. /// @notice Getter for the BatchInbox address.
function batchInbox() external view returns (address addr_) { function batchInbox() external view returns (address addr_) {
addr_ = Storage.getAddress(BATCH_INBOX_SLOT); addr_ = Storage.getAddress(BATCH_INBOX_SLOT);
......
...@@ -65,9 +65,9 @@ contract SystemConfigInterop is SystemConfig { ...@@ -65,9 +65,9 @@ contract SystemConfigInterop is SystemConfig {
Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager); Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager);
} }
/// @custom:semver +interop-beta.10 /// @custom:semver +interop-beta.11
function version() public pure override returns (string memory) { function version() public pure override returns (string memory) {
return string.concat(super.version(), "+interop-beta.10"); return string.concat(super.version(), "+interop-beta.11");
} }
/// @notice Adds a chain to the interop dependency set. Can only be called by the dependency manager. /// @notice Adds a chain to the interop dependency set. Can only be called by the dependency manager.
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
// Testing
import { Test, stdStorage, StdStorage } from "forge-std/Test.sol"; import { Test, stdStorage, StdStorage } from "forge-std/Test.sol";
import { CommonTest } from "test/setup/CommonTest.sol";
import { DeployOPChain_TestBase } from "test/opcm/DeployOPChain.t.sol";
import { DelegateCaller } from "test/mocks/Callers.sol";
// Scripts
import { DeployOPChainInput } from "scripts/deploy/DeployOPChain.s.sol"; import { DeployOPChainInput } from "scripts/deploy/DeployOPChain.s.sol";
import { DeployOPChain_TestBase } from "test/opcm/DeployOPChain.t.sol";
import { OPContractsManager } from "src/L1/OPContractsManager.sol"; // Libraries
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { Blueprint } from "src/libraries/Blueprint.sol";
import { ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol";
// Interfaces
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol"; import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol"; import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol";
import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol";
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
// Contracts
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
import { Blueprint } from "src/libraries/Blueprint.sol"; import { Blueprint } from "src/libraries/Blueprint.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol"; import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol"; import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
...@@ -167,6 +181,120 @@ contract OPContractsManager_InternalMethods_Test is Test { ...@@ -167,6 +181,120 @@ contract OPContractsManager_InternalMethods_Test is Test {
} }
} }
contract OPContractsManager_Upgrade_Harness is CommonTest {
// The Upgraded event emitted by the Proxy contract.
event Upgraded(address indexed implementation);
// The Upgraded event emitted by the OPContractsManager contract.
event Upgraded(uint256 indexed l2ChainId, ISystemConfig indexed systemConfig, address indexed upgrader);
// The AddressSet event emitted by the AddressManager contract.
event AddressSet(string indexed name, address newAddress, address oldAddress);
uint256 l2ChainId;
IProxyAdmin proxyAdmin;
address upgrader;
OPContractsManager.OpChain[] opChains;
function setUp() public virtual override {
super.disableUpgradedFork();
super.setUp();
if (!isForkTest()) {
// This test is only supported in forked tests, as we are testing the upgrade.
vm.skip(true);
}
proxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(systemConfig)));
upgrader = proxyAdmin.owner();
vm.label(upgrader, "ProxyAdmin Owner");
opChains.push(OPContractsManager.OpChain({ systemConfigProxy: systemConfig, proxyAdmin: proxyAdmin }));
// Retrieve the l2ChainId, which was read from the superchain-registry, and saved in Artifacts
// encoded as an address.
l2ChainId = uint256(bytes32(bytes20(address(artifacts.mustGetAddress("L2ChainId")))) >> 96);
delayedWETHPermissionedGameProxy =
IDelayedWETH(payable(artifacts.mustGetAddress("PermissionedDelayedWETHProxy")));
delayedWeth = IDelayedWETH(payable(artifacts.mustGetAddress("PermissionlessDelayedWETHProxy")));
permissionedDisputeGame = IPermissionedDisputeGame(address(artifacts.mustGetAddress("PermissionedDisputeGame")));
faultDisputeGame = IFaultDisputeGame(address(artifacts.mustGetAddress("FaultDisputeGame")));
}
}
contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness {
function test_upgrade_succeeds() public {
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
OPContractsManager.Implementations memory impls = opcm.implementations();
address oldL1CrossDomainMessenger = addressManager.getAddress("OVM_L1CrossDomainMessenger");
expectEmitUpgraded(impls.systemConfigImpl, address(systemConfig));
vm.expectEmit(address(addressManager));
emit AddressSet("OVM_L1CrossDomainMessenger", impls.l1CrossDomainMessengerImpl, oldL1CrossDomainMessenger);
// This is where we would emit an event for the L1StandardBridge however
// the Chugsplash proxy does not emit such an event.
expectEmitUpgraded(impls.l1ERC721BridgeImpl, address(l1ERC721Bridge));
expectEmitUpgraded(impls.disputeGameFactoryImpl, address(disputeGameFactory));
expectEmitUpgraded(impls.optimismPortalImpl, address(optimismPortal2));
expectEmitUpgraded(impls.optimismMintableERC20FactoryImpl, address(l1OptimismMintableERC20Factory));
expectEmitUpgraded(impls.anchorStateRegistryImpl, address(anchorStateRegistry));
expectEmitUpgraded(impls.delayedWETHImpl, address(delayedWETHPermissionedGameProxy));
if (address(delayedWeth) != address(0)) {
expectEmitUpgraded(impls.delayedWETHImpl, address(delayedWeth));
}
vm.expectEmit(true, true, true, true, address(upgrader));
emit Upgraded(l2ChainId, opChains[0].systemConfigProxy, address(upgrader));
DelegateCaller(upgrader).dcForward(address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains)));
assertEq(impls.systemConfigImpl, EIP1967Helper.getImplementation(address(systemConfig)));
assertEq(impls.l1ERC721BridgeImpl, EIP1967Helper.getImplementation(address(l1ERC721Bridge)));
assertEq(impls.disputeGameFactoryImpl, EIP1967Helper.getImplementation(address(disputeGameFactory)));
assertEq(impls.optimismPortalImpl, EIP1967Helper.getImplementation(address(optimismPortal2)));
assertEq(
impls.optimismMintableERC20FactoryImpl,
EIP1967Helper.getImplementation(address(l1OptimismMintableERC20Factory))
);
assertEq(impls.l1StandardBridgeImpl, EIP1967Helper.getImplementation(address(l1StandardBridge)));
assertEq(impls.l1CrossDomainMessengerImpl, addressManager.getAddress("OVM_L1CrossDomainMessenger"));
assertEq(impls.anchorStateRegistryImpl, EIP1967Helper.getImplementation(address(anchorStateRegistry)));
assertEq(impls.delayedWETHImpl, EIP1967Helper.getImplementation(address(delayedWeth)));
if (address(delayedWeth) != address(0)) {
assertEq(impls.delayedWETHImpl, EIP1967Helper.getImplementation(address(delayedWeth)));
}
// TODO: ensure dispute games are updated (upcoming PR)
}
function expectEmitUpgraded(address impl, address proxy) public {
vm.expectEmit(proxy);
emit Upgraded(impl);
}
}
contract OPContractsManager_Upgrade_TestFails is OPContractsManager_Upgrade_Harness {
function test_upgrade_notDelegateCalled_reverts() public {
vm.prank(upgrader);
vm.expectRevert(OPContractsManager.OnlyDelegatecall.selector);
opcm.upgrade(opChains);
}
function test_upgrade_superchainConfigMismatch_reverts() public {
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
// Set the superchainConfig to a different address in the OptimismPortal2 contract.
vm.store(
address(optimismPortal2),
bytes32(ForgeArtifacts.getSlot("OptimismPortal2", "superchainConfig").slot),
bytes32(abi.encode(bob))
);
vm.expectRevert(
abi.encodeWithSelector(OPContractsManager.SuperchainConfigMismatch.selector, address(systemConfig))
);
DelegateCaller(upgrader).dcForward(address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains)));
}
}
contract OPContractsManager_AddGameType_Test is Test { contract OPContractsManager_AddGameType_Test is Test {
OPContractsManager internal opcm; OPContractsManager internal opcm;
......
...@@ -99,13 +99,21 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init { ...@@ -99,13 +99,21 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init {
uint256 cfgStartBlock = deploy.cfg().systemConfigStartBlock(); uint256 cfgStartBlock = deploy.cfg().systemConfigStartBlock();
assertEq(systemConfig.startBlock(), (cfgStartBlock == 0 ? block.number : cfgStartBlock)); assertEq(systemConfig.startBlock(), (cfgStartBlock == 0 ? block.number : cfgStartBlock));
assertEq(address(systemConfig.batchInbox()), address(batchInbox)); assertEq(address(systemConfig.batchInbox()), address(batchInbox));
// Check addresses
// Check address getters both for the single contract getter and the struct getter
ISystemConfig.Addresses memory addrs = systemConfig.getAddresses();
assertEq(address(systemConfig.l1CrossDomainMessenger()), address(l1CrossDomainMessenger)); assertEq(address(systemConfig.l1CrossDomainMessenger()), address(l1CrossDomainMessenger));
assertEq(addrs.l1CrossDomainMessenger, address(l1CrossDomainMessenger));
assertEq(address(systemConfig.l1ERC721Bridge()), address(l1ERC721Bridge)); assertEq(address(systemConfig.l1ERC721Bridge()), address(l1ERC721Bridge));
assertEq(addrs.l1ERC721Bridge, address(l1ERC721Bridge));
assertEq(address(systemConfig.l1StandardBridge()), address(l1StandardBridge)); assertEq(address(systemConfig.l1StandardBridge()), address(l1StandardBridge));
assertEq(addrs.l1StandardBridge, address(l1StandardBridge));
assertEq(address(systemConfig.disputeGameFactory()), address(disputeGameFactory)); assertEq(address(systemConfig.disputeGameFactory()), address(disputeGameFactory));
assertEq(addrs.disputeGameFactory, address(disputeGameFactory));
assertEq(address(systemConfig.optimismPortal()), address(optimismPortal2)); assertEq(address(systemConfig.optimismPortal()), address(optimismPortal2));
assertEq(addrs.optimismPortal, address(optimismPortal2));
assertEq(address(systemConfig.optimismMintableERC20Factory()), address(optimismMintableERC20Factory)); assertEq(address(systemConfig.optimismMintableERC20Factory()), address(optimismMintableERC20Factory));
assertEq(addrs.optimismMintableERC20Factory, address(optimismMintableERC20Factory));
} }
} }
...@@ -281,8 +289,6 @@ contract SystemConfig_Init_ResourceConfig is SystemConfig_Init { ...@@ -281,8 +289,6 @@ contract SystemConfig_Init_ResourceConfig is SystemConfig_Init {
) )
internal internal
{ {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Init_ResourceConfig: initialize() interface differs from mainnet.");
// Wipe out the initialized slot so the proxy can be initialized again // Wipe out the initialized slot so the proxy can be initialized again
vm.store(address(systemConfig), bytes32(0), bytes32(0)); vm.store(address(systemConfig), bytes32(0), bytes32(0));
// Fetch the current gas limit // Fetch the current gas limit
...@@ -325,16 +331,12 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -325,16 +331,12 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @notice Ensures that `setGasConfig` reverts if version byte is set. /// @notice Ensures that `setGasConfig` reverts if version byte is set.
function test_setGasConfig_badValues_reverts() external { function test_setGasConfig_badValues_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'scalar exceeds max' check DNE on op mainnet");
vm.prank(systemConfig.owner()); vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: scalar exceeds max."); vm.expectRevert("SystemConfig: scalar exceeds max.");
systemConfig.setGasConfig({ _overhead: 0, _scalar: type(uint256).max }); systemConfig.setGasConfig({ _overhead: 0, _scalar: type(uint256).max });
} }
function test_setGasConfigEcotone_notOwner_reverts() external { function test_setGasConfigEcotone_notOwner_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setGasConfigEcotone' method DNE on op mainnet");
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
systemConfig.setGasConfigEcotone({ _basefeeScalar: 0, _blobbasefeeScalar: 0 }); systemConfig.setGasConfigEcotone({ _basefeeScalar: 0, _blobbasefeeScalar: 0 });
} }
...@@ -369,16 +371,12 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -369,16 +371,12 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` reverts if the caller is not the owner. /// @dev Tests that `setEIP1559Params` reverts if the caller is not the owner.
function test_setEIP1559Params_notOwner_reverts(uint32 _denominator, uint32 _elasticity) external { function test_setEIP1559Params_notOwner_reverts(uint32 _denominator, uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
systemConfig.setEIP1559Params({ _denominator: _denominator, _elasticity: _elasticity }); systemConfig.setEIP1559Params({ _denominator: _denominator, _elasticity: _elasticity });
} }
/// @dev Tests that `setEIP1559Params` reverts if the denominator is zero. /// @dev Tests that `setEIP1559Params` reverts if the denominator is zero.
function test_setEIP1559Params_zeroDenominator_reverts(uint32 _elasticity) external { function test_setEIP1559Params_zeroDenominator_reverts(uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
vm.prank(systemConfig.owner()); vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: denominator must be >= 1"); vm.expectRevert("SystemConfig: denominator must be >= 1");
systemConfig.setEIP1559Params({ _denominator: 0, _elasticity: _elasticity }); systemConfig.setEIP1559Params({ _denominator: 0, _elasticity: _elasticity });
...@@ -386,8 +384,6 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -386,8 +384,6 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` reverts if the elasticity is zero. /// @dev Tests that `setEIP1559Params` reverts if the elasticity is zero.
function test_setEIP1559Params_zeroElasticity_reverts(uint32 _denominator) external { function test_setEIP1559Params_zeroElasticity_reverts(uint32 _denominator) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
_denominator = uint32(bound(_denominator, 1, type(uint32).max)); _denominator = uint32(bound(_denominator, 1, type(uint32).max));
vm.prank(systemConfig.owner()); vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: elasticity must be >= 1"); vm.expectRevert("SystemConfig: elasticity must be >= 1");
...@@ -420,8 +416,6 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -420,8 +416,6 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
} }
function testFuzz_setGasConfigEcotone_succeeds(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external { function testFuzz_setGasConfigEcotone_succeeds(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setGasConfigEcotone' method DNE on op mainnet");
bytes32 encoded = bytes32 encoded =
ffi.encodeScalarEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar }); ffi.encodeScalarEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar });
...@@ -465,8 +459,6 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -465,8 +459,6 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` updates the EIP1559 parameters successfully. /// @dev Tests that `setEIP1559Params` updates the EIP1559 parameters successfully.
function testFuzz_setEIP1559Params_succeeds(uint32 _denominator, uint32 _elasticity) external { function testFuzz_setEIP1559Params_succeeds(uint32 _denominator, uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
_denominator = uint32(bound(_denominator, 2, type(uint32).max)); _denominator = uint32(bound(_denominator, 2, type(uint32).max));
_elasticity = uint32(bound(_elasticity, 2, type(uint32).max)); _elasticity = uint32(bound(_elasticity, 2, type(uint32).max));
......
...@@ -29,3 +29,24 @@ contract Reverter { ...@@ -29,3 +29,24 @@ contract Reverter {
revert(); revert();
} }
} }
/// @dev Can be etched in to any address to test making a delegatecall from that address.
contract DelegateCaller {
function dcForward(address _target, bytes memory _data) external {
assembly {
// Perform the delegatecall, make sure to pass all available gas.
let success := delegatecall(gas(), _target, add(_data, 0x20), mload(_data), 0x0, 0x0)
// Copy returndata into memory at 0x0....returndatasize. Note that this *will*
// overwrite the calldata that we just copied into memory but that doesn't really
// matter because we'll be returning in a second anyway.
returndatacopy(0x0, 0x0, returndatasize())
// Success == 0 means a revert. We'll revert too and pass the data up.
if iszero(success) { revert(0x0, returndatasize()) }
// Otherwise we'll just return and pass the data up.
return(0x0, returndatasize())
}
}
}
...@@ -37,6 +37,12 @@ contract CommonTest is Test, Setup, Events { ...@@ -37,6 +37,12 @@ contract CommonTest is Test, Setup, Events {
address customGasToken; address customGasToken;
bool useInteropOverride; bool useInteropOverride;
/// @dev This value is only used in forked tests. During forked tests, the default is to perform the upgrade before
/// running the tests.
/// This value should only be set to false in forked tests which are specifically testing the upgrade path
/// itself, rather than simply ensuring that the tests pass after the upgrade.
bool useUpgradedFork = true;
ERC20 L1Token; ERC20 L1Token;
ERC20 BadL1Token; ERC20 BadL1Token;
IOptimismMintableERC20Full L2Token; IOptimismMintableERC20Full L2Token;
...@@ -65,6 +71,9 @@ contract CommonTest is Test, Setup, Events { ...@@ -65,6 +71,9 @@ contract CommonTest is Test, Setup, Events {
if (useInteropOverride) { if (useInteropOverride) {
deploy.cfg().setUseInterop(true); deploy.cfg().setUseInterop(true);
} }
if (useUpgradedFork) {
deploy.cfg().setUseUpgradedFork(true);
}
if (isForkTest()) { if (isForkTest()) {
// Skip any test suite which uses a nonstandard configuration. // Skip any test suite which uses a nonstandard configuration.
...@@ -166,34 +175,42 @@ contract CommonTest is Test, Setup, Events { ...@@ -166,34 +175,42 @@ contract CommonTest is Test, Setup, Events {
emit TransactionDeposited(_from, _to, 0, abi.encodePacked(_mint, _value, _gasLimit, _isCreation, _data)); emit TransactionDeposited(_from, _to, 0, abi.encodePacked(_mint, _value, _gasLimit, _isCreation, _data));
} }
function enableAltDA() public { /// @dev Checks if the system has already been deployed, based off of the heuristic that alice and bob have not been
// Check if the system has already been deployed, based off of the heuristic that alice and bob have not been /// set by the `setUp` function yet.
// set by the `setUp` function yet. function _checkNotDeployed(string memory _feature) internal view {
if (!(alice == address(0) && bob == address(0))) { if (alice != address(0) && bob != address(0)) {
revert("CommonTest: Cannot enable altda after deployment. Consider overriding `setUp`."); revert(
string.concat("CommonTest: Cannot enable ", _feature, " after deployment. Consider overriding `setUp`.")
);
}
console.log("CommonTest: enabling", _feature);
} }
/// @dev Enables alternative data availability mode for testing
function enableAltDA() public {
_checkNotDeployed("altda");
useAltDAOverride = true; useAltDAOverride = true;
} }
/// @dev Sets a custom gas token for testing. Cannot be ETH.
function enableCustomGasToken(address _token) public { function enableCustomGasToken(address _token) public {
// Check if the system has already been deployed, based off of the heuristic that alice and bob have not been _checkNotDeployed("custom gas token");
// set by the `setUp` function yet.
if (!(alice == address(0) && bob == address(0))) {
revert("CommonTest: Cannot enable custom gas token after deployment. Consider overriding `setUp`.");
}
require(_token != Constants.ETHER, "CommonTest: Cannot set gas token to ETHER"); require(_token != Constants.ETHER, "CommonTest: Cannot set gas token to ETHER");
customGasToken = _token; customGasToken = _token;
} }
/// @dev Enables interoperability mode for testing
function enableInterop() public { function enableInterop() public {
// Check if the system has already been deployed, based off of the heuristic that alice and bob have not been _checkNotDeployed("interop");
// set by the `setUp` function yet. useInteropOverride = true;
if (!(alice == address(0) && bob == address(0))) {
revert("CommonTest: Cannot enable interop after deployment. Consider overriding `setUp`.");
} }
useInteropOverride = true; /// @dev Disables upgrade mode for testing. By default the fork testing env will be upgraded to the latest
/// implementation. This can be used to disable the upgrade which, is useful for tests targeting the upgrade
/// process itself.
function disableUpgradedFork() public {
_checkNotDeployed("non-upgraded fork");
useUpgradedFork = false;
} }
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
import { console2 as console } from "forge-std/console2.sol";
// Testing // Testing
import { stdJson } from "forge-std/StdJson.sol"; import { stdToml } from "forge-std/StdToml.sol";
import { DelegateCaller } from "test/mocks/Callers.sol";
// Scripts // Scripts
import { Deployer } from "scripts/deploy/Deployer.sol"; import { Deployer } from "scripts/deploy/Deployer.sol";
...@@ -16,6 +19,9 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; ...@@ -16,6 +19,9 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; import { IAddressManager } from "interfaces/legacy/IAddressManager.sol";
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
/// @title ForkLive /// @title ForkLive
/// @notice This script is called by Setup.sol as a preparation step for the foundry test suite, and is run as an /// @notice This script is called by Setup.sol as a preparation step for the foundry test suite, and is run as an
...@@ -27,7 +33,7 @@ import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; ...@@ -27,7 +33,7 @@ import { IAddressManager } from "interfaces/legacy/IAddressManager.sol";
/// superchain-registry. /// superchain-registry.
/// This contract must not have constructor logic because it is set into state using `etch`. /// This contract must not have constructor logic because it is set into state using `etch`.
contract ForkLive is Deployer { contract ForkLive is Deployer {
using stdJson for string; using stdToml for string;
/// @notice Returns the base chain name to use for forking /// @notice Returns the base chain name to use for forking
/// @return The base chain name as a string /// @return The base chain name as a string
...@@ -52,6 +58,12 @@ contract ForkLive is Deployer { ...@@ -52,6 +58,12 @@ contract ForkLive is Deployer {
// Now deploy the updated OPCM and implementations of the contracts // Now deploy the updated OPCM and implementations of the contracts
_deployNewImplementations(); _deployNewImplementations();
// Now upgrade the contracts (if the config is set to do so)
if (cfg.useUpgradedFork()) {
console.log("ForkLive: upgrading");
_upgrade();
}
} }
/// @notice Reads the superchain config files and saves the addresses to disk. /// @notice Reads the superchain config files and saves the addresses to disk.
...@@ -67,6 +79,8 @@ contract ForkLive is Deployer { ...@@ -67,6 +79,8 @@ contract ForkLive is Deployer {
string memory superchainToml = vm.readFile(string.concat(superchainBasePath, baseChain(), "/superchain.toml")); string memory superchainToml = vm.readFile(string.concat(superchainBasePath, baseChain(), "/superchain.toml"));
string memory opToml = vm.readFile(string.concat(superchainBasePath, baseChain(), "/", opChain(), ".toml")); string memory opToml = vm.readFile(string.concat(superchainBasePath, baseChain(), "/", opChain(), ".toml"));
// Slightly hacky, we encode the uint chainId as an address to save it in Artifacts
artifacts.save("L2ChainId", address(uint160(vm.parseTomlUint(opToml, ".chain_id"))));
// Superchain shared contracts // Superchain shared contracts
saveProxyAndImpl("SuperchainConfig", superchainToml, ".superchain_config_addr"); saveProxyAndImpl("SuperchainConfig", superchainToml, ".superchain_config_addr");
saveProxyAndImpl("ProtocolVersions", superchainToml, ".protocol_versions_addr"); saveProxyAndImpl("ProtocolVersions", superchainToml, ".protocol_versions_addr");
...@@ -99,11 +113,17 @@ contract ForkLive is Deployer { ...@@ -99,11 +113,17 @@ contract ForkLive is Deployer {
saveProxyAndImpl("DelayedWETH", opToml, ".addresses.DelayedWETHProxy"); saveProxyAndImpl("DelayedWETH", opToml, ".addresses.DelayedWETHProxy");
// Fault proof non-proxied contracts // Fault proof non-proxied contracts
// For chains that don't have a permissionless game, we save the dispute game and WETH
// addresses as the zero address.
artifacts.save("PreimageOracle", vm.parseTomlAddress(opToml, ".addresses.PreimageOracle")); artifacts.save("PreimageOracle", vm.parseTomlAddress(opToml, ".addresses.PreimageOracle"));
artifacts.save("MipsSingleton", vm.parseTomlAddress(opToml, ".addresses.MIPS")); artifacts.save("MipsSingleton", vm.parseTomlAddress(opToml, ".addresses.MIPS"));
IDisputeGameFactory disputeGameFactory = IDisputeGameFactory disputeGameFactory =
IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy")); IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy"));
artifacts.save("FaultDisputeGame", vm.parseTomlAddress(opToml, ".addresses.FaultDisputeGame")); IFaultDisputeGame faultDisputeGame =
IFaultDisputeGame(opToml.readAddressOr(".addresses.FaultDisputeGame", address(0)));
artifacts.save("FaultDisputeGame", address(faultDisputeGame));
artifacts.save("PermissionlessDelayedWETHProxy", address(faultDisputeGame.weth()));
// The PermissionedDisputeGame and PermissionedDelayedWETHProxy are not listed in the registry for OP, so we // The PermissionedDisputeGame and PermissionedDelayedWETHProxy are not listed in the registry for OP, so we
// look it up onchain // look it up onchain
IFaultDisputeGame permissionedDisputeGame = IFaultDisputeGame permissionedDisputeGame =
...@@ -119,6 +139,25 @@ contract ForkLive is Deployer { ...@@ -119,6 +139,25 @@ contract ForkLive is Deployer {
deploy.deployImplementations({ _isInterop: false }); deploy.deployImplementations({ _isInterop: false });
} }
/// @notice Upgrades the contracts using the OPCM.
function _upgrade() internal {
OPContractsManager opcm = OPContractsManager(artifacts.mustGetAddress("OPContractsManager"));
ISystemConfig systemConfig = ISystemConfig(artifacts.mustGetAddress("SystemConfigProxy"));
IProxyAdmin proxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(systemConfig)));
address upgrader = proxyAdmin.owner();
vm.label(upgrader, "ProxyAdmin Owner");
OPContractsManager.OpChain[] memory opChains = new OPContractsManager.OpChain[](1);
opChains[0] = OPContractsManager.OpChain({ systemConfigProxy: systemConfig, proxyAdmin: proxyAdmin });
// TODO Migrate from DelegateCaller to a Safe to reduce risk of mocks not properly
// reflecting the production system.
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
DelegateCaller(upgrader).dcForward(address(opcm), abi.encodeCall(OPContractsManager.upgrade, (opChains)));
}
/// @notice Saves the proxy and implementation addresses for a contract name /// @notice Saves the proxy and implementation addresses for a contract name
/// @param _contractName The name of the contract to save /// @param _contractName The name of the contract to save
/// @param _tomlPath The path to the superchain config file /// @param _tomlPath The path to the superchain config file
......
...@@ -20,6 +20,9 @@ import { Preinstalls } from "src/libraries/Preinstalls.sol"; ...@@ -20,6 +20,9 @@ import { Preinstalls } from "src/libraries/Preinstalls.sol";
import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol";
import { Chains } from "scripts/libraries/Chains.sol"; import { Chains } from "scripts/libraries/Chains.sol";
// Contracts (TODO: move to interfaces)
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
// Interfaces // Interfaces
import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol";
import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol"; import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol";
...@@ -51,6 +54,8 @@ import { IWETH98 } from "interfaces/universal/IWETH98.sol"; ...@@ -51,6 +54,8 @@ import { IWETH98 } from "interfaces/universal/IWETH98.sol";
import { IGovernanceToken } from "interfaces/governance/IGovernanceToken.sol"; import { IGovernanceToken } from "interfaces/governance/IGovernanceToken.sol";
import { ILegacyMessagePasser } from "interfaces/legacy/ILegacyMessagePasser.sol"; import { ILegacyMessagePasser } from "interfaces/legacy/ILegacyMessagePasser.sol";
import { ISuperchainTokenBridge } from "interfaces/L2/ISuperchainTokenBridge.sol"; import { ISuperchainTokenBridge } from "interfaces/L2/ISuperchainTokenBridge.sol";
import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol";
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
/// @title Setup /// @title Setup
/// @dev This contact is responsible for setting up the contracts in state. It currently /// @dev This contact is responsible for setting up the contracts in state. It currently
...@@ -83,10 +88,15 @@ contract Setup { ...@@ -83,10 +88,15 @@ contract Setup {
/// @notice Allows users of Setup to override what L2 genesis is being created. /// @notice Allows users of Setup to override what L2 genesis is being created.
Fork l2Fork = LATEST_FORK; Fork l2Fork = LATEST_FORK;
// L1 contracts // L1 contracts - dispute
IDisputeGameFactory disputeGameFactory; IDisputeGameFactory disputeGameFactory;
IAnchorStateRegistry anchorStateRegistry; IAnchorStateRegistry anchorStateRegistry;
IFaultDisputeGame faultDisputeGame;
IDelayedWETH delayedWeth; IDelayedWETH delayedWeth;
IPermissionedDisputeGame permissionedDisputeGame;
IDelayedWETH delayedWETHPermissionedGameProxy;
// L1 contracts - core
IOptimismPortal2 optimismPortal2; IOptimismPortal2 optimismPortal2;
ISystemConfig systemConfig; ISystemConfig systemConfig;
IL1StandardBridge l1StandardBridge; IL1StandardBridge l1StandardBridge;
...@@ -97,6 +107,7 @@ contract Setup { ...@@ -97,6 +107,7 @@ contract Setup {
IProtocolVersions protocolVersions; IProtocolVersions protocolVersions;
ISuperchainConfig superchainConfig; ISuperchainConfig superchainConfig;
IDataAvailabilityChallenge dataAvailabilityChallenge; IDataAvailabilityChallenge dataAvailabilityChallenge;
OPContractsManager opcm;
// L2 contracts // L2 contracts
IL2CrossDomainMessenger l2CrossDomainMessenger = IL2CrossDomainMessenger l2CrossDomainMessenger =
...@@ -218,6 +229,7 @@ contract Setup { ...@@ -218,6 +229,7 @@ contract Setup {
anchorStateRegistry = IAnchorStateRegistry(artifacts.mustGetAddress("AnchorStateRegistryProxy")); anchorStateRegistry = IAnchorStateRegistry(artifacts.mustGetAddress("AnchorStateRegistryProxy"));
disputeGameFactory = IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy")); disputeGameFactory = IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy"));
delayedWeth = IDelayedWETH(artifacts.mustGetAddress("DelayedWETHProxy")); delayedWeth = IDelayedWETH(artifacts.mustGetAddress("DelayedWETHProxy"));
opcm = OPContractsManager(artifacts.mustGetAddress("OPContractsManager"));
if (deploy.cfg().useAltDA()) { if (deploy.cfg().useAltDA()) {
dataAvailabilityChallenge = dataAvailabilityChallenge =
......
...@@ -391,6 +391,7 @@ contract Specification_Test is CommonTest { ...@@ -391,6 +391,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "SystemConfig", _sel: _getSel("basefeeScalar()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("basefeeScalar()") });
_addSpec({ _name: "SystemConfig", _sel: _getSel("blobbasefeeScalar()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("blobbasefeeScalar()") });
_addSpec({ _name: "SystemConfig", _sel: _getSel("maximumGasLimit()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("maximumGasLimit()") });
_addSpec({ _name: "SystemConfig", _sel: _getSel("getAddresses()") });
// SystemConfigInterop // SystemConfigInterop
_addSpec({ _name: "SystemConfigInterop", _sel: _getSel("UNSAFE_BLOCK_SIGNER_SLOT()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("UNSAFE_BLOCK_SIGNER_SLOT()") });
...@@ -470,6 +471,7 @@ contract Specification_Test is CommonTest { ...@@ -470,6 +471,7 @@ contract Specification_Test is CommonTest {
_auth: Role.DEPENDENCYMANAGER _auth: Role.DEPENDENCYMANAGER
}); });
_addSpec({ _name: "SystemConfigInterop", _sel: _getSel("dependencyManager()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("dependencyManager()") });
_addSpec({ _name: "SystemConfigInterop", _sel: _getSel("getAddresses()") });
// ProxyAdmin // ProxyAdmin
_addSpec({ _name: "ProxyAdmin", _sel: _getSel("addressManager()") }); _addSpec({ _name: "ProxyAdmin", _sel: _getSel("addressManager()") });
...@@ -783,6 +785,7 @@ contract Specification_Test is CommonTest { ...@@ -783,6 +785,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.blueprints.selector }); _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.blueprints.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector }); _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.implementations.selector }); _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.implementations.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.upgrade.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.addGameType.selector }); _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.addGameType.selector });
// OPContractsManagerInterop // OPContractsManagerInterop
...@@ -794,6 +797,7 @@ contract Specification_Test is CommonTest { ...@@ -794,6 +797,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.blueprints.selector }); _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.blueprints.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector }); _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.implementations.selector }); _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.implementations.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.upgrade.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.addGameType.selector }); _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.addGameType.selector });
// DeputyGuardianModule // DeputyGuardianModule
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment