diff --git a/.circleci/config.yml b/.circleci/config.yml index c0f73eef0..d702488d0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -236,7 +236,21 @@ jobs: steps: - simulate: task: "/eth/ink-002-set-respected-game-type" + + just_simulate_ink_sep_fp_holocene_pectra_upgrade: + docker: + - image: <> + steps: + - simulate_nested: + task: "/sep/ink-001-fp-holocene-pectra-upgrade" + just_simulate_ink_sep_holocene_system_config_upgrade: + docker: + - image: <> + steps: + - simulate_nested: + task: "/sep/ink-002-holocene-system-config-upgrade" + just_simulate_zora_002_fp_upgrade: docker: - image: <> @@ -359,5 +373,6 @@ workflows: - just_simulate_sc_rehearsal_4 - just_simulate_ink_respected_game_type # sepolia + - just_simulate_ink_sep_fp_holocene_pectra_upgrade + - just_simulate_ink_sep_holocene_system_config_upgrade - just_simulate_zora_002_fp_upgrade - diff --git a/tasks/sep/ink-001-fp-holocene-pectra-upgrade/.env b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/.env new file mode 100644 index 000000000..1c44a212f --- /dev/null +++ b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/.env @@ -0,0 +1,6 @@ +ETH_RPC_URL="https://ethereum-sepolia.publicnode.com" +COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 +FOUNDATION_SAFE=0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B +OWNER_SAFE=0x1Eb2fFc903729a0F03966B917003800b145F56E2 +SAFE_NONCE="" +SIMULATE_WITHOUT_LEDGER=0 # set to 1 during development diff --git a/tasks/sep/ink-001-fp-holocene-pectra-upgrade/NestedSignFromJson.s.sol b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/NestedSignFromJson.s.sol new file mode 100644 index 000000000..e6e2ceaa7 --- /dev/null +++ b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/NestedSignFromJson.s.sol @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import {NestedSignFromJson as OriginalNestedSignFromJson} from "script/NestedSignFromJson.s.sol"; +import {SuperchainRegistry} from "script/verification/Verification.s.sol"; +import {BytecodeComparison} from "src/libraries/BytecodeComparison.sol"; +import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; +import {Types} from "@eth-optimism-bedrock/scripts/libraries/Types.sol"; +import {console2 as console} from "forge-std/console2.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {LibString} from "solady/utils/LibString.sol"; +import {GnosisSafe} from "safe-contracts/GnosisSafe.sol"; +import {Vm, VmSafe} from "forge-std/Vm.sol"; +import "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; +import {DisputeGameFactory} from "@eth-optimism-bedrock/src/dispute/DisputeGameFactory.sol"; +import {FaultDisputeGame} from "@eth-optimism-bedrock/src/dispute/FaultDisputeGame.sol"; +import {PermissionedDisputeGame} from "@eth-optimism-bedrock/src/dispute/PermissionedDisputeGame.sol"; +import {MIPS} from "@eth-optimism-bedrock/src/cannon/MIPS.sol"; +import {ISemver} from "@eth-optimism-bedrock/interfaces/universal/ISemver.sol"; + +contract NestedSignFromJson is OriginalNestedSignFromJson, SuperchainRegistry { + using LibString for string; + + /// Dynamically assigned to the addresses in setUp + DisputeGameFactory dgfProxy; + address newMips; + address oracle; + uint256 chainId; + + //DisputeGameFactory constant dgfProxy = DisputeGameFactory(0x860e626c700AF381133D9f4aF31412A2d1DB3D5d); + address constant livenessGuard = 0xc26977310bC89DAee5823C2e2a73195E85382cC7; + bytes32 constant absolutePrestate = 0x03dfa3b3ac66e8fae9f338824237ebacff616df928cf7dada0e14be2531bc1f4; + //address constant newMips = 0x69470D6970Cd2A006b84B1d4d70179c892cFCE01; + //address constant oracle = 0x92240135b46fc1142dA181f550aE8f595B858854; + string constant gameVersion = "1.3.1"; + //uint256 constant chainId = 763373; + + // Safe contract for this task. + GnosisSafe securityCouncilSafe = GnosisSafe(payable(vm.envAddress("COUNCIL_SAFE"))); + GnosisSafe fndSafe = GnosisSafe(payable(vm.envAddress("FOUNDATION_SAFE"))); + GnosisSafe ownerSafe = GnosisSafe(payable(vm.envAddress("OWNER_SAFE"))); + + FaultDisputeGame faultDisputeGame; + PermissionedDisputeGame permissionedDisputeGame; + + constructor() SuperchainRegistry("sepolia", "ink", "v1.8.0-rc.4") {} + + function setUp() public { + + console.log("Fetching DisputeGameFactory address..."); + dgfProxy = DisputeGameFactory(proxies.DisputeGameFactory); + console.log("DisputeGameFactory Proxy Address:", address(dgfProxy)); + + console.log("Fetching newMips address..."); + newMips = standardVersions.MIPS.Address; + console.log("Fetched newMips Address:", newMips); + + console.log("Fetching oracle address..."); + oracle = standardVersions.PreimageOracle.Address; + console.log("Fetched Oracle Address:", oracle); + + console.log("Fetching chainId..."); + chainId = chainConfig.chainId; + console.log("Fetched Chain ID:", chainId); + + string memory inputJson; + string memory path = "/tasks/sep/ink-001-fp-holocene-pectra-upgrade/input.json"; + try vm.readFile(string.concat(vm.projectRoot(), path)) returns (string memory data) { + inputJson = data; + } catch { + revert(string.concat("Failed to read ", path)); + } + + permissionedDisputeGame = PermissionedDisputeGame(stdJson.readAddress(inputJson, "$.transactions[0].contractInputsValues._impl")); + faultDisputeGame = FaultDisputeGame(stdJson.readAddress(inputJson, "$.transactions[1].contractInputsValues._impl")); + } + + function getCodeExceptions() internal view override returns (address[] memory) { + // Safe owners will appear in storage in the LivenessGuard when added, and they are allowed + // to have code AND to have no code. + address[] memory securityCouncilSafeOwners = securityCouncilSafe.getOwners(); + + // To make sure we probably handle all signers whether or not they have code, first we count + // the number of signers that have no code. + uint256 numberOfSafeSignersWithNoCode; + for (uint256 i = 0; i < securityCouncilSafeOwners.length; i++) { + if (securityCouncilSafeOwners[i].code.length == 0) { + numberOfSafeSignersWithNoCode++; + } + } + + // Then we extract those EOA addresses into a dedicated array. + uint256 trackedSignersWithNoCode; + address[] memory safeSignersWithNoCode = new address[](numberOfSafeSignersWithNoCode); + for (uint256 i = 0; i < securityCouncilSafeOwners.length; i++) { + if (securityCouncilSafeOwners[i].code.length == 0) { + safeSignersWithNoCode[trackedSignersWithNoCode] = securityCouncilSafeOwners[i]; + trackedSignersWithNoCode++; + } + } + + // Here we add the standard (non Safe signer) exceptions. + address[] memory shouldHaveCodeExceptions = new address[](0 + numberOfSafeSignersWithNoCode); + + + // And finally, we append the Safe signer exceptions. + for (uint256 i = 0; i < safeSignersWithNoCode.length; i++) { + shouldHaveCodeExceptions[0 + i] = safeSignersWithNoCode[i]; + } + + return shouldHaveCodeExceptions; + } + + function getAllowedStorageAccess() internal view override returns (address[] memory allowed) { + allowed = new address[](5); + allowed[0] = address(dgfProxy); + allowed[1] = address(ownerSafe); + allowed[2] = address(securityCouncilSafe); + allowed[3] = address(fndSafe); + allowed[4] = livenessGuard; + } + + function _postCheck(Vm.AccountAccess[] memory accesses, Simulation.Payload memory) internal view override { + console.log("Running post-deploy assertions"); + checkStateDiff(accesses); + checkDGFProxyAndGames(); + checkMips(); + console.log("All assertions passed!"); + } + + function checkDGFProxyAndGames() internal view { + console.log("check dispute game implementations"); + require(address(faultDisputeGame) == address(dgfProxy.gameImpls(GameTypes.CANNON)), "dgf-100"); + require(address(permissionedDisputeGame) == address(dgfProxy.gameImpls(GameTypes.PERMISSIONED_CANNON)), "dgf-200"); + + require(faultDisputeGame.version().eq(gameVersion), "game-100"); + require(permissionedDisputeGame.version().eq(gameVersion), "game-200"); + + require(faultDisputeGame.absolutePrestate().raw() == absolutePrestate, "game-300"); + require(permissionedDisputeGame.absolutePrestate().raw() == absolutePrestate, "game-400"); + + require(address(faultDisputeGame.vm()) == newMips, "game-500"); + require(address(permissionedDisputeGame.vm()) == newMips, "game-600"); + + require(faultDisputeGame.l2ChainId() == chainId, "game-700"); + require(permissionedDisputeGame.l2ChainId() == chainId, "game-800"); + } + + function checkMips() internal view{ + console.log("check MIPS"); + + require(newMips.code.length != 0, "MIPS-100"); + vm.assertEq(ISemver(newMips).version(), "1.2.1"); + require(address(MIPS(newMips).oracle()) == oracle, "MIPS-200"); + } + +} diff --git a/tasks/sep/ink-001-fp-holocene-pectra-upgrade/OVERVIEW.md b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/OVERVIEW.md new file mode 100644 index 000000000..7ee4bf904 --- /dev/null +++ b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/OVERVIEW.md @@ -0,0 +1,38 @@ +# Holocene Hardfork - Proof Contract Upgrades +Upgrades the `MIPS.sol`, `FaultDisputeGame.sol`, and `PermissionedDisputeGame.sol` contracts for Holocene. + +The batch will be executed on chain ID `11155111`, and contains `2` transactions. + +## Tx #1: Upgrade `PERMISSIONED_CANNON` game type in `DisputeGameFactory` +Upgrades the `PERMISSIONED_CANNON` game type to the new Holocene deployment, with an updated version of `op-program` as the absolute prestate hash. + +**Function Signature:** `setImplementation(uint32,address)` + +**To:** `0x860e626c700AF381133D9f4aF31412A2d1DB3D5d` + +**Value:** `0 WEI` + +**Raw Input Data:** `0x14f6b1a300000000000000000000000000000000000000000000000000000000000000010000000000000000000000004a0973e21274c4d939c84ac8b98d4308b7c9e249` + +### Inputs +**_gameType:** `1` + +**_impl:** `0x4A0973E21274c4d939c84ac8B98D4308b7c9E249` + + +## Tx #2: Upgrade `CANNON` game type in `DisputeGameFactory` +Upgrades the `CANNON` game type to the new Holocene deployment, with an updated version of `op-program` as the absolute prestate hash. + +**Function Signature:** `setImplementation(uint32,address)` + +**To:** `0x860e626c700AF381133D9f4aF31412A2d1DB3D5d` + +**Value:** `0 WEI` + +**Raw Input Data:** `0x14f6b1a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e562e81d08cd5e212661ef961b4069456e426c56` + +### Inputs +**_gameType:** `0` + +**_impl:** `0xe562e81d08cD5e212661EF961B4069456e426C56` + diff --git a/tasks/sep/ink-001-fp-holocene-pectra-upgrade/README.md b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/README.md new file mode 100644 index 000000000..d2b958a52 --- /dev/null +++ b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/README.md @@ -0,0 +1,44 @@ +# Ink Sepolia Holocene Hardfork + L1 Pectra Support Upgrade + +Status: READY TO SIGN + +## Objective + +Upgrades the Fault Proof contracts for the Holocene hardfork and utilizes the absolute prestate `0x03dfa3b3ac66e8fae9f338824237ebacff616df928cf7dada0e14be2531bc1f4` that enables L1 pectra support. + +The proposal was: + +- [X] [Posted](https://gov.optimism.io/t/upgrade-proposal-11-holocene-network-upgrade/9313) on the governance forum. +- [X] [Approved](https://vote.optimism.io/proposals/20127877429053636874064552098716749508236019236440427814457915785398876262515) by Token House voting. +- [X] Not vetoed by the Citizens' house. +- [X] Executed on OP Mainnet. + +The governance proposal should be treated as the source of truth and used to verify the correctness of the onchain operations. + +This upgrades the Fault Proof contracts in the +[op-contracts/v1.8.0-rc.4](https://github.com/ethereum-optimism/optimism/tree/op-contracts/v1.8.0-rc.4) release. + +## Pre-deployments + +- `MIPS` - `0x69470D6970Cd2A006b84B1d4d70179c892cFCE01` +- `FaultDisputeGame` - `0xe562e81d08cD5e212661EF961B4069456e426C56` +- `PermissionedDisputeGame` - `0x4A0973E21274c4d939c84ac8B98D4308b7c9E249` + +## Simulation + +Please see the "Simulating and Verifying the Transaction" instructions in [NESTED.md](../../../NESTED.md). +When simulating, ensure the logs say `Using script /your/path/to/superchain-ops/tasks//NestedSignFromJson.s.sol`. +This ensures all safety checks are run. If the default `NestedSignFromJson.s.sol` script is shown (without the full path), something is wrong and the safety checks will not run. + +## State Validation + +Please see the instructions for [validation](./VALIDATION.md). + +## Execution + +This upgrade +* Changes dispute game implementation of the `CANNON` and `PERMISSIONED_CANNON` game types to contain a `op-program` release for the Holocene hardfork, which contains + the Holocene fork implementation as well as a `ChainConfig` and `RollupConfig` for the L2 chain being upgraded. +* Upgrades `MIPS.sol` to support the `F_GETFD` syscall, required by the golang 1.22+ runtime. + +See the [overview](./OVERVIEW.md) and `input.json` bundle for more details. diff --git a/tasks/sep/ink-001-fp-holocene-pectra-upgrade/VALIDATION.md b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/VALIDATION.md new file mode 100644 index 000000000..996211960 --- /dev/null +++ b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/VALIDATION.md @@ -0,0 +1,43 @@ +# Validation + +This document can be used to validate the state diff resulting from the execution of the upgrade +transaction. + +For each contract listed in the state diff, please verify that no contracts or state changes shown in the Tenderly diff are missing from this document. Additionally, please verify that for each contract: + +- The following state changes (and none others) are made to that contract. This validates that no unexpected state changes occur. +- All addresses (in section headers and storage values) match the provided name, using the Etherscan and Superchain Registry links provided. This validates the bytecode deployed at the addresses contains the correct logic. +- All key values match the semantic meaning provided, which can be validated using the storage layout links provided. + +## State Changes + +### `0x860e626c700AF381133D9f4aF31412A2d1DB3D5d` (`DisputeGameFactoryProxy`) + +- **Key**: `0xffdfc1249c027f9191656349feb0761381bb32c9f557e01f419fd08754bf5a1b`
+ **Before**: `0x0000000000000000000000000000000000000000000000000000000000000000`
+ **After**: `0x000000000000000000000000e562e81d08cd5e212661ef961b4069456e426c56`
+ **Meaning**: Updates the CANNON game type implementation. You can verify which implementation is set using `cast call 0x860e626c700AF381133D9f4aF31412A2d1DB3D5d "gameImpls(uint32)(address)" 0`, where `0` is the [`CANNON` game type](https://github.com/ethereum-optimism/optimism/blob/op-contracts/v1.4.0/packages/contracts-bedrock/src/dispute/lib/Types.sol#L28). + Before this task has been executed, you will see that the returned address is `0x0000000000000000000000000000000000000000000000000000000000000000`, matching the "Before" value of this slot, demonstrating this slot is storing the address of the CANNON implementation. + +- **Key**: `0x4d5a9bd2e41301728d41c8e705190becb4e74abe869f75bdb405b63716a35f9e`
+ **Before**: `0x000000000000000000000000a8808360f7bc16da81938e5c29400d18bea651c4`
+ **After**: `0x0000000000000000000000004a0973e21274c4d939c84ac8b98d4308b7c9e249`
+ **Meaning**: Updates the PERMISSIONED_CANNON game type implementation. You can verify which implementation is set using `cast call 0x860e626c700AF381133D9f4aF31412A2d1DB3D5d "gameImpls(uint32)(address)" 1`, where `1` is the [`PERMISSIONED_CANNON` game type](https://github.com/ethereum-optimism/optimism/blob/op-contracts/v1.4.0/packages/contracts-bedrock/src/dispute/lib/Types.sol#L31). + Before this task has been executed, you will see that the returned address is `0x000000000000000000000000a8808360f7bc16da81938e5c29400d18bea651c4`, matching the "Before" value of this slot, demonstrating this slot is storing the address of the PERMISSIONED_CANNON implementation. + +## Verify Absolute Prestate +The following is based on the **op-program/v1.5.0-rc.1** https://github.com/ethereum-optimism/optimism/tree/op-program/v1.5.0-rc.1 +You can verify the absolute prestate `0x03dfa3b3ac66e8fae9f338824237ebacff616df928cf7dada0e14be2531bc1f4` by running the following command in the root of the monorepo: + +make reproducible-prestate + +You should expect the following output at the end of the command: + +- **Cannon Absolute prestate hash**: +`0x03dfa3b3ac66e8fae9f338824237ebacff616df928cf7dada0e14be2531bc1f4` + +- **Cannon64 Absolute prestate hash**: +`0x03f83792f653160f3274b0888e998077a27e1f74cb35bcb20d86021e769340aa` + +- **CannonInterop Absolute prestate hash**: +`0x03b7658b889796c1e372f57439e48eb46a5b008f6e6a4b7e5c8c2d3bddffa797` diff --git a/tasks/sep/ink-001-fp-holocene-pectra-upgrade/input.json b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/input.json new file mode 100644 index 000000000..57b93d768 --- /dev/null +++ b/tasks/sep/ink-001-fp-holocene-pectra-upgrade/input.json @@ -0,0 +1,67 @@ +{ + "chainId": 11155111, + "metadata": { + "name": "Holocene Hardfork - Proof Contract Upgrades", + "description": "Upgrades the `MIPS.sol`, `FaultDisputeGame.sol`, and `PermissionedDisputeGame.sol` contracts for Holocene." + }, + "transactions": [ + { + "metadata": { + "name": "Upgrade `PERMISSIONED_CANNON` game type in `DisputeGameFactory`", + "description": "Upgrades the `PERMISSIONED_CANNON` game type to the new Holocene deployment, with an updated version of `op-program` as the absolute prestate hash." + }, + "to": "0x860e626c700AF381133D9f4aF31412A2d1DB3D5d", + "value": "0x0", + "data": "0x14f6b1a300000000000000000000000000000000000000000000000000000000000000010000000000000000000000004a0973e21274c4d939c84ac8b98d4308b7c9e249", + "contractMethod": { + "type": "function", + "name": "setImplementation", + "inputs": [ + { + "name": "_gameType", + "type": "uint32" + }, + { + "name": "_impl", + "type": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + "contractInputsValues": { + "_gameType": "1", + "_impl": "0x4A0973E21274c4d939c84ac8B98D4308b7c9E249" + } + }, + { + "metadata": { + "name": "Upgrade `CANNON` game type in `DisputeGameFactory`", + "description": "Upgrades the `CANNON` game type to the new Holocene deployment, with an updated version of `op-program` as the absolute prestate hash." + }, + "to": "0x860e626c700AF381133D9f4aF31412A2d1DB3D5d", + "value": "0x0", + "data": "0x14f6b1a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e562e81d08cd5e212661ef961b4069456e426c56", + "contractMethod": { + "type": "function", + "name": "setImplementation", + "inputs": [ + { + "name": "_gameType", + "type": "uint32" + }, + { + "name": "_impl", + "type": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + "contractInputsValues": { + "_gameType": "0", + "_impl": "0xe562e81d08cD5e212661EF961B4069456e426C56" + } + } + ] +} diff --git a/tasks/sep/ink-002-holocene-system-config-upgrade/.env b/tasks/sep/ink-002-holocene-system-config-upgrade/.env new file mode 100644 index 000000000..4a4e63e8a --- /dev/null +++ b/tasks/sep/ink-002-holocene-system-config-upgrade/.env @@ -0,0 +1,4 @@ +ETH_RPC_URL="https://ethereum-sepolia.publicnode.com" +COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 +FOUNDATION_SAFE=0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B +OWNER_SAFE=0x1Eb2fFc903729a0F03966B917003800b145F56E2 diff --git a/tasks/sep/ink-002-holocene-system-config-upgrade/NestedSignFromJson.s.sol b/tasks/sep/ink-002-holocene-system-config-upgrade/NestedSignFromJson.s.sol new file mode 100644 index 000000000..e46193e6c --- /dev/null +++ b/tasks/sep/ink-002-holocene-system-config-upgrade/NestedSignFromJson.s.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import {console2 as console} from "forge-std/console2.sol"; +import {Vm} from "forge-std/Vm.sol"; +import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; +import {NestedSignFromJson as OriginalNestedSignFromJson} from "script/NestedSignFromJson.s.sol"; +import {CouncilFoundationNestedSign} from "script/verification/CouncilFoundationNestedSign.s.sol"; +import {VerificationBase, SuperchainRegistry} from "script/verification/Verification.s.sol"; +import {HoloceneSystemConfigUpgrade} from "script/verification/HoloceneSystemConfigUpgrade.s.sol"; + +contract NestedSignFromJson is OriginalNestedSignFromJson, CouncilFoundationNestedSign { + string constant l1ChainName = "sepolia"; + string constant release = "v1.8.0-rc.4"; + string[1] l2ChainNames = ["ink"]; + + HoloceneSystemConfigUpgrade[] sysCfgUpgrades; + + constructor() { + for (uint256 i = 0; i < l2ChainNames.length; i++) { + // Deploy a HoloceneSystemConfigUpgrade instance per chain, + // which each contains its own bindings to an individual chain's SuperchainRegistry data. + sysCfgUpgrades.push(new HoloceneSystemConfigUpgrade(l1ChainName, l2ChainNames[i], release)); + console.log(""); + console.log("Set up verification data for chain", l2ChainNames[i], "-", l1ChainName); + console.log("with SystemConfigProxy @", sysCfgUpgrades[i].systemConfigAddress()); + addAllowedStorageAccess(sysCfgUpgrades[i].systemConfigAddress()); + addCodeExceptions(sysCfgUpgrades[i].getCodeExceptions()); + } + } + + function _postCheck(Vm.AccountAccess[] memory accesses, Simulation.Payload memory) internal view override { + console.log("Running post-deploy assertions"); + checkStateDiff(accesses); + for (uint256 i = 0; i < sysCfgUpgrades.length; i++) { + console.log(""); + console.log("Running post-deploy assertions for chain", l2ChainNames[i], "-", l1ChainName); + sysCfgUpgrades[i].checkSystemConfigUpgrade(); + } + console.log("All assertions passed!"); + } + + function getAllowedStorageAccess() internal view override returns (address[] memory) { + return allowedStorageAccess; + } + + function getCodeExceptions() internal view override returns (address[] memory) { + return codeExceptions; + } +} diff --git a/tasks/sep/ink-002-holocene-system-config-upgrade/OVERVIEW.md b/tasks/sep/ink-002-holocene-system-config-upgrade/OVERVIEW.md new file mode 100644 index 000000000..e4b511006 --- /dev/null +++ b/tasks/sep/ink-002-holocene-system-config-upgrade/OVERVIEW.md @@ -0,0 +1,57 @@ +# Holocene Hardfork - SystemConfig Upgrade +Upgrades the `SystemConfig.sol` contract for Holocene. + +The batch will be executed on chain ID `11155111`, and contains `3` transactions. + +## Tx #1: ProxyAdmin.upgrade(SystemConfigProxy, StorageSetter) +Upgrades the `SystemConfigProxy`to the StorageSetter. + +**Function Signature:** `upgrade(address,address)` + +**To:** `0xd7dB319a49362b2328cf417a934300cCcB442C8d` + +**Value:** `0 WEI` + +**Raw Input Data:** `0x99a88ec400000000000000000000000005c993e60179f28bf649a2bb5b00b5f4283bd525000000000000000000000000d81f43edbcacb4c29a9ba38a13ee5d79278270cc` + +### Inputs +**_implementation:** `0xd81f43eDBCAcb4c29a9bA38a13Ee5d79278270cC` + +**_proxy:** `0x05C993e60179f28bF649a2Bb5b00b5F4283bD525` + + +## Tx #2: SystemConfigProxy.setBytes32(0,0) +Zeroes out the initialized state variable to allow reinitialization. + +**Function Signature:** `setBytes32(bytes32,bytes32)` + +**To:** `0x05C993e60179f28bF649a2Bb5b00b5F4283bD525` + +**Value:** `0 WEI` + +**Raw Input Data:** `0x4e91db0800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000` + +### Inputs +**_slot:** `0x0000000000000000000000000000000000000000000000000000000000000000` + +**_value:** `0x0000000000000000000000000000000000000000000000000000000000000000` + + +## Tx #3: ProxyAdmin.upgradeAndCall(SystemConfigProxy, SystemConfigImplementation, Initialize()) +Upgrades the SystemConfig to a new implementation and initializes it. + +**Function Signature:** `upgradeAndCall(address,address,bytes)` + +**To:** `0xd7dB319a49362b2328cf417a934300cCcB442C8d` + +**Value:** `0 WEI` + +**Raw Input Data:** `0x9623609d00000000000000000000000005c993e60179f28bf649a2bb5b00b5f4283bd52500000000000000000000000033b83e4c305c908b2fc181dda36e230213058d7d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000284db9040fa000000000000000000000000bea2bc852a160b8547273660e22f4f08c2fa9bbb00000000000000000000000000000000000000000000000000000000000c3c9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021e57c21530bc33f12ba96c9ddc135488365002f0000000000000000000000000000000000000000000000000000000001c9c38000000000000000000000000043ec5732581d3fae18abb7ce34a796e111dbd1a00000000000000000000000000000000000000000000000000000000001312d00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000004de1914f4f17ac234f5a5bc8a4072a231d44bf0000000000000000000000009fe1d3523f5342535e6e7770ed09ed85dbc1acc2000000000000000000000000d1c901bbd7796546a7ba2492e0e199911fae68c700000000000000000000000033f60714bbd74d62b66d79213c348614de51901c000000000000000000000000860e626c700af381133d9f4af31412a2d1db3d5d0000000000000000000000005c1d29c6c9c8b0800692acc95d700bcb4966a1d7000000000000000000000000686f782a749d1854f6fa3f948450f4c65c6674f0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000000000000000000000000000000000000` + +### Inputs +**_proxy:** `0x05C993e60179f28bF649a2Bb5b00b5F4283bD525` + +**_data:** `0xdb9040fa000000000000000000000000bea2bc852a160b8547273660e22f4f08c2fa9bbb00000000000000000000000000000000000000000000000000000000000c3c9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021e57c21530bc33f12ba96c9ddc135488365002f0000000000000000000000000000000000000000000000000000000001c9c38000000000000000000000000043ec5732581d3fae18abb7ce34a796e111dbd1a00000000000000000000000000000000000000000000000000000000001312d00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000004de1914f4f17ac234f5a5bc8a4072a231d44bf0000000000000000000000009fe1d3523f5342535e6e7770ed09ed85dbc1acc2000000000000000000000000d1c901bbd7796546a7ba2492e0e199911fae68c700000000000000000000000033f60714bbd74d62b66d79213c348614de51901c000000000000000000000000860e626c700af381133d9f4af31412a2d1db3d5d0000000000000000000000005c1d29c6c9c8b0800692acc95d700bcb4966a1d7000000000000000000000000686f782a749d1854f6fa3f948450f4c65c6674f0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` + +**_implementation:** `0x33b83E4C305c908B2Fc181dDa36e230213058d7d` + diff --git a/tasks/sep/ink-002-holocene-system-config-upgrade/README.md b/tasks/sep/ink-002-holocene-system-config-upgrade/README.md new file mode 100644 index 000000000..4bde625e5 --- /dev/null +++ b/tasks/sep/ink-002-holocene-system-config-upgrade/README.md @@ -0,0 +1,42 @@ +# Holocene Hardfork Upgrade - `SystemConfig` + +Status: READY TO SIGN + +## Objective + +Upgrades the `SystemConfig` for the Holocene hardfork. + +The proposal was: + +- [x] [Posted](https://gov.optimism.io/t/upgrade-proposal-11-holocene-network-upgrade/9313) on the governance forum. +- [x] [Approved](https://vote.optimism.io/proposals/20127877429053636874064552098716749508236019236440427814457915785398876262515) by Token House voting. +- [x] Not vetoed by the Citizens' house. +- [x] Executed on OP Mainnet. + +This upgrades the SystemConfig in the v1.8.0-rc.4 release. + +The governance proposal should be treated as the source of truth and used to verify the correctness of the onchain operations. + +This upgrades the `SystemConfig` in the +[v1.8.0-rc.4](https://github.com/ethereum-optimism/optimism/tree/v1.8.0-rc.4) release. + +## Pre-deployments + +- `SystemConfig` - `0x33b83E4C305c908B2Fc181dDa36e230213058d7d` + +## Simulation + +Please see the "Simulating and Verifying the Transaction" instructions in [NESTED.md](../../../NESTED.md). +When simulating, ensure the logs say `Using script /your/path/to/superchain-ops/tasks//NestedSignFromJson.s.sol`. +This ensures all safety checks are run. If the default `NestedSignFromJson.s.sol` script is shown (without the full path), something is wrong and the safety checks will not run. + +## State Validation + +Please see the instructions for [validation](./VALIDATION.md). + +## Execution + +This upgrade +* Changes the implementation of the `SystemConfig` to hold EIP-1559 parameters for the + +See the [overview](./OVERVIEW.md) and `input.json` bundle for more details. diff --git a/tasks/sep/ink-002-holocene-system-config-upgrade/VALIDATION.md b/tasks/sep/ink-002-holocene-system-config-upgrade/VALIDATION.md new file mode 100644 index 000000000..52559d509 --- /dev/null +++ b/tasks/sep/ink-002-holocene-system-config-upgrade/VALIDATION.md @@ -0,0 +1,19 @@ +# Validation + +This document can be used to validate the state diff resulting from the execution of the upgrade +transaction. + +For each contract listed in the state diff, please verify that no contracts or state changes shown in the Tenderly diff are missing from this document. Additionally, please verify that for each contract: + +- The following state changes (and none others) are made to that contract. This validates that no unexpected state changes occur. +- All addresses (in section headers and storage values) match the provided name, using the Etherscan and Superchain Registry links provided. This validates the bytecode deployed at the addresses contains the correct logic. +- All key values match the semantic meaning provided, which can be validated using the storage layout links provided. + +## State Changes + +### `0x05C993e60179f28bF649a2Bb5b00b5F4283bD525` (`SystemConfigProxy`) + +- **Key**: `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` + **Before**: `0x000000000000000000000000ccdd86d581e40fb5a1c77582247bc493b6c8b169` + **After**: `0x00000000000000000000000033b83e4c305c908b2fc181dda36e230213058d7d` + **Meaning**: Updates the `SystemConfig` proxy implementation. diff --git a/tasks/sep/ink-002-holocene-system-config-upgrade/input.json b/tasks/sep/ink-002-holocene-system-config-upgrade/input.json new file mode 100644 index 000000000..d29f31ed7 --- /dev/null +++ b/tasks/sep/ink-002-holocene-system-config-upgrade/input.json @@ -0,0 +1,105 @@ +{ + "chainId": 11155111, + "metadata": { + "name": "Holocene Hardfork - SystemConfig Upgrade", + "description": "Upgrades the `SystemConfig.sol` contract for Holocene." + }, + "transactions": [ + { + "metadata": { + "name": "ProxyAdmin.upgrade(SystemConfigProxy, StorageSetter)", + "description": "Upgrades the `SystemConfigProxy`to the StorageSetter." + }, + "to": "0xd7dB319a49362b2328cf417a934300cCcB442C8d", + "data": "0x99a88ec400000000000000000000000005c993e60179f28bf649a2bb5b00b5f4283bd525000000000000000000000000d81f43edbcacb4c29a9ba38a13ee5d79278270cc", + "value": "0", + "contractMethod": { + "inputs": [ + { + "name": "_proxy", + "type": "address", + "internalType": "address payable" + }, + { + "name": "_implementation", + "type": "address", + "internalType": "address" + } + ], + "name": "upgrade", + "payable": false, + "outputs": [] + }, + "contractInputsValues": { + "_proxy": "0x05C993e60179f28bF649a2Bb5b00b5F4283bD525", + "_implementation": "0xd81f43eDBCAcb4c29a9bA38a13Ee5d79278270cC" + } + }, + { + "metadata": { + "name": "SystemConfigProxy.setBytes32(0,0)", + "description": "Zeroes out the initialized state variable to allow reinitialization." + }, + "to": "0x05C993e60179f28bF649a2Bb5b00b5F4283bD525", + "data": "0x4e91db0800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "contractMethod": { + "inputs": [ + { + "name": "_slot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "_value", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "name": "setBytes32", + "payable": false, + "outputs": [] + }, + "contractInputsValues": { + "_slot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "_value": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "metadata": { + "name": "ProxyAdmin.upgradeAndCall(SystemConfigProxy, SystemConfigImplementation, Initialize())", + "description": "Upgrades the SystemConfig to a new implementation and initializes it." + }, + "to": "0xd7dB319a49362b2328cf417a934300cCcB442C8d", + "data": "0x9623609d00000000000000000000000005c993e60179f28bf649a2bb5b00b5f4283bd52500000000000000000000000033b83e4c305c908b2fc181dda36e230213058d7d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000284db9040fa000000000000000000000000bea2bc852a160b8547273660e22f4f08c2fa9bbb00000000000000000000000000000000000000000000000000000000000c3c9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021e57c21530bc33f12ba96c9ddc135488365002f0000000000000000000000000000000000000000000000000000000001c9c38000000000000000000000000043ec5732581d3fae18abb7ce34a796e111dbd1a00000000000000000000000000000000000000000000000000000000001312d00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000004de1914f4f17ac234f5a5bc8a4072a231d44bf0000000000000000000000009fe1d3523f5342535e6e7770ed09ed85dbc1acc2000000000000000000000000d1c901bbd7796546a7ba2492e0e199911fae68c700000000000000000000000033f60714bbd74d62b66d79213c348614de51901c000000000000000000000000860e626c700af381133d9f4af31412a2d1db3d5d0000000000000000000000005c1d29c6c9c8b0800692acc95d700bcb4966a1d7000000000000000000000000686f782a749d1854f6fa3f948450f4c65c6674f0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000000000000000000000000000000000000", + "value": "0", + "contractMethod": { + "inputs": [ + { + "name": "_proxy", + "type": "address", + "internalType": "address payable" + }, + { + "name": "_implementation", + "type": "address", + "internalType": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "upgradeAndCall", + "payable": false, + "outputs": [] + }, + "contractInputsValues": { + "_data": "0xdb9040fa000000000000000000000000bea2bc852a160b8547273660e22f4f08c2fa9bbb00000000000000000000000000000000000000000000000000000000000c3c9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021e57c21530bc33f12ba96c9ddc135488365002f0000000000000000000000000000000000000000000000000000000001c9c38000000000000000000000000043ec5732581d3fae18abb7ce34a796e111dbd1a00000000000000000000000000000000000000000000000000000000001312d00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000004de1914f4f17ac234f5a5bc8a4072a231d44bf0000000000000000000000009fe1d3523f5342535e6e7770ed09ed85dbc1acc2000000000000000000000000d1c901bbd7796546a7ba2492e0e199911fae68c700000000000000000000000033f60714bbd74d62b66d79213c348614de51901c000000000000000000000000860e626c700af381133d9f4af31412a2d1db3d5d0000000000000000000000005c1d29c6c9c8b0800692acc95d700bcb4966a1d7000000000000000000000000686f782a749d1854f6fa3f948450f4c65c6674f0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "_proxy": "0x05C993e60179f28bF649a2Bb5b00b5F4283bD525", + "_implementation": "0x33b83E4C305c908B2Fc181dDa36e230213058d7d" + } + } + ] +}