diff --git a/security-council-rehearsals/SIGNER_SETUP.md b/security-council-rehearsals/SIGNER_SETUP.md new file mode 100644 index 000000000..6a642b831 --- /dev/null +++ b/security-council-rehearsals/SIGNER_SETUP.md @@ -0,0 +1,65 @@ +# Signer Setup Instructions + +This guide provides setup instructions for Security Council members participating in rehearsals. + +## Repository Setup + +Run these commands **once** when you first clone the repository or when instructed by the facilitator: + +```bash +cd superchain-ops +git pull +mise trust mise.toml # Only required the first time you use the repository. +mise install +mise activate # Activate mise for the current shell; if it doesn't take effect, restart your terminal. +forge clean +forge install +``` + +For more details on repository setup and dependencies, see the main [README](../README.md). + +## Hardware Wallet Setup + +### Default Setup (Ledger) + +Your hardware wallet needs to be connected and unlocked. The Ethereum application needs to be opened on your hardware wallet with the message "Application is ready". + +By default, the tooling uses the first Ethereum account on your hardware wallet (derivation path `m/44'/60'/0'/0/0`). + +### Using a Different Derivation Path + +If you need to use a different Ethereum account on your hardware wallet, you can specify the HD_PATH environment variable: + +```bash +# Use the second account (m/44'/60'/1'/0/0) +HD_PATH=1 just simulate-stack rehearsals/ +HD_PATH=1 just sign-stack rehearsals/ +``` + +The `HD_PATH` value is used as an index in the BIP44 Ethereum path: `m/44'/60'/$HD_PATH'/0/0`. + +### Using a Different Hardware Wallet + +The tooling supports any hardware wallet that works with Foundry's signing tools. Common options include: +- Ledger devices (Nano S, Nano X, Nano S Plus) +- Trezor devices +- Any wallet compatible with Foundry's `cast wallet` command + +### Using Keystore Instead of Hardware Wallet + +If you prefer to use a keystore file instead of a hardware wallet: + +1. First, import your private key into Foundry's keystore: + ```bash + cast wallet import my-account-name --private-key + ``` + +2. Then use the `USE_KEYSTORE` environment variable when running commands: + ```bash + USE_KEYSTORE=1 just simulate-stack rehearsals/ + USE_KEYSTORE=1 just sign-stack rehearsals/ + ``` + +You'll be prompted for your keystore password when signing. + +For more information on hardware wallet configuration, see the [main README](../README.md#how-do-i-sign-a-task-that-depends-on-another-task). diff --git a/security-council-rehearsals/rehearsal-1-welcome/README.md b/security-council-rehearsals/rehearsal-1-welcome/README.md index 7a94368e9..bf1cc10c1 100644 --- a/security-council-rehearsals/rehearsal-1-welcome/README.md +++ b/security-council-rehearsals/rehearsal-1-welcome/README.md @@ -21,33 +21,26 @@ convenience. ## Approving the transaction -### 1. Update repo and move to the appropriate folder for this rehearsal task: +### 1. Setup -``` -cd superchain-ops -git pull -# Make sure you've installed the dependencies for the repository. -cd src/tasks//rehearsals/ # This path should be shared with you by the Facilitator. -``` - -See the [README](../../src/README.md) for more information on how to install the dependencies for the repository. +Follow the [Signer Setup Instructions](../SIGNER_SETUP.md) to: +- Update the repository and install dependencies (first time only) +- Configure your hardware wallet or keystore +- Learn about using different derivation paths or hardware wallets -### 2. Setup Ledger +### 2. Simulate and validate the transaction -Your Ledger needs to be connected and unlocked. The Ethereum -application needs to be opened on Ledger with the message “Application -is ready”. - -### 3. Simulate and validate the transaction - -Make sure your ledger is still unlocked and run the following. +Make sure your hardware wallet is still unlocked and run the following. ``` shell -cd src/tasks//rehearsals/ -just --dotenv-path $(pwd)/.env simulate -# For a different derivation path, use: HD_PATH=1 just --dotenv-path $(pwd)/.env simulate +cd superchain-ops/src +just simulate-stack rehearsals/ ``` +Note: The `` and `` should be shared with you by the Facilitator (e.g., `eth` and `2025-01-08-R1-welcome`). + +For different derivation paths or hardware wallet options, see the [Signer Setup Instructions](../SIGNER_SETUP.md). + You will see a "Simulation link" URL in the output. Copy this URL from the output and and open it with your browser. A prompt may ask you to choose a @@ -57,7 +50,7 @@ Click "Simulate Transaction". We will be performing 3 validations and ensure the domain hash and message hash are the same between the Tenderly simulation and your -Ledger: +hardware wallet: 1. Validate integrity of the simulation. 2. Validate correctness of the state diff. @@ -71,8 +64,8 @@ To validate integrity of the simulation, we need to check the following: 2. "Timestamp": Check the simulation is performed on a block with a recent timestamp (i.e. close to when you run the script). 3. "Sender": Check the address shown is your signer account. If not, - you will need to determine which “number” it is in the list of - addresses on your ledger. By default the script uses derivation path 0 + you will need to determine which "number" it is in the list of + addresses on your hardware wallet. By default the script uses derivation path 0 (`m/44'/60'/0'/0/0`). You can set the HD_PATH environment variable to use a different path. Here is an example screenshot, note that the Timestamp and Sender might be different in your simulation: @@ -116,7 +109,7 @@ approve. Go back to the "Summary" tab, and find the first `GnosisSafe.domainSeparator` call. This call's return value will be -the domain hash that will show up in your Ledger. +the domain hash that will show up on your hardware wallet. Here is an example screenshot. Note that the hash value may be different: @@ -134,26 +127,27 @@ different: ![](./images/4-tenderly-hashes.png) Note down both the domain hash and the message hash. You will need to -compare them with the ones displayed in your terminal AND on the Ledger screen at signing. +compare them with the ones displayed in your terminal AND on the hardware wallet screen at signing. -### 4. Approve the signature on your ledger +### 3. Approve the signature on your hardware wallet Once the validations are done, it's time to actually sign the -transaction. Make sure your ledger is still unlocked and run the +transaction. Make sure your hardware wallet is still unlocked and run the following: ``` shell -cd src/tasks//rehearsals/ -just --dotenv-path $(pwd)/.env sign -# For a different derivation path, use: HD_PATH=1 just --dotenv-path $(pwd)/.env sign +cd superchain-ops/src +just sign-stack rehearsals/ ``` +For different derivation paths or hardware wallet options, see the [Signer Setup Instructions](../SIGNER_SETUP.md). + > [!IMPORTANT] This is the most security critical part of the > playbook: make sure the domain hash and message hash in the > following three places match: 1. In your terminal output. -2. On your Ledger screen. +2. On your hardware wallet screen. 3. In the Tenderly simulation. You should use the same Tenderly simulation as the one you used to verify the state diffs, instead of opening the new one printed in the console. @@ -192,6 +186,10 @@ congrats, you are done! ### [Before the rehearsal] Prepare the rehearsal +#### 0. Setup the repository + +See the [Signer Setup Instructions](../SIGNER_SETUP.md) for repository setup steps. + #### 1. Create the Council Safe The first step of preparing the rehearsal is creating a multisig for @@ -266,9 +264,9 @@ Signature: BBBB Then you should run ``` shell +cd superchain-ops/src/tasks//rehearsals/ export SIGNATURES="0xAAAABBBB" -cd src/tasks//rehearsals/ -just --dotenv-path $(pwd)/.env execute +just execute ``` For posterity, you should make a `README.md` file in the tasks directory that contains a link to the executed transaction e.g. see [here](../../src/tasks/eth/rehearsals/2025-07-21-R1-welcome/README.md). \ No newline at end of file diff --git a/security-council-rehearsals/rehearsal-2-remove-signer/README.md b/security-council-rehearsals/rehearsal-2-remove-signer/README.md index f587dd1d7..b39c5ac7b 100644 --- a/security-council-rehearsals/rehearsal-2-remove-signer/README.md +++ b/security-council-rehearsals/rehearsal-2-remove-signer/README.md @@ -15,33 +15,26 @@ Once the required number of signatures is collected, anyone can finalize the exe ## Approving the transaction -### 1. Update repo and move to the appropriate folder for this rehearsal task: +### 1. Setup -``` -cd superchain-ops -git pull -# Make sure you've installed the dependencies for the repository. -cd src/tasks//rehearsals/ # This path should be shared with you by the Facilitator. -``` - -See the [README](../../src/README.md) for more information on how to install the dependencies for the repository. +Follow the [Signer Setup Instructions](../SIGNER_SETUP.md) to: +- Update the repository and install dependencies (first time only) +- Configure your hardware wallet or keystore +- Learn about using different derivation paths or hardware wallets -### 2. Setup Ledger +### 2. Simulate and validate the transaction -Your Ledger needs to be connected and unlocked. The Ethereum -application needs to be opened on Ledger with the message “Application -is ready”. - -### 3. Simulate and validate the transaction - -Make sure your ledger is still unlocked and run the following. +Make sure your hardware wallet is still unlocked and run the following. ``` shell -cd src/tasks//rehearsals/ -just --dotenv-path $(pwd)/.env simulate -# For a different derivation path, use: HD_PATH=1 just --dotenv-path $(pwd)/.env simulate +cd superchain-ops/src +just simulate-stack rehearsals/ ``` +Note: The `` and `` should be shared with you by the Facilitator (e.g., `eth` and `2025-01-08-R2-remove-signer`). + +For different derivation paths or hardware wallet options, see the [Signer Setup Instructions](../SIGNER_SETUP.md). + You will see a "Simulation link" URL in the output. Copy this URL from the output and and open it with your browser. A prompt may ask you to choose a @@ -51,7 +44,7 @@ Click "Simulate Transaction". We will be performing 3 validations and ensure the domain hash and message hash are the same between the Tenderly simulation and your -Ledger: +hardware wallet: 1. Validate integrity of the simulation. 2. Validate correctness of the state diff. @@ -65,8 +58,8 @@ To validate integrity of the simulation, we need to check the following: 2. "Timestamp": Check the simulation is performed on a block with a recent timestamp (i.e. close to when you run the script). 3. "Sender": Check the address shown is your signer account. If not, - you will need to determine which “number” it is in the list of - addresses on your ledger. By default the script will assume the + you will need to determine which "number" it is in the list of + addresses on your hardware wallet. By default the script will assume the derivation path is `m/44'/60'/0'/0/0`. Here is an example screenshot, note that the Timestamp and Sender @@ -98,7 +91,7 @@ approve. Go back to the "Overview" tab, and find the first `GnosisSafe.domainSeparator` call. This call's return value will be -the domain hash that will show up in your Ledger. +the domain hash that will show up on your hardware wallet. Here is an example screenshot. Note that the hash value may be different: @@ -116,26 +109,27 @@ different: ![](./images/4-tenderly-hashes.png) Note down both the domain hash and the message hash. You will need to -compare them with the ones displayed in your terminal AND on the Ledger screen at signing. +compare them with the ones displayed in your terminal AND on the hardware wallet screen at signing. -### 4. Approve the signature on your ledger +### 3. Approve the signature on your hardware wallet Once the validations are done, it's time to actually sign the -transaction. Make sure your ledger is still unlocked and run the +transaction. Make sure your hardware wallet is still unlocked and run the following: ``` shell -cd src/tasks//rehearsals/ -just --dotenv-path $(pwd)/.env sign -# For a different derivation path, use: HD_PATH=1 just --dotenv-path $(pwd)/.env sign +cd superchain-ops/src +just sign-stack rehearsals/ ``` +For different derivation paths or hardware wallet options, see the [Signer Setup Instructions](../SIGNER_SETUP.md). + > [!IMPORTANT] This is the most security critical part of the > playbook: make sure the domain hash and message hash in the > following three places match: 1. In your terminal output. -2. On your Ledger screen. +2. On your hardware wallet screen. 3. In the Tenderly simulation. You should use the same Tenderly simulation as the one you used to verify the state diffs, instead of opening the new one printed in the console. @@ -174,6 +168,10 @@ congrats, you are done! ### [Before the rehearsal] Prepare the rehearsal +#### 0. Setup the repository + +See the [Signer Setup Instructions](../SIGNER_SETUP.md) for repository setup steps. + #### 1. Create a new task in the `eth` directory: ```bash @@ -232,9 +230,9 @@ Signature: BBBB Then you should run ``` shell +cd superchain-ops/src/tasks//rehearsals/ export SIGNATURES="0xAAAABBBB" -cd src/tasks//rehearsals/ -just --dotenv-path $(pwd)/.env execute +just execute ``` For posterity, you should make a `README.md` file in the tasks directory that contains a link to the executed transaction e.g. see [here](../../src/tasks/eth/rehearsals/2025-11-28-R2-remove-signer/README.md). diff --git a/security-council-rehearsals/rehearsal-3-nested-upgrade/README.md b/security-council-rehearsals/rehearsal-3-nested-upgrade/README.md index b5cc942a5..36a07bbae 100644 --- a/security-council-rehearsals/rehearsal-3-nested-upgrade/README.md +++ b/security-council-rehearsals/rehearsal-3-nested-upgrade/README.md @@ -1,4 +1,4 @@ -# Rehearsal 4 - Protocol Upgrade via Nested Multisig +# Rehearsal 3 - Protocol Upgrade via Nested Multisig ## Objective @@ -18,34 +18,27 @@ Once the required number of signatures is collected, anyone can finalize the exe ## Approving the transaction -### 1. Update repo and move to the appropriate folder for this rehearsal task: +### 1. Setup -``` -cd superchain-ops -git pull -# Make sure you've installed the dependencies for the repository. -cd src/tasks//rehearsals/ # This path should be shared with you by the Facilitator. -``` - -See the [README](../../src/README.md) for more information on how to install the dependencies for the repository. +Follow the [Signer Setup Instructions](../SIGNER_SETUP.md) to: +- Update the repository and install dependencies (first time only) +- Configure your hardware wallet or keystore +- Learn about using different derivation paths or hardware wallets -### 2. Setup Ledger +### 2. Simulate and validate the transaction -Your Ledger needs to be connected and unlocked. The Ethereum -application needs to be opened on Ledger with the message "Application -is ready". - -### 3. Simulate and validate the transaction - -Make sure your ledger is still unlocked and run the following. +Make sure your hardware wallet is still unlocked and run the following. ``` shell -cd src/tasks//rehearsals/ -just --dotenv-path $(pwd)/.env simulate test-rehearsal-council -# For a different derivation path, use: HD_PATH=1 just --dotenv-path $(pwd)/.env simulate test-rehearsal-council +cd superchain-ops/src +just simulate-stack rehearsals/ test-rehearsal-council # 'test-rehearsal-council' maps to the test rehearsal security council safe in the tasks 'config.toml' file. Denoted as 'TestRehearsalCouncil'. ``` +Note: The `` and `` should be shared with you by the Facilitator (e.g., `eth` and `2025-01-08-R3-nested-upgrade`). + +For different derivation paths or hardware wallet options, see the [Signer Setup Instructions](../SIGNER_SETUP.md). + You will see a "Simulation link" URL in the output. Copy this URL from the output and and open it with your browser. A prompt may ask you to choose a @@ -55,7 +48,7 @@ Click "Simulate Transaction". We will be performing 3 validations and ensure the domain hash and message hash are the same between the Tenderly simulation and your -Ledger: +hardware wallet: 1. Validate integrity of the simulation. 2. Validate correctness of the state diff. @@ -69,8 +62,8 @@ To validate integrity of the simulation, we need to check the following: 2. "Timestamp": Check the simulation is performed on a block with a recent timestamp (i.e. close to when you run the script). 3. "Sender": Check the address shown is your signer account. If not, - you will need to determine which “number” it is in the list of - addresses on your ledger. By default the script will assume the + you will need to determine which "number" it is in the list of + addresses on your hardware wallet. By default the script will assume the derivation path is `m/44'/60'/0'/0/0`. Here is an example screenshot, note that the Timestamp and Sender @@ -98,7 +91,7 @@ approve. Go back to the "Overview" tab, and find the first `GnosisSafe.domainSeparator` call. This call's return value will be -the domain hash that will show up in your Ledger. +the domain hash that will show up on your hardware wallet. Here is an example screenshot. Note that the hash value may be different: @@ -116,27 +109,28 @@ different: ![](./images/tenderly-hashes-2.png) Note down both the domain hash and the message hash. You will need to -compare them with the ones displayed in your terminal AND on the Ledger screen at signing. +compare them with the ones displayed in your terminal AND on the hardware wallet screen at signing. -### 4. Approve the signature on your ledger +### 3. Approve the signature on your hardware wallet Once the validations are done, it's time to actually sign the -transaction. Make sure your ledger is still unlocked and run the +transaction. Make sure your hardware wallet is still unlocked and run the following: ``` shell -cd src/tasks//rehearsals/ -just --dotenv-path $(pwd)/.env sign test-rehearsal-council -# For a different derivation path, use: HD_PATH=1 just --dotenv-path $(pwd)/.env sign test-rehearsal-council +cd superchain-ops/src +just sign-stack rehearsals/ test-rehearsal-council # 'test-rehearsal-council' maps to the test rehearsal security council safe in the tasks 'config.toml' file. ``` +For different derivation paths or hardware wallet options, see the [Signer Setup Instructions](../SIGNER_SETUP.md). + > [!IMPORTANT] This is the most security critical part of the > playbook: make sure the domain hash and message hash in the > following three places match: 1. In your terminal output. -2. On your Ledger screen. +2. On your hardware wallet screen. 3. In the Tenderly simulation. You should use the same Tenderly simulation as the one you used to verify the state diffs, instead of opening the new one printed in the console. @@ -175,6 +169,10 @@ congrats, you are done! ### [Before the rehearsal] Prepare the rehearsal +#### 0. Setup the repository + +See the [Signer Setup Instructions](../SIGNER_SETUP.md) for repository setup steps. + #### 1. Create and configure the safes To simulate our production Safe configuration (i.e. 2-of-2 between the Security Council and the Optimism Foundation), we need to create 2 more Safe contracts. We are assuming you have already created the Security Council Safe in the [previous rehearsal](../step-1-welcome/README.md). You should create the safes in the following order: @@ -206,7 +204,7 @@ graph TD 1. Set the `OWNER_SAFE` address in [`.env`](./.env) to the newly-created Safe address. 2. Set the `COUNCIL_SAFE` address in [`.env`](./.env) to the same one used in previous rehearsals. -3. Make sure your Ledger is connected and run `just deploy-contracts` to deploy the rehearsal contracts. There will be two contracts deployed: the `OptimismPortalProxy` and the `ProxyAdmin` as their admin (you'll have to accept a total of 4 transactions on your Ledger). +3. Make sure your hardware wallet is connected and run `just deploy-contracts` to deploy the rehearsal contracts. There will be two contracts deployed: the `OptimismPortalProxy` and the `ProxyAdmin` as their admin (you'll have to accept a total of 4 transactions on your hardware wallet). 4. Take note of all the addresses that are deployed, we will need them for the next step. Below is a screenshot of example output of the `just deploy-contracts` command: @@ -269,9 +267,10 @@ Commit the newly created files to Github. 2. Concatenate all signatures and export it as the `SIGNATURES` environment variable, i.e. `export SIGNATURES="0x[SIGNATURE1][SIGNATURE2]..."`. 3. Run the approval for the Security Council Safe: ```bash +cd superchain-ops/src/tasks//rehearsals/ # These should be the signatures from the signers on the security council safe. export SIGNATURES="0x[SIGNATURE1]..." -just --dotenv-path $(pwd)/.env approve test-rehearsal-council +just approve test-rehearsal-council # 'test-rehearsal-council' maps to the test rehearsal security council safe in the tasks 'config.toml' file. Denoted as 'TestRehearsalCouncil'. ``` 4. Run the approval for the Foundation Safe. Note that `SIGNATURES` will now contain signatures from the foundation safe, not the security council safe. @@ -279,7 +278,7 @@ just --dotenv-path $(pwd)/.env approve test-rehearsal-council # These should be the signatures from the signers on the foundation safe. export SIGNATURES="0x[SIGNATURE1]..." # Remember, if you're using a different HD_PATH to set the env var e.g. 'export HD_PATH=1' -just --dotenv-path $(pwd)/.env approve test-rehearsal-foundation +just approve test-rehearsal-foundation # 'test-rehearsal-foundation' maps to the test rehearsal foundation safe in the tasks 'config.toml' file. Denoted as 'TestRehearsalFoundation'. ``` 5. Perform the final execution: @@ -287,5 +286,5 @@ just --dotenv-path $(pwd)/.env approve test-rehearsal-foundation # Reset the SIGNATURES env var as it can sometimes interact with the execute function. export SIGNATURES="" # Remember, if you're using a different HD_PATH to set the env var e.g. 'export HD_PATH=1' -just --dotenv-path $(pwd)/.env execute +just execute ``` diff --git a/src/SuperchainAddressRegistry.sol b/src/SuperchainAddressRegistry.sol index 7b87deee6..f651bf110 100644 --- a/src/SuperchainAddressRegistry.sol +++ b/src/SuperchainAddressRegistry.sol @@ -37,6 +37,7 @@ interface IFetcher { function owner() external view returns (address); function unsafeBlockSigner() external view returns (address); function weth() external view returns (address); + function gameArgs(GameType _gameType) external view returns (bytes memory); } /// @notice This contract provides a single source of truth for storing and retrieving addresses @@ -350,34 +351,31 @@ contract SuperchainAddressRegistry is StdChains { } /// @dev Saves all dispute game related registry entries. - function _saveDisputeGameEntries(ChainInfo memory chain, address disputeGameFactoryProxy) internal { - saveAddress("DisputeGameFactoryProxy", chain, disputeGameFactoryProxy); + /// @dev Supports both pre-v6.0.0 (values on dispute game) and v6.0.0+ (values in gameArgs). + function _saveDisputeGameEntries(ChainInfo memory chain, address factory) internal { + saveAddress("DisputeGameFactoryProxy", chain, factory); - address faultDisputeGame = getFaultDisputeGame(disputeGameFactoryProxy); - if (faultDisputeGame != address(0)) { - saveAddress("FaultDisputeGame", chain, faultDisputeGame); - saveAddress("PermissionlessWETH", chain, getDelayedWETHProxy(faultDisputeGame)); - } - - address permissionedDisputeGame = getPermissionedDisputeGame(disputeGameFactoryProxy); - saveAddress("PermissionedDisputeGame", chain, permissionedDisputeGame); + address fdg = getFaultDisputeGame(factory); + address pdg = getPermissionedDisputeGame(factory); - address challenger = IFetcher(permissionedDisputeGame).challenger(); - saveAddress("Challenger", chain, challenger); + // Decode gameArgs once per game type (empty struct if pre-v6.0.0) + DecodedGameArgs memory args0 = _tryDecodeGameArgs(factory, GameType.wrap(0)); + DecodedGameArgs memory args1 = _tryDecodeGameArgs(factory, GameType.wrap(1)); - address anchorStateRegistryProxy = getAnchorStateRegistryProxy(permissionedDisputeGame); - saveAddress("AnchorStateRegistryProxy", chain, anchorStateRegistryProxy); + if (fdg != address(0)) { + saveAddress("FaultDisputeGame", chain, fdg); + saveAddress("PermissionlessWETH", chain, _addrOr(args0.weth, fdg, IFetcher.weth.selector)); + } - saveAddress("PermissionedWETH", chain, getDelayedWETHProxy(permissionedDisputeGame)); + saveAddress("PermissionedDisputeGame", chain, pdg); + saveAddress("Challenger", chain, _addrOr(args1.challenger, pdg, IFetcher.challenger.selector)); + saveAddress("AnchorStateRegistryProxy", chain, _addrOr(args1.asr, pdg, IFetcher.anchorStateRegistry.selector)); + saveAddress("PermissionedWETH", chain, _addrOr(args1.weth, pdg, IFetcher.weth.selector)); - address mips = getMips(permissionedDisputeGame); + address mips = _addrOr(args1.vm_, pdg, IFetcher.vm.selector); saveAddress("MIPS", chain, mips); - - address preimageOracle = IFetcher(mips).oracle(); - saveAddress("PreimageOracle", chain, preimageOracle); - - address proposer = IFetcher(permissionedDisputeGame).proposer(); - saveAddress("Proposer", chain, proposer); + saveAddress("PreimageOracle", chain, IFetcher(mips).oracle()); + saveAddress("Proposer", chain, _addrOr(args1.proposer, pdg, IFetcher.proposer.selector)); } /// @notice Saves all addresses for a given chain from the addresses.json file. This does not perform any onchain discovery. @@ -492,18 +490,44 @@ contract SuperchainAddressRegistry is StdChains { } } - function getAnchorStateRegistryProxy(address permissionedDisputeGame) internal view returns (address) { - return IFetcher(permissionedDisputeGame).anchorStateRegistry(); - } - - function getDelayedWETHProxy(address disputeGame) internal view returns (address) { - (bool ok, bytes memory data) = address(disputeGame).staticcall(abi.encodeWithSelector(IFetcher.weth.selector)); - if (ok && data.length == 32) return abi.decode(data, (address)); - else return address(0); + /// @notice Decoded game arguments from DisputeGameFactory.gameArgs() + /// @dev In op-contracts v6.0.0+, these values are stored in gameArgs instead of on the dispute game. + /// gameArgs layout: absolutePrestate (32) | vm (20) | asr (20) | weth (20) | l2ChainId (32) + /// Permissioned adds: proposer (20) | challenger (20) + struct DecodedGameArgs { + address vm_; + address asr; + address weth; + address proposer; + address challenger; + } + + /// @notice Tries to fetch and decode gameArgs from the factory. Returns empty struct if unavailable. + function _tryDecodeGameArgs(address factory, GameType gameType) internal view returns (DecodedGameArgs memory d) { + try IFetcher(factory).gameArgs(gameType) returns (bytes memory args) { + if (args.length >= 92) { + assembly { + let p := add(args, 32) // skip length prefix + mstore(add(d, 0x00), shr(96, mload(add(p, 32)))) // vm at offset 32 + mstore(add(d, 0x20), shr(96, mload(add(p, 52)))) // asr at offset 52 + mstore(add(d, 0x40), shr(96, mload(add(p, 72)))) // weth at offset 72 + } + } + if (args.length >= 164) { + assembly { + let p := add(args, 32) + mstore(add(d, 0x60), shr(96, mload(add(p, 124)))) // proposer at offset 124 + mstore(add(d, 0x80), shr(96, mload(add(p, 144)))) // challenger at offset 144 + } + } + } catch {} } - function getMips(address permissionedDisputeGame) internal view returns (address) { - return IFetcher(permissionedDisputeGame).vm(); + /// @notice Returns `primary` if non-zero, otherwise calls `selector` on `fallback_`. + function _addrOr(address primary, address fallback_, bytes4 selector) internal view returns (address) { + if (primary != address(0)) return primary; + (bool ok, bytes memory data) = fallback_.staticcall(abi.encodeWithSelector(selector)); + return (ok && data.length == 32) ? abi.decode(data, (address)) : address(0); } function getBatchSubmitter(address systemConfigProxy) internal view returns (address) { diff --git a/src/justfile b/src/justfile index d8ca63b63..7f5196085 100644 --- a/src/justfile +++ b/src/justfile @@ -53,6 +53,7 @@ new COMMAND="" TASK_TYPE="": simulate-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2="": #!/usr/bin/env bash set -euo pipefail + unset ETHERSCAN_API_KEY # Avoid Etherscan API rate limiting during simulation root_dir=$(git rev-parse --show-toplevel) root_just_file="${root_dir}/src/justfile" just _print-welcome-message @@ -65,10 +66,27 @@ simulate-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEP echo " just simulate-stack eth 001-example # Specific task" echo " just simulate-stack eth 001-example foundation # On child safe" echo " just simulate-stack eth 001-example base-nested base-council # Multiple child safes" + echo " just simulate-stack eth rehearsals # All rehearsal tasks" + echo " just simulate-stack eth rehearsals/2025-01-08-R1-welcome # Specific rehearsal task" + echo " just simulate-stack eth rehearsals/2025-01-08-R3 council # Rehearsal with nested safe" } [ -z "{{NETWORK}}" ] && { echo -e "\n\033[31mError: No network specified\033[0m"; show_usage; exit 1; } + # Handle rehearsal tasks using FETCH_REHEARSALS mode + # For rehearsals, effective_task is the task name without "rehearsals/" prefix + # This is needed because StackedSimulator matches task names by their final path component + effective_task="{{TASK}}" + if [[ "$effective_task" == rehearsals* ]]; then + export FETCH_REHEARSALS=1 + # Extract rehearsal task name (remove "rehearsals/" prefix if present) + if [[ "$effective_task" == "rehearsals" ]]; then + effective_task="" + else + effective_task="${effective_task#rehearsals/}" + fi + fi + ETH_RPC_URL=$("$root_dir"/src/script/get-rpc-url.sh "{{NETWORK}}") # Load FORK_BLOCK_NUMBER from the task's .env file if available @@ -97,26 +115,26 @@ simulate-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEP echo -e "\n⏳ Stacked Task simulation in progress..." - if [ -z "{{TASK}}" ]; then + if [ -z "$effective_task" ]; then echo -e "⏳ You are simulating all tasks for network: {{NETWORK}}\n" just list-stack {{NETWORK}} forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string)" {{NETWORK}} --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} elif [ -z "{{CHILD_SAFE_NAME_DEPTH_1}}" ] && [ -z "{{CHILD_SAFE_NAME_DEPTH_2}}" ]; then - echo -e "⏳ You are simulating the task: {{TASK}} for network: '{{NETWORK}}' on the root safe\n" - just list-stack {{NETWORK}} {{TASK}} - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string)" "{{NETWORK}}" "{{TASK}}" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} + echo -e "⏳ You are simulating the task: $effective_task for network: '{{NETWORK}}' on the root safe\n" + just list-stack {{NETWORK}} $effective_task + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string)" "{{NETWORK}}" "$effective_task" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} else task_dir_path="${root_dir}/src/tasks/{{NETWORK}}/{{TASK}}" child_safe_depth_1=$(just --justfile "$root_just_file" _fetch-safe "$task_dir_path" "{{CHILD_SAFE_NAME_DEPTH_1}}") child_safe_depth_2=$(just --justfile "$root_just_file" _fetch-safe "$task_dir_path" "{{CHILD_SAFE_NAME_DEPTH_2}}") - just list-stack {{NETWORK}} {{TASK}} + just list-stack {{NETWORK}} $effective_task if [ "$child_safe_depth_2" != "$ZERO_ADDRESS" ]; then - echo -e "⏳ You are simulating the task: {{TASK}} for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_2\n" - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_2" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} + echo -e "⏳ You are simulating the task: $effective_task for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_2\n" + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address,address)" "{{NETWORK}}" "$effective_task" "$child_safe_depth_2" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} else - echo -e "⏳ You are simulating the task: {{TASK}} for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_1\n" - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} + echo -e "⏳ You are simulating the task: $effective_task for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_1\n" + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address)" "{{NETWORK}}" "$effective_task" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} fi fi echo -e "\n⚠️ Please note: Some Tenderly links may not work when running a stacked simulation. Check out Tenderly's Virtual TestNets as a workaround.⚠️" @@ -124,6 +142,7 @@ simulate-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEP sign-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2="": #!/usr/bin/env bash set -euo pipefail + unset ETHERSCAN_API_KEY # Avoid Etherscan API rate limiting during simulation root_dir=$(git rev-parse --show-toplevel) root_just_file="${root_dir}/src/justfile" just _print-welcome-message @@ -132,6 +151,7 @@ sign-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2 echo echo "Usage: just sign-stack [child-safe-name-depth-1] [child-safe-name-depth-2]" echo "Environment: HD_PATH (default: 0), USE_KEYSTORE" + echo "Example: just sign-stack eth rehearsals/2025-01-08-R1-welcome # Rehearsal task" } if [ -z "{{NETWORK}}" ] || [ -z "{{TASK}}" ]; then @@ -139,6 +159,14 @@ sign-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2 exit 0 fi + # Handle rehearsal tasks using FETCH_REHEARSALS mode + # For rehearsals, effective_task is the task name without "rehearsals/" prefix + effective_task="{{TASK}}" + if [[ "$effective_task" == rehearsals* ]]; then + export FETCH_REHEARSALS=1 + effective_task="${effective_task#rehearsals/}" + fi + ETH_RPC_URL=$("$root_dir"/src/script/get-rpc-url.sh "{{NETWORK}}") task_dir_path="${root_dir}/src/tasks/{{NETWORK}}/{{TASK}}" child_safe_depth_1=$(just --justfile "$root_just_file" _fetch-safe "$task_dir_path" "{{CHILD_SAFE_NAME_DEPTH_1}}") @@ -158,30 +186,45 @@ sign-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2 HD_PATH=${HD_PATH:-0} USE_KEYSTORE=${USE_KEYSTORE:-} signer_info=$(just --justfile "$root_just_file" _get-signer-args "$HD_PATH" "$USE_KEYSTORE") + signer=$(echo "$signer_info" | sed -n '1p') signer_args=$(echo "$signer_info" | sed -n '2p') + # Determine target safe for validation + if [ "$child_safe_depth_2" != "$ZERO_ADDRESS" ]; then + target_safe="$child_safe_depth_2" + elif [ "$child_safe_depth_1" != "$ZERO_ADDRESS" ]; then + target_safe="$child_safe_depth_1" + else + target_safe=$(forge script TaskManager --sig "getRootSafe(string)" "${root_dir}/src/tasks/{{NETWORK}}/{{TASK}}/config.toml" --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} --json | jq -r '.returns["0"].value') + fi + + # Validate that signer is an owner on the target safe + echo "Validating signer is an owner on the safe..." + forge script TaskManager --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} --sig "requireSignerOnSafe(address,address)" $signer $target_safe + export SIGNING_MODE_IN_PROGRESS=true export STACKED_SIGNING_MODE=true if [ "$child_safe_depth_2" != "$ZERO_ADDRESS" ]; then - echo -e "⏳ You are signing the task: {{TASK}} for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_2\n" + echo -e "⏳ You are signing the task: $effective_task for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_2\n" ${root_dir}/bin/eip712sign ${signer_args} -- \ - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_2" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address,address)" "{{NETWORK}}" "$effective_task" "$child_safe_depth_2" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} elif [ -z "{{CHILD_SAFE_NAME_DEPTH_1}}" ] && [ -z "{{CHILD_SAFE_NAME_DEPTH_2}}" ]; then - echo -e "⏳ You are signing the task: {{TASK}} for network: '{{NETWORK}}' on the root safe\n" - just list-stack {{NETWORK}} {{TASK}} + echo -e "⏳ You are signing the task: $effective_task for network: '{{NETWORK}}' on the root safe\n" + just list-stack {{NETWORK}} $effective_task ${root_dir}/bin/eip712sign ${signer_args} -- \ - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string)" "{{NETWORK}}" "{{TASK}}" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string)" "{{NETWORK}}" "$effective_task" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} else - echo -e "⏳ You are signing the task: {{TASK}} for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_1\n" + echo -e "⏳ You are signing the task: $effective_task for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_1\n" ${root_dir}/bin/eip712sign ${signer_args} -- \ - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address)" "{{NETWORK}}" "$effective_task" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} fi echo -e "\n⚠️ Please note: Some Tenderly links may not work when running a stacked simulation. Check out Tenderly's Virtual TestNets as a workaround.⚠️" list-stack NETWORK="" TASK="": #!/usr/bin/env bash set -euo pipefail + unset ETHERSCAN_API_KEY # Avoid Etherscan API rate limiting during simulation root_dir=$(git rev-parse --show-toplevel) show_usage() { @@ -222,6 +265,7 @@ list-stack NETWORK="" TASK="": simulate CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2="": #!/usr/bin/env bash set -euo pipefail + unset ETHERSCAN_API_KEY # Avoid Etherscan API rate limiting during simulation root_dir=$(git rev-parse --show-toplevel) root_just_file="${root_dir}/src/justfile" config_path=${TASK_PATH}/config.toml @@ -257,6 +301,7 @@ simulate CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2="": sign CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2="": #!/usr/bin/env bash set -euo pipefail + unset ETHERSCAN_API_KEY # Avoid Etherscan API rate limiting during simulation root_dir=$(git rev-parse --show-toplevel) root_just_file="${root_dir}/src/justfile" config_path=${TASK_PATH}/config.toml @@ -299,6 +344,7 @@ sign CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2="": approve CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2="": #!/usr/bin/env bash set -euo pipefail + unset ETHERSCAN_API_KEY # Avoid Etherscan API rate limiting during simulation root_dir=$(git rev-parse --show-toplevel) root_just_file="${root_dir}/src/justfile" config_path=${TASK_PATH}/config.toml @@ -351,6 +397,7 @@ approve CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2="": execute: #!/usr/bin/env bash set -euo pipefail + unset ETHERSCAN_API_KEY # Avoid Etherscan API rate limiting during simulation root_dir=$(git rev-parse --show-toplevel) root_just_file="${root_dir}/src/justfile" config_path=${TASK_PATH}/config.toml diff --git a/src/script/fetch-tasks.sh b/src/script/fetch-tasks.sh index fa1adb27d..b223b9d92 100755 --- a/src/script/fetch-tasks.sh +++ b/src/script/fetch-tasks.sh @@ -1,9 +1,13 @@ #!/bin/bash set -euo pipefail -# This file finds non-terminal tasks for a specifc network. +# This file finds non-terminal tasks for a specific network. # It prints these tasks to the console. Other processes can use this output # to execute the tasks locally. +# +# Environment variables: +# FETCH_TASKS_TEST_DIR - Directory containing test tasks (enables test mode) +# FETCH_REHEARSALS - Set to "1" to fetch rehearsal tasks instead of regular tasks # Array to store tasks that should be executed declare -a tasks_to_run=() @@ -12,10 +16,10 @@ declare -a tasks_to_run=() check_status() { local file_path=$1 local status_line - + # Extract the status line status_line=$(awk '/^Status: /{print; exit}' "$file_path") - + # If status is not EXECUTED, CANCELLED, or APPROVED, add to tasks to run if [[ "$status_line" != *"EXECUTED"* ]] && [[ "$status_line" != *"CANCELLED"* ]] && [[ "$status_line" != *"APPROVED"* ]]; then # Get the task directory path @@ -39,6 +43,8 @@ fi # To enable testing mode set the FETCH_TASKS_TEST_DIR environment variable to the directory containing your test tasks. test_dir=${FETCH_TASKS_TEST_DIR:-} +# To fetch rehearsal tasks, set FETCH_REHEARSALS=1 +fetch_rehearsals=${FETCH_REHEARSALS:-} task_dir="$root_dir/src/tasks/$network" @@ -49,6 +55,15 @@ if [[ -n "$test_dir" ]]; then for config_file in $config_files; do tasks_to_run+=("$config_file") done +elif [[ "$fetch_rehearsals" == "1" ]]; then + # For rehearsal tasks, return all tasks without checking status + rehearsals_dir="$task_dir/rehearsals" + if [[ -d "$rehearsals_dir" ]]; then + config_files=$(find "$rehearsals_dir" -type f -name 'config.toml') + for config_file in $config_files; do + tasks_to_run+=("$config_file") + done + fi else # For production directories, check status before adding tasks files=$(find "$task_dir" -type f -name 'README.md' -not -path '*/rehearsals/*') diff --git a/src/tasks/StackedSimulator.sol b/src/tasks/StackedSimulator.sol index 27c2f3fdb..c9a5b053a 100644 --- a/src/tasks/StackedSimulator.sol +++ b/src/tasks/StackedSimulator.sol @@ -159,14 +159,53 @@ contract StackedSimulator is Script { sortedTasks_ = tasks_; } - /// @notice Converts the first three characters of a task name string to a uint256. + /// @notice Converts the task name prefix to a uint256 for sorting. + /// Supports two formats: + /// - Standard 3-digit prefix: "001-task-name" -> 1 + /// - Date-based prefix: "2025-07-21-R1-task" -> 202507210001 (YYYYMMDD + rehearsal number) function convertPrefixToUint(string memory taskName) public pure returns (uint256) { require(bytes(taskName).length > 0, "StackedSimulator: Task name must not be empty."); string[] memory parts = vm.split(taskName, "-"); require(parts.length > 0, "StackedSimulator: Invalid task name, must contain at least one '-'."); require(!parts[0].contains("0x"), "StackedSimulator: Does not support hex strings."); - require(bytes(parts[0]).length == 3, "StackedSimulator: Prefix must have 3 characters."); - return vm.parseUint(parts[0]); + + // Handle standard 3-digit prefix format (e.g., "001-task-name") + if (bytes(parts[0]).length == 3) { + return vm.parseUint(parts[0]); + } + + // Handle date-based format (e.g., "2025-07-21-R1-task") + // Format: YYYY-MM-DD-RN-name where RN is the rehearsal number + if (bytes(parts[0]).length == 4 && parts.length >= 4) { + uint256 year = vm.parseUint(parts[0]); + uint256 month = vm.parseUint(parts[1]); + uint256 day = vm.parseUint(parts[2]); + // Validate date components + require(year <= 2100, "StackedSimulator: Year must be <= 2100"); + require(month >= 1 && month <= 12, "StackedSimulator: Month must be between 1 and 12"); + require(day >= 1 && day <= 31, "StackedSimulator: Day must be between 1 and 31"); + // Extract rehearsal number from parts[3] (e.g., "R1" -> 1) + string memory rehearsalPart = parts[3]; + uint256 rehearsalNum = 0; + if (bytes(rehearsalPart).length >= 2 && bytes(rehearsalPart)[0] == bytes1("R")) { + // Extract the number after "R" + bytes memory numBytes = new bytes(bytes(rehearsalPart).length - 1); + for (uint256 i = 1; i < bytes(rehearsalPart).length; i++) { + numBytes[i - 1] = bytes(rehearsalPart)[i]; + } + rehearsalNum = vm.parseUint(string(numBytes)); + } else { + revert( + "StackedSimulator: Date-based format requires 'R' prefix in fourth component (e.g., YYYY-MM-DD-RN)" + ); + } + // Create a sortable number: YYYYMMDD * 10000 + rehearsal number + return (year * 10000 + month * 100 + day) * 10000 + rehearsalNum; + } + + revert( + "StackedSimulator: Invalid task name format. Valid formats are either: 1) A 3-digit prefix followed by a descriptive name (e.g., '123-deploy-contract'), or 2) A date-based format 'YYYY-MM-DD-RN' where YYYY=year, MM=month, DD=day, R=rehearsal indicator (must be 'R'), and N=sequence number (e.g., '2025-01-08-R1')." + ); } /// @notice Finds the index of a task in a list of tasks. diff --git a/src/tasks/eth/038-fos-safersafes-enable/README.md b/src/tasks/eth/038-fos-safersafes-enable/README.md index 118de8448..b32990bc0 100644 --- a/src/tasks/eth/038-fos-safersafes-enable/README.md +++ b/src/tasks/eth/038-fos-safersafes-enable/README.md @@ -1,6 +1,6 @@ # 038-fos-safersafes-enable -Status: [READY TO SIGN]() +Status: [EXECUTED](https://etherscan.io/tx/0xf1ae77bea001acd7f3355ce971fd992601f467ce0a2305a38b1a82da459b502c) ## Objective diff --git a/src/tasks/eth/039-fus-safersafes-enable/README.md b/src/tasks/eth/039-fus-safersafes-enable/README.md index 8b0041cbb..2ba4483c6 100644 --- a/src/tasks/eth/039-fus-safersafes-enable/README.md +++ b/src/tasks/eth/039-fus-safersafes-enable/README.md @@ -1,6 +1,6 @@ # 039-fus-safersafes-enable -Status: [READY TO SIGN]() +Status: [EXECUTED](https://etherscan.io/tx/0x5f91ef9e90c0c7f3623cd6361b471f8d9643d67854af7c1906d23790948faf46) ## Objective diff --git a/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/.env b/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/.env new file mode 100644 index 000000000..adf17d369 --- /dev/null +++ b/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/.env @@ -0,0 +1 @@ +TENDERLY_GAS=15000000 diff --git a/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/README.md b/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/README.md new file mode 100644 index 000000000..bd799aff8 --- /dev/null +++ b/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/README.md @@ -0,0 +1,37 @@ +# 040-U18-op-ink-mmz-arena-swell + +Status: [READY TO SIGN] + +## Objective + +U18 on Mainnet networks of OP, Ink, Metal, Mode, Zora, Arena-Z, Swell. + +## Simulation & Signing + +### For Signers + +```bash +# Change directory to the correct task +cd src/tasks/eth/040-U18-op-ink-mmz-arena-swell + +# Command to simulate +just simulate-stack eth 040-U18-op-ink-mmz-arena-swell + +# Command to sign +just sign-stack eth 040-U18-op-ink-mmz-arena-swell +``` + +### For Facilitators, after signatures have been collected + +```bash +# Change directory to the correct task +cd src/tasks/eth/040-U18-op-ink-mmz-arena-swell + +# Command to approve +SIGNATURES=0x just approve + +# Command to execute +just execute + +# Add USE_KEYSTORE=1 to the above if you are using a local keystore instead of a connected Ledger +``` diff --git a/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/VALIDATION.md b/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/VALIDATION.md new file mode 100644 index 000000000..37ef5d10f --- /dev/null +++ b/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/VALIDATION.md @@ -0,0 +1,29 @@ +# Validation + +This document can be used to validate the inputs and result of the execution of the upgrade transaction which you are +signing. + +## Expected Domain and Message Hashes + +Validate the domain and message hashes. These values should match both the values on your ledger and +the values printed to the terminal when you run the task. + +> [!CAUTION] +> +> Before signing, ensure the below hashes match what is on your ledger. +> +> ### Nested Safe 1 (Foundation): `0x847B5c174615B1B7fDF770882256e2D3E95b9D92` +> +> - Domain Hash: `0xa4a9c312badf3fcaa05eafe5dc9bee8bd9316c78ee8b0bebe3115bb21b732672` +> - Message Hash: `0x96c68390b307d2412bada8db68e29c3a8d00afff96cd97ec86cb533c84d1c841` +> +> ### Nested Safe 2 (Security Council): `0xc2819DC788505Aac350142A7A707BF9D03E3Bd03` +> +> - Domain Hash: `0xdf53d510b56e539b90b369ef08fce3631020fbf921e3136ea5f8747c20bce967` +> - Message Hash: `0x1f6a88fdb49cafc4af76182fe1783d07faac8bef1ddb25fccd068be87b403b59` + +## Task Calldata + +``` +0x82ad56cb00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000050f47b43c24f40b92c873fa0704d4207586d0c9f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002e4cbeda5a700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007000000000000000000000000229047fed2591dbec1ef1118d64f7af3db9eb290033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000062c0a111929fa32cec2f76adba54c16afb6e8364033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa0000000000000000000000007bd909970b0eedcf078de6aeff23ce571663b8aa033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa0000000000000000000000005e6432f18bc5d497b1ab2288a025fbf9d69e2221033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa000000000000000000000000a3cab0126d5f504b071b81a3e8a2bbbf17930d86033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000034a564bbd863c4bf73eca711cf38a77c4ccbdd6a033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa000000000000000000000000d3d4c6b703978a5d24fecf3a70a51127667ff1a4033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000000000000000000000000000000000000 +``` diff --git a/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/config.toml b/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/config.toml new file mode 100644 index 000000000..edb86a445 --- /dev/null +++ b/src/tasks/eth/040-U18-op-ink-mmz-arena-swell/config.toml @@ -0,0 +1,94 @@ +# U18 Mainnet networks (OP, Ink, Metal, Mode, Zora, Arena-z, Swell) +l2chains = [ + {name = "OP Mainnet", chainId = 10}, + {name = "Ink", chainId = 57073}, + {name = "Metal L2", chainId = 1750}, + {name = "Mode", chainId = 34443}, + {name = "Zora", chainId = 7777777}, + {name = "arena-z", chainId = 7897}, + {name = "Swellchain", chainId = 1923} +] + + +templateName = "OPCMUpgradeV600" + +# U18 prestates: https://www.notion.so/oplabs/Upgrade-18-Governance-Post-2d1f153ee162807db0deee6100c9ad5a?source=copy_link#2d1f153ee16280b197bcf82b759ad1d6 + + +# OP Mainnet (Permissionless) +[[opcmUpgrades]] +chainId = 10 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "" # No errors expected + +# Ink Mainnet (Permissionless) +[[opcmUpgrades]] +chainId = 57073 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "" # No errors expected + +# Metal (Permissioned) +[[opcmUpgrades]] +chainId = 1750 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + +# Mode (Permissioned) +[[opcmUpgrades]] +chainId = 34443 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + +# Zora (Permissioned) +[[opcmUpgrades]] +chainId = 7777777 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + +# Arena-Z (Permissioned) +[[opcmUpgrades]] +chainId = 7897 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + +# Swell (Permissioned) +[[opcmUpgrades]] +chainId = 1923 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + + +[addresses] +OPCM = "0x50f47b43c24f40b92c873fa0704d4207586d0c9f" # v600 OPCM source: https://github.com/ethereum-optimism/superchain-registry/blob/c84ed822ae5a65500d8c0e323460fa688cfcca22/validation/standard/standard-versions-mainnet.toml#L23 + + +[stateOverrides] +# ProxyAdminOwner +0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 31} +] +# Foundation Upgrades Safe +0x847B5c174615B1B7fDF770882256e2D3E95b9D92 = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 49} +] +# Security Council +0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 50} +] diff --git a/src/tasks/eth/041-U18-uni/.env b/src/tasks/eth/041-U18-uni/.env new file mode 100644 index 000000000..adf17d369 --- /dev/null +++ b/src/tasks/eth/041-U18-uni/.env @@ -0,0 +1 @@ +TENDERLY_GAS=15000000 diff --git a/src/tasks/eth/041-U18-uni/README.md b/src/tasks/eth/041-U18-uni/README.md new file mode 100644 index 000000000..19f44591a --- /dev/null +++ b/src/tasks/eth/041-U18-uni/README.md @@ -0,0 +1,37 @@ +# 041-U18-uni + +Status: [READY TO SIGN] + +## Objective + +U18 on Unichain Mainnet. + +## Simulation & Signing + +### For Signers + +```bash +# Change directory to the correct task +cd src/tasks/eth/041-U18-uni + +# Command to simulate +just simulate-stack eth 041-U18-uni + +# Command to sign +just sign-stack eth 041-U18-uni +``` + +### For Facilitators, after signatures have been collected + +```bash +# Change directory to the correct task +cd src/tasks/eth/041-U18-uni + +# Command to approve +SIGNATURES=0x just approve + +# Command to execute +just execute + +# Add USE_KEYSTORE=1 to the above if you are using a local keystore instead of a connected Ledger +``` diff --git a/src/tasks/eth/041-U18-uni/VALIDATION.md b/src/tasks/eth/041-U18-uni/VALIDATION.md new file mode 100644 index 000000000..109b2cbd8 --- /dev/null +++ b/src/tasks/eth/041-U18-uni/VALIDATION.md @@ -0,0 +1,34 @@ +# Validation + +This document can be used to validate the inputs and result of the execution of the upgrade transaction which you are +signing. + +## Expected Domain and Message Hashes + +Validate the domain and message hashes. These values should match both the values on your ledger and +the values printed to the terminal when you run the task. + +> [!CAUTION] +> +> Before signing, ensure the below hashes match what is on your ledger. +> +> ### Nested Safe 1 (Foundation): `0x847B5c174615B1B7fDF770882256e2D3E95b9D92` +> +> - Domain Hash: `0xa4a9c312badf3fcaa05eafe5dc9bee8bd9316c78ee8b0bebe3115bb21b732672` +> - Message Hash: `0x1778cea8cd5b0000a075d379a09adb2892e71e2d3a1862ae97770fa93fdf7fb8` +> +> ### Nested Safe 2 (Security Council): `0xc2819DC788505Aac350142A7A707BF9D03E3Bd03` +> +> - Domain Hash: `0xdf53d510b56e539b90b369ef08fce3631020fbf921e3136ea5f8747c20bce967` +> - Message Hash: `0x19719ef8d3e5a825bb29f04be4160f50cb1a538857a10423b65d74320feea164` +> +> ### Nested Safe 3 (Chain Governor): `0xb0c4C487C5cf6d67807Bc2008c66fa7e2cE744EC` +> +> - Domain Hash: `0x4f0b6efb6c01fa7e127a0ff87beefbeb53e056d30d3216c5ac70371b909ca66d` +> - Message Hash: `0xb5b5d8954e59f023bc69a476b742bc02356dc0e2bf5026245fa3d1ccc86396fd` + +## Task Calldata + +``` +0x82ad56cb00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000050f47b43c24f40b92c873fa0704d4207586d0c9f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a4cbeda5a700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c407398d063f942febbcc6f80a156b47f3f1bda6033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000000000000000000000000000000000000 +``` \ No newline at end of file diff --git a/src/tasks/eth/041-U18-uni/config.toml b/src/tasks/eth/041-U18-uni/config.toml new file mode 100644 index 000000000..f379be064 --- /dev/null +++ b/src/tasks/eth/041-U18-uni/config.toml @@ -0,0 +1,43 @@ +# U18 Unichain Mainnet +l2chains = [ + {name = "Unichain", chainId = 130} +] + + +templateName = "OPCMUpgradeV600" + + +# Unichain (Permissionless) +[[opcmUpgrades]] +chainId = 130 +# U18 prestates: https://www.notion.so/oplabs/Upgrade-18-Governance-Post-2d1f153ee162807db0deee6100c9ad5a?source=copy_link#2d1f153ee16280b197bcf82b759ad1d6 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "OVERRIDES-L1PAOMULTISIG" +# OVERRIDES-L1PAOMULTISIG: this is expected as they are not using the same L1PAO as OP Mainnet + + +[addresses] +OPCM = "0x50f47b43c24f40b92c873fa0704d4207586d0c9f" # v600 OPCM source: https://github.com/ethereum-optimism/superchain-registry/blob/c84ed822ae5a65500d8c0e323460fa688cfcca22/validation/standard/standard-versions-mainnet.toml#L23 + + +[stateOverrides] +# Unichain 3/3 (L1PAO) +0x6d5B183F538ABB8572F5cD17109c617b994D5833 = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 8} +] + +# Unichain Operations Safe +0xb0c4C487C5cf6d67807Bc2008c66fa7e2cE744EC = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 15} +] + +# Foundation Upgrade Safe +0x847B5c174615B1B7fDF770882256e2D3E95b9D92 = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 50} +] + +# Security Council +0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 51} +] diff --git a/src/tasks/eth/042-U18-soneium/.env b/src/tasks/eth/042-U18-soneium/.env new file mode 100644 index 000000000..adf17d369 --- /dev/null +++ b/src/tasks/eth/042-U18-soneium/.env @@ -0,0 +1 @@ +TENDERLY_GAS=15000000 diff --git a/src/tasks/eth/042-U18-soneium/README.md b/src/tasks/eth/042-U18-soneium/README.md new file mode 100644 index 000000000..972c3de03 --- /dev/null +++ b/src/tasks/eth/042-U18-soneium/README.md @@ -0,0 +1,37 @@ +# 042-U18-soneium + +Status: [READY TO SIGN] + +## Objective + +U18 on Soneium Mainnet. + +## Simulation & Signing + +### For Signers + +```bash +# Change directory to the correct task +cd src/tasks/eth/042-U18-soneium + +# Command to simulate +just simulate-stack eth 042-U18-soneium + +# Command to sign +just sign-stack eth 042-U18-soneium +``` + +### For Facilitators, after signatures have been collected + +```bash +# Change directory to the correct task +cd src/tasks/eth/042-U18-soneium + +# Command to approve +SIGNATURES=0x just approve + +# Command to execute +just execute + +# Add USE_KEYSTORE=1 to the above if you are using a local keystore instead of a connected Ledger +``` diff --git a/src/tasks/eth/042-U18-soneium/VALIDATION.md b/src/tasks/eth/042-U18-soneium/VALIDATION.md new file mode 100644 index 000000000..e06992e10 --- /dev/null +++ b/src/tasks/eth/042-U18-soneium/VALIDATION.md @@ -0,0 +1,29 @@ +# Validation + +This document can be used to validate the inputs and result of the execution of the upgrade transaction which you are +signing. + +## Expected Domain and Message Hashes + +Validate the domain and message hashes. These values should match both the values on your ledger and +the values printed to the terminal when you run the task. + +> [!CAUTION] +> +> Before signing, ensure the below hashes match what is on your ledger. +> +> ### Nested Safe 1 (Foundation): `0x847B5c174615B1B7fDF770882256e2D3E95b9D92` +> +> - Domain Hash: `0xa4a9c312badf3fcaa05eafe5dc9bee8bd9316c78ee8b0bebe3115bb21b732672` +> - Message Hash: `0x155c69ca23d180898a5000cbe6c52efd569efc500405f03f6049dbf85bf3e0ff` +> +> ### Nested Safe 2 (Security Council): `0xc2819DC788505Aac350142A7A707BF9D03E3Bd03` +> +> - Domain Hash: `0xdf53d510b56e539b90b369ef08fce3631020fbf921e3136ea5f8747c20bce967` +> - Message Hash: `0x1beacb71be3f73ebe422d3331e5b829f69b2b2770741a84bf6135147df1b2f3f` + +## Task Calldata + +``` +0x82ad56cb00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000050f47b43c24f40b92c873fa0704d4207586d0c9f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a4cbeda5a7000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000007a8ed66b319911a0f3e7288bddab30d9c0c875c3033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000000000000000000000000000000000000 +``` diff --git a/src/tasks/eth/042-U18-soneium/config.toml b/src/tasks/eth/042-U18-soneium/config.toml new file mode 100644 index 000000000..d41a73824 --- /dev/null +++ b/src/tasks/eth/042-U18-soneium/config.toml @@ -0,0 +1,37 @@ +# U18 Soneium Mainnet +l2chains = [ + {name = "Soneium", chainId = 1868} +] + + +templateName = "OPCMUpgradeV600" + + +# Soneium Mainnet (Permissioned) +[[opcmUpgrades]] +chainId = 1868 +# U18 prestates: https://www.notion.so/oplabs/Upgrade-18-Governance-Post-2d1f153ee162807db0deee6100c9ad5a?source=copy_link#2d1f153ee16280b197bcf82b759ad1d6 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + + +[addresses] +OPCM = "0x50f47b43c24f40b92c873fa0704d4207586d0c9f" # v600 OPCM source: https://github.com/ethereum-optimism/superchain-registry/blob/c84ed822ae5a65500d8c0e323460fa688cfcca22/validation/standard/standard-versions-mainnet.toml#L23 + + +[stateOverrides] +# ProxyAdminOwner +0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 32} +] +# Foundation Upgrades Safe +0x847B5c174615B1B7fDF770882256e2D3E95b9D92 = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 51} +] +# Security Council +0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 52} +] diff --git a/src/tasks/eth/044-fos-rotation/README.md b/src/tasks/eth/044-fos-rotation/README.md new file mode 100644 index 000000000..6cb641b7f --- /dev/null +++ b/src/tasks/eth/044-fos-rotation/README.md @@ -0,0 +1,21 @@ +# 044-fos-rotation + +Status: READY TO SIGN + +## Objective + +This task rotates a signer on the FoundationOperationsSafe: +- Removes: `0x69acfE2096Dfb8d5A041eF37693553c48d9BFd02` +- Adds: `0xc222ab08333109243B1f4E2a80e3D0A190714AB5` + +## Simulation & Signing + +Simulation commands: +```bash +SIMULATE_WITHOUT_LEDGER=1 just simulate-stack eth 044-fos-rotation +``` + +Signing commands: +```bash +just sign-stack eth 044-fos-rotation +``` diff --git a/src/tasks/eth/044-fos-rotation/VALIDATION.md b/src/tasks/eth/044-fos-rotation/VALIDATION.md new file mode 100644 index 000000000..8cb3a3f74 --- /dev/null +++ b/src/tasks/eth/044-fos-rotation/VALIDATION.md @@ -0,0 +1,69 @@ +# Validation + +This document can be used to validate the inputs and result of the execution of the transaction which you are +signing. + +The steps are: + +1. [Validate the Domain and Message Hashes](#expected-domain-and-message-hashes) +2. [Verifying the transaction input](#understanding-task-calldata) + +## Expected Domain and Message Hashes + +First, we need to validate the domain and message hashes. These values should match both the values on your ledger and +the values printed to the terminal when you run the task. + +> [!CAUTION] +> +> Before signing, ensure the below hashes match what is on your ledger. +> +> ### Single Safe Signer Data +> +> - Domain Hash: `0x2e5ad244d335c45fbace4ebd1736b0fad81b01591a2819baedad311ead5bce76` +> - Message Hash: `0xe50e9872ef896ed2a00a734df7510b2a7921c78d15cba7750ed11a536b396122` + +## Understanding Task Calldata + +This document provides a detailed analysis of the final calldata executed on-chain for the signer rotation. + +By reconstructing the calldata, we can confirm that the execution precisely implements the approved plan with no unexpected modifications or side effects. + + +### Inputs to `safe.swapOwner()` + +`safe.swapOwner()` function is called with the address to be removed and the previous owner: + +- The address of the new signer: `0xc222ab08333109243B1f4E2a80e3D0A190714AB5` +- The address of the signer to be removed: `0x69acfE2096Dfb8d5A041eF37693553c48d9BFd02` +- The address of the previous signer: `0x4d014f3c5f33aa9cd1dc29ce29618d07ae666d15` + +Thus, the command to encode the calldata is: + +```bash +cast calldata 'swapOwner(address, address, address)' "0x4d014f3c5f33aa9cd1dc29ce29618d07ae666d15" "0x69acfE2096Dfb8d5A041eF37693553c48d9BFd02" "0xc222ab08333109243B1f4E2a80e3D0A190714AB5" +``` + +### Inputs to `Multicall3DelegateCall` + +The output from the previous section becomes the `data` in the argument to the `Multicall3DelegateCall.aggregate3Value()` function. + +This function is called with a tuple of four elements: + +Call3 struct for Multicall3DelegateCall: + +- `target`: `0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A` - Foundation Operations Safe +- `allowFailure`: false +- `value`: 0 +- `callData`: `0xe318b52b0000000000000000000000004d014f3c5f33aa9cd1dc29ce29618d07ae666d1500000000000000000000000069acfe2096dfb8d5a041ef37693553c48d9bfd02000000000000000000000000c222ab08333109243b1f4e2a80e3d0a190714ab5` + +Command to encode: + +```bash +cast calldata 'aggregate3Value((address,bool,uint256,bytes)[])' "[(0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A,false,0,0xe318b52b0000000000000000000000004d014f3c5f33aa9cd1dc29ce29618d07ae666d1500000000000000000000000069acfe2096dfb8d5a041ef37693553c48d9bfd02000000000000000000000000c222ab08333109243b1f4e2a80e3d0a190714ab5)]" +``` + +The resulting calldata sent from the ProxyAdminOwner safe is thus: + +``` +0x174dea710000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000009ba6e03d8b90de867373db8cf1a58d2f7f006b3a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064e318b52b0000000000000000000000004d014f3c5f33aa9cd1dc29ce29618d07ae666d1500000000000000000000000069acfe2096dfb8d5a041ef37693553c48d9bfd02000000000000000000000000c222ab08333109243b1f4e2a80e3d0a190714ab500000000000000000000000000000000000000000000000000000000 +``` diff --git a/src/tasks/eth/044-fos-rotation/config.toml b/src/tasks/eth/044-fos-rotation/config.toml new file mode 100644 index 000000000..55c6b5668 --- /dev/null +++ b/src/tasks/eth/044-fos-rotation/config.toml @@ -0,0 +1,18 @@ +templateName = "GnosisSafeRotateSigner" + +safeAddressString = "FoundationOperationsSafe" + +ownerToRemove = "0x69acfE2096Dfb8d5A041eF37693553c48d9BFd02" +ownerToAdd = "0xc222ab08333109243B1f4E2a80e3D0A190714AB5" + +[stateOverrides] + + +0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A = [ + # This state override sets the nonce for the FOS contract address + # Key 0x5 corresponds to the nonce storage slot in Ethereum state + # Value 115 is the expected nonce value needed for this rotation + # This override is necessary to ensure the transaction executes with the correct nonce + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 115} +] + diff --git a/src/tasks/eth/045-fus-rotation/README.md b/src/tasks/eth/045-fus-rotation/README.md new file mode 100644 index 000000000..993287199 --- /dev/null +++ b/src/tasks/eth/045-fus-rotation/README.md @@ -0,0 +1,21 @@ +# 045-fus-rotation + +Status: READY TO SIGN + +## Objective + +This task rotates a signer on the FoundationUpgradeSafe: +- Removes: `0x69acfE2096Dfb8d5A041eF37693553c48d9BFd02` +- Adds: `0xc222ab08333109243B1f4E2a80e3D0A190714AB5` + +## Simulation & Signing + +Simulation commands: +```bash +SIMULATE_WITHOUT_LEDGER=1 just simulate-stack eth 045-fus-rotation +``` + +Signing commands: +```bash +just sign-stack eth 045-fus-rotation +``` diff --git a/src/tasks/eth/045-fus-rotation/VALIDATION.md b/src/tasks/eth/045-fus-rotation/VALIDATION.md new file mode 100644 index 000000000..27e27a275 --- /dev/null +++ b/src/tasks/eth/045-fus-rotation/VALIDATION.md @@ -0,0 +1,69 @@ +# Validation + +This document can be used to validate the inputs and result of the execution of the transaction which you are +signing. + +The steps are: + +1. [Validate the Domain and Message Hashes](#expected-domain-and-message-hashes) +2. [Verifying the transaction input](#understanding-task-calldata) + +## Expected Domain and Message Hashes + +First, we need to validate the domain and message hashes. These values should match both the values on your ledger and +the values printed to the terminal when you run the task. + +> [!CAUTION] +> +> Before signing, ensure the below hashes match what is on your ledger. +> +> ### Single Safe Signer Data +> +> - Domain Hash: `0xa4a9c312badf3fcaa05eafe5dc9bee8bd9316c78ee8b0bebe3115bb21b732672` +> - Message Hash: `0xe00aa5702a88a72f2aaca7ec04dd7d7d00aaaf0f2302bf0a34c591d303d730d2` + +## Understanding Task Calldata + +This document provides a detailed analysis of the final calldata executed on-chain for the signer rotation. + +By reconstructing the calldata, we can confirm that the execution precisely implements the approved plan with no unexpected modifications or side effects. + + +### Inputs to `safe.swapOwner()` + +`safe.swapOwner()` function is called with the address to be removed and the previous owner: + +- The address of the new signer: `0xc222ab08333109243B1f4E2a80e3D0A190714AB5` +- The address of the signer to be removed: `0x69acfE2096Dfb8d5A041eF37693553c48d9BFd02` +- The address of the previous signer: `0x4d014f3c5f33aa9cd1dc29ce29618d07ae666d15` + +Thus, the command to encode the calldata is: + +```bash +cast calldata 'swapOwner(address, address, address)' "0x4d014f3c5f33aa9cd1dc29ce29618d07ae666d15" "0x69acfE2096Dfb8d5A041eF37693553c48d9BFd02" "0xc222ab08333109243B1f4E2a80e3D0A190714AB5" +``` + +### Inputs to `Multicall3DelegateCall` + +The output from the previous section becomes the `data` in the argument to the `Multicall3DelegateCall.aggregate3Value()` function. + +This function is called with a tuple of four elements: + +Call3 struct for Multicall3DelegateCall: + +- `target`: `0x847B5c174615B1B7fDF770882256e2D3E95b9D92` - Foundation Upgrade Safe +- `allowFailure`: false +- `value`: 0 +- `callData`: `0xe318b52b0000000000000000000000004d014f3c5f33aa9cd1dc29ce29618d07ae666d1500000000000000000000000069acfe2096dfb8d5a041ef37693553c48d9bfd02000000000000000000000000c222ab08333109243b1f4e2a80e3d0a190714ab5` + +Command to encode: + +```bash +cast calldata 'aggregate3Value((address,bool,uint256,bytes)[])' "[(0x847B5c174615B1B7fDF770882256e2D3E95b9D92,false,0,0xe318b52b0000000000000000000000004d014f3c5f33aa9cd1dc29ce29618d07ae666d1500000000000000000000000069acfe2096dfb8d5a041ef37693553c48d9bfd02000000000000000000000000c222ab08333109243b1f4e2a80e3d0a190714ab5)]" +``` + +The resulting calldata sent from the ProxyAdminOwner safe is thus: + +``` +0x174dea71000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000847b5c174615b1b7fdf770882256e2d3e95b9d920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064e318b52b0000000000000000000000004d014f3c5f33aa9cd1dc29ce29618d07ae666d1500000000000000000000000069acfe2096dfb8d5a041ef37693553c48d9bfd02000000000000000000000000c222ab08333109243b1f4e2a80e3d0a190714ab500000000000000000000000000000000000000000000000000000000 +``` diff --git a/src/tasks/eth/045-fus-rotation/config.toml b/src/tasks/eth/045-fus-rotation/config.toml new file mode 100644 index 000000000..0630b5b0c --- /dev/null +++ b/src/tasks/eth/045-fus-rotation/config.toml @@ -0,0 +1,12 @@ +templateName = "GnosisSafeRotateSigner" + +safeAddressString = "FoundationUpgradeSafe" + +ownerToRemove = "0x69acfE2096Dfb8d5A041eF37693553c48d9BFd02" +ownerToAdd = "0xc222ab08333109243B1f4E2a80e3D0A190714AB5" + +[stateOverrides] + +0x847B5c174615B1B7fDF770882256e2D3E95b9D92 = [ + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 52} +] diff --git a/src/tasks/eth/rehearsals/2026-01-21-R1-welcome/.env b/src/tasks/eth/rehearsals/2026-01-21-R1-welcome/.env new file mode 100644 index 000000000..663b00c13 --- /dev/null +++ b/src/tasks/eth/rehearsals/2026-01-21-R1-welcome/.env @@ -0,0 +1 @@ +TENDERLY_GAS=10000000 diff --git a/src/tasks/eth/rehearsals/2026-01-21-R1-welcome/config.toml b/src/tasks/eth/rehearsals/2026-01-21-R1-welcome/config.toml new file mode 100644 index 000000000..f468fddc4 --- /dev/null +++ b/src/tasks/eth/rehearsals/2026-01-21-R1-welcome/config.toml @@ -0,0 +1,9 @@ +templateName = "WelcomeToSuperchainOps" + +name = "Satoshi" # Enter your name here if you like. + +allowOverwrite = ["SecurityCouncil"] # We know that we want to overwrite the default SecurityCouncil address in [addresses]. + +[addresses] +TargetContract = "0x0fb11b4164894912f079de62699f4cc5a2271f0c" # This is the mainnet deployment. Sepolia deployment of target contract: 0x5c6623738B2a3a54edF1d46B2A85f959fe6b1f6b +SecurityCouncil = "0x348eebA2609645182872CCd75256D873e689fCFf" # This is the address of the multisig that you created in step 1. e.g. 0x799F5202AEBB41eC779e046e46a4D033d367d877. \ No newline at end of file diff --git a/src/tasks/sep/057-U18-op-ink-mmz-arena/.env b/src/tasks/sep/057-U18-op-ink-mmz-arena/.env new file mode 100644 index 000000000..adf17d369 --- /dev/null +++ b/src/tasks/sep/057-U18-op-ink-mmz-arena/.env @@ -0,0 +1 @@ +TENDERLY_GAS=15000000 diff --git a/src/tasks/sep/057-U18-op-ink-mmz-arena/README.md b/src/tasks/sep/057-U18-op-ink-mmz-arena/README.md new file mode 100644 index 000000000..485f5b99d --- /dev/null +++ b/src/tasks/sep/057-U18-op-ink-mmz-arena/README.md @@ -0,0 +1,37 @@ +# 057-U18-op-ink-mmz-arena + +Status: [EXECUTED](https://sepolia.etherscan.io/tx/0xa8e313347672ffe4a9893f27cf5861f70a04577ca3d33bcf2898dcae1bd9a2d0) + +## Objective + +U18 on Sepolia networks of OP, Ink, Metal, Mode, Zora, Arena-Z. + +## Simulation & Signing + +### For Signers + +```bash +# Change directory to the correct task +cd src/tasks/sep/057-U18-op-ink-mmz-arena + +# Command to simulate +just simulate-stack sep 057-U18-op-ink-mmz-arena + +# Command to sign +just sign-stack sep 057-U18-op-ink-mmz-arena +``` + +### For Facilitators, after signatures have been collected + +```bash +# Change directory to the correct task +cd src/tasks/sep/057-U18-op-ink-mmz-arena + +# Command to approve +SIGNATURES=0x just approve + +# Command to execute +just execute + +# Add USE_KEYSTORE=1 to the above if you are using a local keystore instead of a connected Ledger +``` diff --git a/src/tasks/sep/057-U18-op-ink-mmz-arena/VALIDATION.md b/src/tasks/sep/057-U18-op-ink-mmz-arena/VALIDATION.md new file mode 100644 index 000000000..1d054af91 --- /dev/null +++ b/src/tasks/sep/057-U18-op-ink-mmz-arena/VALIDATION.md @@ -0,0 +1,29 @@ +# Validation + +This document can be used to validate the inputs and result of the execution of the upgrade transaction which you are +signing. + +## Expected Domain and Message Hashes + +Validate the domain and message hashes. These values should match both the values on your ledger and +the values printed to the terminal when you run the task. + +> [!CAUTION] +> +> Before signing, ensure the below hashes match what is on your ledger. +> +> ### Security Council Safe (`0xf64bc17485f0B4Ea5F06A96514182FC4cB561977`) +> +> - Domain Hash: `0xbe081970e9fc104bd1ea27e375cd21ec7bb1eec56bfe43347c3e36c5d27b8533` +> - Message Hash: `0xcebb785596afe6d9edb0e2a07c55341b1d5b42a4ffffebd74cab0329cd105a2c` +> +> ### Foundation Safe (`0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B`) +> +> - Domain Hash: `0x37e1f5dd3b92a004a23589b741196c8a214629d4ea3a690ec8e41ae45c689cbb` +> - Message Hash: `0x7e834f657753d14022768e01ef18d222637c43732ea43aa3fffbab1338854c05` + +## Task Calldata + +``` +0x82ad56cb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f0a2e224519e876979ea6b2cd15ef5cc3d6703bd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000284cbeda5a700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006000000000000000000000000034edd2a225f7f429a63e0f1d2084b9e0a93b538033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000005c993e60179f28bf649a2bb5b00b5f4283bd525033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa0000000000000000000000005d63a8dc2737ce771aa4a6510d063b6ba2c4f6f2033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000015cd4f6e0ce3b4832b33cb9c6f6fe6fc246754c2033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa000000000000000000000000b54c7bfc223058773cf9b739cc5bd4095184fb08033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa0000000000000000000000005357be2d78aad17860570e14b74561840e959d4d033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000000000000000000000000000000000000 +``` diff --git a/src/tasks/sep/057-U18-op-ink-mmz-arena/config.toml b/src/tasks/sep/057-U18-op-ink-mmz-arena/config.toml new file mode 100644 index 000000000..3e4248512 --- /dev/null +++ b/src/tasks/sep/057-U18-op-ink-mmz-arena/config.toml @@ -0,0 +1,82 @@ +# U18 Sepolia networks (OP, Ink, Metal, Mode, Zora, Arena-z) +l2chains = [ + {name = "OP Sepolia Testnet", chainId = 11155420}, + {name = "Ink Sepolia Testnet", chainId = 763373}, + {name = "Metal L2 Testnet", chainId = 1740}, + {name = "Mode Testnet", chainId = 919}, + {name = "Zora Sepolia Testnet", chainId = 999999999}, + {name = "arena-z-testnet", chainId = 9899} +] + + +templateName = "OPCMUpgradeV600" + +# U18 prestates: https://www.notion.so/oplabs/Upgrade-18-Governance-Post-2d1f153ee162807db0deee6100c9ad5a?source=copy_link#2d1f153ee16280b197bcf82b759ad1d6 + + +# OP Sepolia Testnet (Permissionless) +[[opcmUpgrades]] +chainId = 11155420 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "" # No errors expected + +# Ink Sepolia Testnet (Permissionless) +[[opcmUpgrades]] +chainId = 763373 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "" # No errors expected + +# Metal L2 Testnet (Permissioned) +[[opcmUpgrades]] +chainId = 1740 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + +# Mode Testnet (Permissioned) +[[opcmUpgrades]] +chainId = 919 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + +# Zora Sepolia Testnet (Permissioned) +[[opcmUpgrades]] +chainId = 999999999 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "OVERRIDES-CHALLENGER,PLDG-10,CKDG-10" +# OVERRIDES-CHALLENGER: this is expected as the challenger is not the standard one +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + +# Arena-Z Testnet (Permissioned) +[[opcmUpgrades]] +chainId = 9899 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "PLDG-10,CKDG-10" +# PLDG-10: CANNON game type not found, expected as it's a Permissioned chain +# CKDG-10: CANNON_KONA game type not found, expected as it's a Permissioned chain + + +[addresses] +OPCM = "0xf0a2e224519e876979ea6b2cd15ef5cc3d6703bd" # v600 OPCM source: https://github.com/ethereum-optimism/superchain-registry/blob/c84ed822ae5a65500d8c0e323460fa688cfcca22/validation/standard/standard-versions-sepolia.toml#L23C56-L23C98 + + +[stateOverrides] +0x1Eb2fFc903729a0F03966B917003800b145F56E2 = [ # L1PAO + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 46} +] +0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 = [ # SC + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 60} +] +0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B = [ # FUS + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 65} +] diff --git a/src/tasks/sep/058-U18-soneium/.env b/src/tasks/sep/058-U18-soneium/.env new file mode 100644 index 000000000..adf17d369 --- /dev/null +++ b/src/tasks/sep/058-U18-soneium/.env @@ -0,0 +1 @@ +TENDERLY_GAS=15000000 diff --git a/src/tasks/sep/058-U18-soneium/README.md b/src/tasks/sep/058-U18-soneium/README.md new file mode 100644 index 000000000..99d1a3074 --- /dev/null +++ b/src/tasks/sep/058-U18-soneium/README.md @@ -0,0 +1,37 @@ +# 058-U18-soneium + +Status: [CANCELLED] + +## Objective + +U18 on Soneium Minato Testnet. + +## Simulation & Signing + +### For Signers + +```bash +# Change directory to the correct task +cd src/tasks/sep/058-U18-soneium + +# Command to simulate +just simulate-stack sep 058-U18-soneium + +# Command to sign +just sign-stack sep 058-U18-soneium +``` + +### For Facilitators, after signatures have been collected + +```bash +# Change directory to the correct task +cd src/tasks/sep/058-U18-soneium + +# Command to approve +SIGNATURES=0x just approve + +# Command to execute +just execute + +# Add USE_KEYSTORE=1 to the above if you are using a local keystore instead of a connected Ledger +``` diff --git a/src/tasks/sep/058-U18-soneium/VALIDATION.md b/src/tasks/sep/058-U18-soneium/VALIDATION.md new file mode 100644 index 000000000..115bacef6 --- /dev/null +++ b/src/tasks/sep/058-U18-soneium/VALIDATION.md @@ -0,0 +1,29 @@ +# Validation + +This document can be used to validate the inputs and result of the execution of the upgrade transaction which you are +signing. + +## Expected Domain and Message Hashes + +Validate the domain and message hashes. These values should match both the values on your ledger and +the values printed to the terminal when you run the task. + +> [!CAUTION] +> +> Before signing, ensure the below hashes match what is on your ledger. +> +> ### Security Council Safe (`0xf64bc17485f0B4Ea5F06A96514182FC4cB561977`) +> +> - Domain Hash: `0xbe081970e9fc104bd1ea27e375cd21ec7bb1eec56bfe43347c3e36c5d27b8533` +> - Message Hash: `0xe291177165d972f689f11b71b6ba6d0a5b7e98671b4054c0f91be52823573945` +> +> ### Foundation Safe (`0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B`) +> +> - Domain Hash: `0x37e1f5dd3b92a004a23589b741196c8a214629d4ea3a690ec8e41ae45c689cbb` +> - Message Hash: `0x6b4371cad5e356e7eea4324526ae0daa0c1740f16d51a28a8d973c302fe9dcac` + +## Task Calldata + +``` +0x82ad56cb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f0a2e224519e876979ea6b2cd15ef5cc3d6703bd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a4cbeda5a7000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000004ca9608fef202216bc21d543798ec854539baad3033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000000000000000000000000000000000000 +``` diff --git a/src/tasks/sep/058-U18-soneium/config.toml b/src/tasks/sep/058-U18-soneium/config.toml new file mode 100644 index 000000000..e77a8a767 --- /dev/null +++ b/src/tasks/sep/058-U18-soneium/config.toml @@ -0,0 +1,33 @@ +# U18 Soneium Minato Testnet +l2chains = [ + {name = "Soneium Testnet Minato", chainId = 1946} +] + + +templateName = "OPCMUpgradeV600" + + +# Soneium Minato Testnet (Permissionless) +[[opcmUpgrades]] +chainId = 1946 +# U18 prestates: https://www.notion.so/oplabs/Upgrade-18-Governance-Post-2d1f153ee162807db0deee6100c9ad5a?source=copy_link#2d1f153ee16280b197bcf82b759ad1d6 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "OVERRIDES-CHALLENGER" +# OVERRIDES-CHALLENGER: this is expected as it's not the standard OP Sepolia one + + +[addresses] +OPCM = "0xf0a2e224519e876979ea6b2cd15ef5cc3d6703bd" # v600 OPCM source: https://github.com/ethereum-optimism/superchain-registry/blob/c84ed822ae5a65500d8c0e323460fa688cfcca22/validation/standard/standard-versions-sepolia.toml#L23C56-L23C98 + + +[stateOverrides] +0x1Eb2fFc903729a0F03966B917003800b145F56E2 = [ # L1PAO + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 47} +] +0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 = [ # SC + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 61} +] +0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B = [ # FUS + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 66} +] diff --git a/src/tasks/sep/059-U18-uni/.env b/src/tasks/sep/059-U18-uni/.env new file mode 100644 index 000000000..adf17d369 --- /dev/null +++ b/src/tasks/sep/059-U18-uni/.env @@ -0,0 +1 @@ +TENDERLY_GAS=15000000 diff --git a/src/tasks/sep/059-U18-uni/README.md b/src/tasks/sep/059-U18-uni/README.md new file mode 100644 index 000000000..8060f9563 --- /dev/null +++ b/src/tasks/sep/059-U18-uni/README.md @@ -0,0 +1,37 @@ +# 059-U18-uni + +Status: [EXECUTED](https://sepolia.etherscan.io/tx/0x3a8dba3ce7739b215b18a8bab445c376e56ccee8403d15deacda43b7895583e2) + +## Objective + +U18 on Unichain Sepolia. + +## Simulation & Signing + +### For Signers + +```bash +# Change directory to the correct task +cd src/tasks/sep/059-U18-uni + +# Command to simulate +just simulate-stack sep 059-U18-uni + +# Command to sign +just sign-stack sep 059-U18-uni +``` + +### For Facilitators, after signatures have been collected + +```bash +# Change directory to the correct task +cd src/tasks/sep/059-U18-uni + +# Command to approve +SIGNATURES=0x just approve + +# Command to execute +just execute + +# Add USE_KEYSTORE=1 to the above if you are using a local keystore instead of a connected Ledger +``` diff --git a/src/tasks/sep/059-U18-uni/VALIDATION.md b/src/tasks/sep/059-U18-uni/VALIDATION.md new file mode 100644 index 000000000..607c41b75 --- /dev/null +++ b/src/tasks/sep/059-U18-uni/VALIDATION.md @@ -0,0 +1,24 @@ +# Validation + +This document can be used to validate the inputs and result of the execution of the upgrade transaction which you are +signing. + +## Expected Domain and Message Hashes + +Validate the domain and message hashes. These values should match both the values on your ledger and +the values printed to the terminal when you run the task. + +> [!CAUTION] +> +> Before signing, ensure the below hashes match what is on your ledger. +> +> ### Safe (L1ProxyAdminOwner): `0xd363339eE47775888Df411A163c586a8BdEA9dbf` - This safe is not nested. +> +> - Domain Hash: `0x2fedecce87979400ff00d5cec4c77da942d43ab3b9db4a5ffc51bb2ef498f30b` +> - Message Hash: `0x56585becf1613478b43ba98abfcfa9df19abf62ebaa4a2cc127ab705b9d3135c` + +## Task Calldata + +``` +0x82ad56cb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f0a2e224519e876979ea6b2cd15ef5cc3d6703bd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a4cbeda5a700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000aee94b9ab7752d3f7704bde212c0c6a0b701571d033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa00000000000000000000000000000000000000000000000000000000 +``` \ No newline at end of file diff --git a/src/tasks/sep/059-U18-uni/config.toml b/src/tasks/sep/059-U18-uni/config.toml new file mode 100644 index 000000000..fa59802e6 --- /dev/null +++ b/src/tasks/sep/059-U18-uni/config.toml @@ -0,0 +1,28 @@ +# U18 Unichain Sepolia +l2chains = [ + {name = "Unichain Sepolia Testnet", chainId = 1301} +] + + +templateName = "OPCMUpgradeV600" + + +# Unichain Sepolia Testnet (Permissionless) +[[opcmUpgrades]] +chainId = 1301 +# U18 prestates: https://www.notion.so/oplabs/Upgrade-18-Governance-Post-2d1f153ee162807db0deee6100c9ad5a?source=copy_link#2d1f153ee16280b197bcf82b759ad1d6 +cannonPrestate = "0x033c000916b4a88cfffeceddd6cf0f4be3897a89195941e5a7c3f8209b4dbb6e" +cannonKonaPrestate = "0x0323914d3050e80c3d09da528be54794fde60cd26849cd3410dde0da7cd7d4fa" +expectedValidationErrors = "OVERRIDES-L1PAOMULTISIG,OVERRIDES-CHALLENGER" +# OVERRIDES-L1PAOMULTISIG,OVERRIDES-CHALLENGER: these are expected as they are not the standard OP Sepolia ones + + +[addresses] +OPCM = "0xf0a2e224519e876979ea6b2cd15ef5cc3d6703bd" # v600 OPCM source: https://github.com/ethereum-optimism/superchain-registry/blob/c84ed822ae5a65500d8c0e323460fa688cfcca22/validation/standard/standard-versions-sepolia.toml#L23C56-L23C98 + + +[stateOverrides] +# Unichain Sepolia ProxyAdminOwner: +0xd363339eE47775888Df411A163c586a8BdEA9dbf = [ # L1PAO + {key = "0x0000000000000000000000000000000000000000000000000000000000000005", value = 42} +] diff --git a/test/tasks/StackedSimulator.t.sol b/test/tasks/StackedSimulator.t.sol index bb3d2ec51..4749cd0de 100644 --- a/test/tasks/StackedSimulator.t.sol +++ b/test/tasks/StackedSimulator.t.sol @@ -262,7 +262,9 @@ contract StackedSimulatorUnitTest is Test { function testStringConversionShortString() public { StackedSimulator ss = new StackedSimulator(); - vm.expectRevert("StackedSimulator: Prefix must have 3 characters."); + vm.expectRevert( + "StackedSimulator: Invalid task name format. Valid formats are either: 1) A 3-digit prefix followed by a descriptive name (e.g., '123-deploy-contract'), or 2) A date-based format 'YYYY-MM-DD-RN' where YYYY=year, MM=month, DD=day, R=rehearsal indicator (must be 'R'), and N=sequence number (e.g., '2025-01-08-R1')." + ); ss.convertPrefixToUint("12"); // Input with less than 3 characters } @@ -436,20 +438,26 @@ contract StackedSimulatorUnitTest is Test { function testConvertPrefixToUint_InvalidLength() public { StackedSimulator ss = new StackedSimulator(); - vm.expectRevert("StackedSimulator: Prefix must have 3 characters."); + vm.expectRevert( + "StackedSimulator: Invalid task name format. Valid formats are either: 1) A 3-digit prefix followed by a descriptive name (e.g., '123-deploy-contract'), or 2) A date-based format 'YYYY-MM-DD-RN' where YYYY=year, MM=month, DD=day, R=rehearsal indicator (must be 'R'), and N=sequence number (e.g., '2025-01-08-R1')." + ); ss.convertPrefixToUint("12-task-name"); // Only 2 characters } function testConvertPrefixToUint_TooLongPrefix() public { StackedSimulator ss = new StackedSimulator(); - vm.expectRevert("StackedSimulator: Prefix must have 3 characters."); + vm.expectRevert( + "StackedSimulator: Invalid task name format. Valid formats are either: 1) A 3-digit prefix followed by a descriptive name (e.g., '123-deploy-contract'), or 2) A date-based format 'YYYY-MM-DD-RN' where YYYY=year, MM=month, DD=day, R=rehearsal indicator (must be 'R'), and N=sequence number (e.g., '2025-01-08-R1')." + ); ss.convertPrefixToUint("1234-task-name"); // 4 characters } function testConvertPrefixToUint_NoHyphen() public { StackedSimulator ss = new StackedSimulator(); // The validation order is: length check first, then hyphen check - vm.expectRevert("StackedSimulator: Prefix must have 3 characters."); + vm.expectRevert( + "StackedSimulator: Invalid task name format. Valid formats are either: 1) A 3-digit prefix followed by a descriptive name (e.g., '123-deploy-contract'), or 2) A date-based format 'YYYY-MM-DD-RN' where YYYY=year, MM=month, DD=day, R=rehearsal indicator (must be 'R'), and N=sequence number (e.g., '2025-01-08-R1')." + ); ss.convertPrefixToUint("123taskname"); // No hyphen, but also wrong length } @@ -465,6 +473,67 @@ contract StackedSimulatorUnitTest is Test { ss.convertPrefixToUint("0x1-task-name"); // Hex string } + // Tests for date-based format + function testConvertPrefixToUint_ValidDateFormat() public { + StackedSimulator ss = new StackedSimulator(); + uint256 result = ss.convertPrefixToUint("2025-01-08-R1-welcome"); + // Expected: (2025 * 10000 + 1 * 100 + 8) * 10000 + 1 = 20250108 * 10000 + 1 = 202501080001 + assertEq(result, 202501080001, "Should correctly parse date-based format"); + } + + function testConvertPrefixToUint_DateFormatWithLargerRehearsalNumber() public { + StackedSimulator ss = new StackedSimulator(); + uint256 result = ss.convertPrefixToUint("2025-07-21-R15-task"); + // Expected: (2025 * 10000 + 7 * 100 + 21) * 10000 + 15 = 20250721 * 10000 + 15 = 202507210015 + assertEq(result, 202507210015, "Should correctly parse date with larger rehearsal number"); + } + + function testConvertPrefixToUint_InvalidYear() public { + StackedSimulator ss = new StackedSimulator(); + vm.expectRevert("StackedSimulator: Year must be <= 2100"); + ss.convertPrefixToUint("2101-01-08-R1-task"); // Year > 2100 + } + + function testConvertPrefixToUint_InvalidMonthTooHigh() public { + StackedSimulator ss = new StackedSimulator(); + vm.expectRevert("StackedSimulator: Month must be between 1 and 12"); + ss.convertPrefixToUint("2025-13-08-R1-task"); // Month > 12 + } + + function testConvertPrefixToUint_InvalidMonthZero() public { + StackedSimulator ss = new StackedSimulator(); + vm.expectRevert("StackedSimulator: Month must be between 1 and 12"); + ss.convertPrefixToUint("2025-00-08-R1-task"); // Month = 0 + } + + function testConvertPrefixToUint_InvalidDayTooHigh() public { + StackedSimulator ss = new StackedSimulator(); + vm.expectRevert("StackedSimulator: Day must be between 1 and 31"); + ss.convertPrefixToUint("2025-01-32-R1-task"); // Day > 31 + } + + function testConvertPrefixToUint_InvalidDayZero() public { + StackedSimulator ss = new StackedSimulator(); + vm.expectRevert("StackedSimulator: Day must be between 1 and 31"); + ss.convertPrefixToUint("2025-01-00-R1-task"); // Day = 0 + } + + function testConvertPrefixToUint_MissingRPrefix() public { + StackedSimulator ss = new StackedSimulator(); + vm.expectRevert( + "StackedSimulator: Date-based format requires 'R' prefix in fourth component (e.g., YYYY-MM-DD-RN)" + ); + ss.convertPrefixToUint("2025-01-08-1-task"); // Missing R prefix + } + + function testConvertPrefixToUint_LowercaseRPrefix() public { + StackedSimulator ss = new StackedSimulator(); + vm.expectRevert( + "StackedSimulator: Date-based format requires 'R' prefix in fourth component (e.g., YYYY-MM-DD-RN)" + ); + ss.convertPrefixToUint("2025-01-08-r1-task"); // Lowercase r instead of R + } + function testSortTasksLargeNumbers() public { StackedSimulator ss = new StackedSimulator(); StackedSimulator.TaskInfo[] memory input = new StackedSimulator.TaskInfo[](3);