From a7865882278beddc35ed60716d8d04ae9265cd11 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 15 Oct 2025 14:37:22 -0400 Subject: [PATCH 01/27] init run --- Makefile | 6 + .../.env | 22 ++ .../Makefile | 54 +++++ .../README.md | 193 ++++++++++++++++++ .../foundry.toml | 20 ++ .../script/UpdateRetirementTimestamp.s.sol | 83 ++++++++ .../template-update-retirement-timestamp/.env | 20 ++ .../Makefile | 54 +++++ .../README.md | 193 ++++++++++++++++++ .../foundry.toml | 20 ++ .../script/UpdateRetirementTimestamp.s.sol | 83 ++++++++ 11 files changed, 748 insertions(+) create mode 100644 mainnet/2025-10-15-update-retirement-timestamp/.env create mode 100644 mainnet/2025-10-15-update-retirement-timestamp/Makefile create mode 100644 mainnet/2025-10-15-update-retirement-timestamp/README.md create mode 100644 mainnet/2025-10-15-update-retirement-timestamp/foundry.toml create mode 100644 mainnet/2025-10-15-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol create mode 100644 setup-templates/template-update-retirement-timestamp/.env create mode 100644 setup-templates/template-update-retirement-timestamp/Makefile create mode 100644 setup-templates/template-update-retirement-timestamp/README.md create mode 100644 setup-templates/template-update-retirement-timestamp/foundry.toml create mode 100644 setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol diff --git a/Makefile b/Makefile index 4e81995f..c77b5c4b 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ SAFE_MANAGEMENT_DIR = $(network)/$(shell date +'%Y-%m-%d')-safe-swap-owner FUNDING_DIR = $(network)/$(shell date +'%Y-%m-%d')-funding SET_BASE_BRIDGE_PARTNER_THRESHOLD_DIR = $(network)/$(shell date +'%Y-%m-%d')-pause-bridge-base PAUSE_BRIDGE_BASE_DIR = $(network)/$(shell date +'%Y-%m-%d')-pause-bridge-base +UPDATE_RETIREMENT_TIMESTAMP_DIR=$(network)/$(shell date +'%Y-%m-%d')-update-retirement-timestamp TEMPLATE_GENERIC = setup-templates/template-generic TEMPLATE_GAS_INCREASE = setup-templates/template-gas-increase @@ -13,6 +14,7 @@ TEMPLATE_SAFE_MANAGEMENT = setup-templates/template-safe-management TEMPLATE_FUNDING = setup-templates/template-funding TEMPLATE_SET_BASE_BRIDGE_PARTNER_THRESHOLD = setup-templates/template-set-bridge-partner-threshold TEMPLATE_PAUSE_BRIDGE_BASE = setup-templates/template-pause-bridge-base +TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP= setup-templates/template-update-retirement-timestamp ifndef $(GOPATH) GOPATH=$(shell go env GOPATH) @@ -61,6 +63,10 @@ setup-bridge-pause: rm -rf $(TEMPLATE_PAUSE_BRIDGE_BASE)/cache $(TEMPLATE_PAUSE_BRIDGE_BASE)/lib $(TEMPLATE_PAUSE_BRIDGE_BASE)/out cp -r $(TEMPLATE_PAUSE_BRIDGE_BASE) $(PAUSE_BRIDGE_BASE_DIR) +setup-update-retirement-timestamp: + rm -rf $(TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP)/cache $(TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP)/lib $(TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP)/out + cp -r $(TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP) $(UPDATE_RETIREMENT_TIMESTAMP_DIR) + ## # Solidity Setup ## diff --git a/mainnet/2025-10-15-update-retirement-timestamp/.env b/mainnet/2025-10-15-update-retirement-timestamp/.env new file mode 100644 index 00000000..0185f43c --- /dev/null +++ b/mainnet/2025-10-15-update-retirement-timestamp/.env @@ -0,0 +1,22 @@ +OP_COMMIT=ad12b8da0785da6938ebdb9c477c0f55d6ae834d +BASE_CONTRACTS_COMMIT=132ba0f33cb455ffff783924588df8864767bd9c + +CURRENT_RETIREMENT_TIMESTAMP=1759862579 + +# Mainnet Config +SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 + +OWNER_SAFE=0x7bB41C3008B3f03FE483B28b8DB90e19Cf07595c +CB_SIGNER_SAFE_ADDR=0x9855054731540A48b28990B63DcF4f33d8AE46A1 +CB_NESTED_SAFE_ADDR=0x20AcF55A3DCfe07fC4cecaCFa1628F788EC8A4Dd +CB_SC_SAFE_ADDR=0x9C4a57Feb77e294Fd7BF5EBE9AB01CAA0a90A110 +OP_SIGNER_SAFE_ADDR=0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A + +# # Sepolia Config +# SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 + +# OWNER_SAFE=0x0fe884546476dDd290eC46318785046ef68a0BA9 +# CB_SIGNER_SAFE_ADDR=0x646132A1667ca7aD00d36616AFBA1A28116C770A +# CB_NESTED_SAFE_ADDR=0x5dfEB066334B67355A15dc9b67317fD2a2e1f77f +# CB_SC_SAFE_ADDR=0x6AF0674791925f767060Dd52f7fB20984E8639d8 +# OP_SIGNER_SAFE_ADDR=0x6AF0674791925f767060Dd52f7fB20984E8639d8 diff --git a/mainnet/2025-10-15-update-retirement-timestamp/Makefile b/mainnet/2025-10-15-update-retirement-timestamp/Makefile new file mode 100644 index 00000000..ce9b646e --- /dev/null +++ b/mainnet/2025-10-15-update-retirement-timestamp/Makefile @@ -0,0 +1,54 @@ +include ../../Makefile +include ../../Multisig.mk + +include ../.env +include .env + +ifndef LEDGER_ACCOUNT +override LEDGER_ACCOUNT = 0 +endif + +# Mainnet Commands + +# OWNER_SAFE/ +# ├── CB_SIGNER_SAFE_ADDR/ +# │ ├── CB_NESTED_SAFE_ADDR/ +# │ │ └── Signers +# │ └── CB_SC_SAFE_ADDR/ +# │ └── Signers +# └── OP_SIGNER_SAFE_ADDR/ +# └── Signers + +RPC_URL = $(L1_RPC_URL) +SCRIPT_NAME = UpdateRetirementTimestamp + +# CB +.PHONY: sign-cb +sign-cb: + $(call MULTISIG_SIGN,$(CB_NESTED_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR)) + +.PHONY: approve-cb +approve-cb: + $(call MULTISIG_APPROVE,$(CB_NESTED_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR),$(SIGNATURES)) + +.PHONY: sign-cb-sc +sign-cb-sc: + $(call MULTISIG_SIGN,$(CB_SC_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR)) + +.PHONY: approve-cb-sc +approve-cb-sc: + $(call MULTISIG_APPROVE,$(CB_SC_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR),$(SIGNATURES)) + +# OP +.PHONY: sign-op +sign-op: + $(call MULTISIG_SIGN,$(OP_SIGNER_SAFE_ADDR)) + +.PHONY: approve-op +approve-op: + $(call MULTISIG_APPROVE,$(OP_SIGNER_SAFE_ADDR),$(SIGNATURES)) + +# Execute +.PHONY: execute +execute: + $(call MULTISIG_EXECUTE,0x) diff --git a/mainnet/2025-10-15-update-retirement-timestamp/README.md b/mainnet/2025-10-15-update-retirement-timestamp/README.md new file mode 100644 index 00000000..bbff6d1b --- /dev/null +++ b/mainnet/2025-10-15-update-retirement-timestamp/README.md @@ -0,0 +1,193 @@ +# Upgrade Fault Proofs + +Status: PENDING + +## Description + +This task contains two scripts. One for deploying new versions of the `FaultDisputeGame` and `PermissionedDisputeGame` contracts, and one for updating the `DisputeGameFactory` contract to reference the new dispute game contracts. + +## Procedure + +### 1. Update repo: + +```bash +cd contract-deployments +git pull +cd /-upgrade-fault-proofs +make deps +``` + +### 2. Setup Ledger + +Your Ledger needs to be connected and unlocked. The Ethereum +application needs to be opened on Ledger with the message "Application +is ready". + +### 3. Run relevant script(s) + +#### 3.1 Deploy new Dispute Game Implementations + +```bash +make deploy +``` + +This will output the new addresses of the `FaultDisputeGame` and `PermissionedDisputeGame` contracts to an `addresses.json` file. You will need to commit this file to the repo before signers can sign. + +#### 3.2 Sign the transaction + +**If on testnet**: + +```bash +make sign +``` + +**If on mainnet**: + +Coinbase signer: + +```bash +make sign-cb +``` + +Op signer: + +```bash +make sign-op +``` + +You will see a "Simulation link" from the output. + +Paste this URL in your browser. A prompt may ask you to choose a +project, any project will do. You can create one if necessary. + +Click "Simulate Transaction". + +We will be performing 3 validations and extract the domain hash and message hash to approve on your Ledger: + +1. Validate integrity of the simulation. +2. Validate correctness of the state diff. +3. Validate and extract domain hash and message hash to approve. + +##### 3.2.1 Validate integrity of the simulation. + +Make sure you are on the "Summary" tab of the tenderly simulation, to +validate integrity of the simulation, we need to check the following: + +1. "Network": Check the network is Sepolia or Mainnet. +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 see the derivation path Note above. + +##### 3.2.2. Validate correctness of the state diff. + +Now click on the "State" tab, and refer to the [State Validations](./VALIDATION.md) instructions for the transaction you are signing. +Once complete return to this document to complete the signing. + +##### 3.2.3. Extract the domain hash and the message hash to approve. + +Now that we have verified the transaction performs the right +operation, we need to extract the domain hash and the message hash to +approve. + +Go back to the "Summary" tab, and find the +`GnosisSafe.checkSignatures` (for OP signers) or `Safe.checkSignatures` (for Coinbase signers) call. +This call's `data` parameter contains both the domain hash and the +message hash that will show up in your Ledger. + +It will be a concatenation of `0x1901`, the domain hash, and the +message hash: `0x1901[domain hash][message hash]`. + +Note down this value. You will need to compare it with the ones +displayed on the Ledger screen at signing. + +Once the validations are done, it's time to actually sign the +transaction. + +> [!WARNING] +> This is the most security critical part of the playbook: make sure the +> domain hash and message hash in the following two places match: +> +> 1. On your Ledger screen. +> 2. 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. +> +> There is no need to verify anything printed in the console. There is +> no need to open the new Tenderly simulation link either. + +After verification, sign the transaction. You will see the `Data`, +`Signer` and `Signature` printed in the console. Format should be +something like this: + +```shell +Data: +Signer:
+Signature: +``` + +Double check the signer address is the right one. + +##### 3.2.4 Send the output to Facilitator(s) + +Nothing has occurred onchain - these are offchain signatures which +will be collected by Facilitators for execution. Execution can occur +by anyone once a threshold of signatures are collected, so a +Facilitator will do the final execution for convenience. + +Share the `Data`, `Signer` and `Signature` with the Facilitator, and +congrats, you are done! + +### [For Facilitator ONLY] How to execute + +#### Execute the transaction + +1. IMPORTANT: Ensure op-challenger has been updated before executing. +1. Collect outputs from all participating signers. +1. Concatenate all signatures and export it as the `SIGNATURES` + environment variable, i.e. `export +SIGNATURES="[SIGNATURE1][SIGNATURE2]..."`. +1. Run the `make execute` or `make approve` command as described below to execute the transaction. + +For example, if the quorum is 2 and you get the following outputs: + +```shell +Data: 0xDEADBEEF +Signer: 0xC0FFEE01 +Signature: AAAA +``` + +```shell +Data: 0xDEADBEEF +Signer: 0xC0FFEE02 +Signature: BBBB +``` + +If on testnet, then you should run: + +Coinbase facilitator: + +```bash +SIGNATURES=AAAABBBB make execute +``` + +If on mainnet, then you should run: + +Coinbase facilitator: + +```bash +SIGNATURES=AAAABBBB make approve-cb +``` + +Optimism facilitator: + +```bash +SIGNATURES=AAAABBBB make approve-op +``` + +#### If on mainnet, execute the transaction + +Once the signatures have been submitted approving the transaction for all nested Safes run: + +```bash +make execute +``` diff --git a/mainnet/2025-10-15-update-retirement-timestamp/foundry.toml b/mainnet/2025-10-15-update-retirement-timestamp/foundry.toml new file mode 100644 index 00000000..7a443d45 --- /dev/null +++ b/mainnet/2025-10-15-update-retirement-timestamp/foundry.toml @@ -0,0 +1,20 @@ +[profile.default] +src = 'src' +out = 'out' +libs = ['lib'] +broadcast = 'records' +fs_permissions = [{ access = "read-write", path = "./" }] +optimizer = true +optimizer_runs = 200 +via-ir = false +remappings = [ + '@eth-optimism-bedrock/=lib/optimism/packages/contracts-bedrock/', + '@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts', + '@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts', + '@rari-capital/solmate/=lib/solmate/', + '@base-contracts/=lib/base-contracts', + 'solady/=lib/solady/src/', + '@lib-keccak/=lib/lib-keccak/contracts/lib', +] + +# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/mainnet/2025-10-15-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol b/mainnet/2025-10-15-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol new file mode 100644 index 00000000..7a0e5288 --- /dev/null +++ b/mainnet/2025-10-15-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import {Vm} from "forge-std/Vm.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol"; +import {console} from "forge-std/console.sol"; +import {IAnchorStateRegistry} from "@eth-optimism-bedrock/src/dispute/FaultDisputeGame.sol"; +import {SystemConfig} from "@eth-optimism-bedrock/src/L1/SystemConfig.sol"; +import {DisputeGameFactory} from "@eth-optimism-bedrock/src/dispute/DisputeGameFactory.sol"; +import {FaultDisputeGame} from "@eth-optimism-bedrock/src/dispute/PermissionedDisputeGame.sol"; +import {GameTypes} from "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; +import {MultisigScript} from "@base-contracts/script/universal/MultisigScript.sol"; +import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; + +/// @notice This script updates the FaultDisputeGame and PermissionedDisputeGame implementations in the +/// DisputeGameFactory contract. +contract UpdateRetirementTimestamp is MultisigScript { + using stdJson for string; + + // TODO: Confirm expected version + string public constant EXPECTED_VERSION = "1.4.1"; + + address public immutable OWNER_SAFE; + uint64 public immutable CURRENT_RETIREMENT_TIMESTAMP; + + SystemConfig internal _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); + + IAnchorStateRegistry anchorStateRegistry; + + constructor() { + OWNER_SAFE = vm.envAddress("OWNER_SAFE"); + CURRENT_RETIREMENT_TIMESTAMP = uint64(vm.envUint("CURRENT_RETIREMENT_TIMESTAMP")); + } + + function setUp() public { + DisputeGameFactory dgfProxy = DisputeGameFactory(_SYSTEM_CONFIG.disputeGameFactory()); + FaultDisputeGame currentFdg = FaultDisputeGame(address(dgfProxy.gameImpls(GameTypes.CANNON))); + anchorStateRegistry = currentFdg.anchorStateRegistry(); + + _precheckRetirementTimestamp(); + } + + // Checks that the current state matches the CURRENT_RETIREMENT_TIMESTAMP + function _precheckRetirementTimestamp() internal view { + console.log("pre-check current retirement timestamp", CURRENT_RETIREMENT_TIMESTAMP); + require(anchorStateRegistry.retirementTimestamp() == CURRENT_RETIREMENT_TIMESTAMP, "00"); + } + + // Confirm the CURRENT_RETIREMENT_TIMESTAMP is updated to the block time. + function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { + require(anchorStateRegistry.retirementTimestamp() == block.timestamp, "post-110"); + } + + // // Checks the anchor state for the source game type still exists after re-initialization. The actual anchor state + // // may have been updated since the task was defined so just assert it exists, not that it has a specific value. + // function _postcheckHasAnchorState(uint32 gameType) internal view { + // console.log("check anchor state exists", gameType); + + // IFaultDisputeGame impl = IFaultDisputeGame(dgfProxy.gameImpls(gameType)); + // (bytes32 root, uint256 rootBlockNumber) = IAnchorStateRegistry(impl.anchorStateRegistry()).anchors(gameType); + + // require(root != bytes32(0), "check-300"); + // require(rootBlockNumber != 0, "check-310"); + // } + + function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { + IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](2); + + calls[0] = IMulticall3.Call3Value({ + target: address(anchorStateRegistry), + allowFailure: false, + callData: abi.encodeCall(IAnchorStateRegistry.updateRetirementTimestamp, ()), + value: 0 + }); + + return calls; + } + + function _ownerSafe() internal view override returns (address) { + return OWNER_SAFE; + } +} diff --git a/setup-templates/template-update-retirement-timestamp/.env b/setup-templates/template-update-retirement-timestamp/.env new file mode 100644 index 00000000..827f496b --- /dev/null +++ b/setup-templates/template-update-retirement-timestamp/.env @@ -0,0 +1,20 @@ +OP_COMMIT= +BASE_CONTRACTS_COMMIT= + +# Mainnet Config +SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 + +OWNER_SAFE=0x7bB41C3008B3f03FE483B28b8DB90e19Cf07595c +CB_SIGNER_SAFE_ADDR=0x9855054731540A48b28990B63DcF4f33d8AE46A1 +CB_NESTED_SAFE_ADDR=0x20AcF55A3DCfe07fC4cecaCFa1628F788EC8A4Dd +CB_SC_SAFE_ADDR=0x9C4a57Feb77e294Fd7BF5EBE9AB01CAA0a90A110 +OP_SIGNER_SAFE_ADDR=0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A + +# # Sepolia Config +# SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 + +# OWNER_SAFE=0x0fe884546476dDd290eC46318785046ef68a0BA9 +# CB_SIGNER_SAFE_ADDR=0x646132A1667ca7aD00d36616AFBA1A28116C770A +# CB_NESTED_SAFE_ADDR=0x5dfEB066334B67355A15dc9b67317fD2a2e1f77f +# CB_SC_SAFE_ADDR=0x6AF0674791925f767060Dd52f7fB20984E8639d8 +# OP_SIGNER_SAFE_ADDR=0x6AF0674791925f767060Dd52f7fB20984E8639d8 diff --git a/setup-templates/template-update-retirement-timestamp/Makefile b/setup-templates/template-update-retirement-timestamp/Makefile new file mode 100644 index 00000000..ce9b646e --- /dev/null +++ b/setup-templates/template-update-retirement-timestamp/Makefile @@ -0,0 +1,54 @@ +include ../../Makefile +include ../../Multisig.mk + +include ../.env +include .env + +ifndef LEDGER_ACCOUNT +override LEDGER_ACCOUNT = 0 +endif + +# Mainnet Commands + +# OWNER_SAFE/ +# ├── CB_SIGNER_SAFE_ADDR/ +# │ ├── CB_NESTED_SAFE_ADDR/ +# │ │ └── Signers +# │ └── CB_SC_SAFE_ADDR/ +# │ └── Signers +# └── OP_SIGNER_SAFE_ADDR/ +# └── Signers + +RPC_URL = $(L1_RPC_URL) +SCRIPT_NAME = UpdateRetirementTimestamp + +# CB +.PHONY: sign-cb +sign-cb: + $(call MULTISIG_SIGN,$(CB_NESTED_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR)) + +.PHONY: approve-cb +approve-cb: + $(call MULTISIG_APPROVE,$(CB_NESTED_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR),$(SIGNATURES)) + +.PHONY: sign-cb-sc +sign-cb-sc: + $(call MULTISIG_SIGN,$(CB_SC_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR)) + +.PHONY: approve-cb-sc +approve-cb-sc: + $(call MULTISIG_APPROVE,$(CB_SC_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR),$(SIGNATURES)) + +# OP +.PHONY: sign-op +sign-op: + $(call MULTISIG_SIGN,$(OP_SIGNER_SAFE_ADDR)) + +.PHONY: approve-op +approve-op: + $(call MULTISIG_APPROVE,$(OP_SIGNER_SAFE_ADDR),$(SIGNATURES)) + +# Execute +.PHONY: execute +execute: + $(call MULTISIG_EXECUTE,0x) diff --git a/setup-templates/template-update-retirement-timestamp/README.md b/setup-templates/template-update-retirement-timestamp/README.md new file mode 100644 index 00000000..bbff6d1b --- /dev/null +++ b/setup-templates/template-update-retirement-timestamp/README.md @@ -0,0 +1,193 @@ +# Upgrade Fault Proofs + +Status: PENDING + +## Description + +This task contains two scripts. One for deploying new versions of the `FaultDisputeGame` and `PermissionedDisputeGame` contracts, and one for updating the `DisputeGameFactory` contract to reference the new dispute game contracts. + +## Procedure + +### 1. Update repo: + +```bash +cd contract-deployments +git pull +cd /-upgrade-fault-proofs +make deps +``` + +### 2. Setup Ledger + +Your Ledger needs to be connected and unlocked. The Ethereum +application needs to be opened on Ledger with the message "Application +is ready". + +### 3. Run relevant script(s) + +#### 3.1 Deploy new Dispute Game Implementations + +```bash +make deploy +``` + +This will output the new addresses of the `FaultDisputeGame` and `PermissionedDisputeGame` contracts to an `addresses.json` file. You will need to commit this file to the repo before signers can sign. + +#### 3.2 Sign the transaction + +**If on testnet**: + +```bash +make sign +``` + +**If on mainnet**: + +Coinbase signer: + +```bash +make sign-cb +``` + +Op signer: + +```bash +make sign-op +``` + +You will see a "Simulation link" from the output. + +Paste this URL in your browser. A prompt may ask you to choose a +project, any project will do. You can create one if necessary. + +Click "Simulate Transaction". + +We will be performing 3 validations and extract the domain hash and message hash to approve on your Ledger: + +1. Validate integrity of the simulation. +2. Validate correctness of the state diff. +3. Validate and extract domain hash and message hash to approve. + +##### 3.2.1 Validate integrity of the simulation. + +Make sure you are on the "Summary" tab of the tenderly simulation, to +validate integrity of the simulation, we need to check the following: + +1. "Network": Check the network is Sepolia or Mainnet. +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 see the derivation path Note above. + +##### 3.2.2. Validate correctness of the state diff. + +Now click on the "State" tab, and refer to the [State Validations](./VALIDATION.md) instructions for the transaction you are signing. +Once complete return to this document to complete the signing. + +##### 3.2.3. Extract the domain hash and the message hash to approve. + +Now that we have verified the transaction performs the right +operation, we need to extract the domain hash and the message hash to +approve. + +Go back to the "Summary" tab, and find the +`GnosisSafe.checkSignatures` (for OP signers) or `Safe.checkSignatures` (for Coinbase signers) call. +This call's `data` parameter contains both the domain hash and the +message hash that will show up in your Ledger. + +It will be a concatenation of `0x1901`, the domain hash, and the +message hash: `0x1901[domain hash][message hash]`. + +Note down this value. You will need to compare it with the ones +displayed on the Ledger screen at signing. + +Once the validations are done, it's time to actually sign the +transaction. + +> [!WARNING] +> This is the most security critical part of the playbook: make sure the +> domain hash and message hash in the following two places match: +> +> 1. On your Ledger screen. +> 2. 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. +> +> There is no need to verify anything printed in the console. There is +> no need to open the new Tenderly simulation link either. + +After verification, sign the transaction. You will see the `Data`, +`Signer` and `Signature` printed in the console. Format should be +something like this: + +```shell +Data: +Signer:
+Signature: +``` + +Double check the signer address is the right one. + +##### 3.2.4 Send the output to Facilitator(s) + +Nothing has occurred onchain - these are offchain signatures which +will be collected by Facilitators for execution. Execution can occur +by anyone once a threshold of signatures are collected, so a +Facilitator will do the final execution for convenience. + +Share the `Data`, `Signer` and `Signature` with the Facilitator, and +congrats, you are done! + +### [For Facilitator ONLY] How to execute + +#### Execute the transaction + +1. IMPORTANT: Ensure op-challenger has been updated before executing. +1. Collect outputs from all participating signers. +1. Concatenate all signatures and export it as the `SIGNATURES` + environment variable, i.e. `export +SIGNATURES="[SIGNATURE1][SIGNATURE2]..."`. +1. Run the `make execute` or `make approve` command as described below to execute the transaction. + +For example, if the quorum is 2 and you get the following outputs: + +```shell +Data: 0xDEADBEEF +Signer: 0xC0FFEE01 +Signature: AAAA +``` + +```shell +Data: 0xDEADBEEF +Signer: 0xC0FFEE02 +Signature: BBBB +``` + +If on testnet, then you should run: + +Coinbase facilitator: + +```bash +SIGNATURES=AAAABBBB make execute +``` + +If on mainnet, then you should run: + +Coinbase facilitator: + +```bash +SIGNATURES=AAAABBBB make approve-cb +``` + +Optimism facilitator: + +```bash +SIGNATURES=AAAABBBB make approve-op +``` + +#### If on mainnet, execute the transaction + +Once the signatures have been submitted approving the transaction for all nested Safes run: + +```bash +make execute +``` diff --git a/setup-templates/template-update-retirement-timestamp/foundry.toml b/setup-templates/template-update-retirement-timestamp/foundry.toml new file mode 100644 index 00000000..7a443d45 --- /dev/null +++ b/setup-templates/template-update-retirement-timestamp/foundry.toml @@ -0,0 +1,20 @@ +[profile.default] +src = 'src' +out = 'out' +libs = ['lib'] +broadcast = 'records' +fs_permissions = [{ access = "read-write", path = "./" }] +optimizer = true +optimizer_runs = 200 +via-ir = false +remappings = [ + '@eth-optimism-bedrock/=lib/optimism/packages/contracts-bedrock/', + '@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts', + '@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts', + '@rari-capital/solmate/=lib/solmate/', + '@base-contracts/=lib/base-contracts', + 'solady/=lib/solady/src/', + '@lib-keccak/=lib/lib-keccak/contracts/lib', +] + +# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol b/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol new file mode 100644 index 00000000..7a0e5288 --- /dev/null +++ b/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import {Vm} from "forge-std/Vm.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol"; +import {console} from "forge-std/console.sol"; +import {IAnchorStateRegistry} from "@eth-optimism-bedrock/src/dispute/FaultDisputeGame.sol"; +import {SystemConfig} from "@eth-optimism-bedrock/src/L1/SystemConfig.sol"; +import {DisputeGameFactory} from "@eth-optimism-bedrock/src/dispute/DisputeGameFactory.sol"; +import {FaultDisputeGame} from "@eth-optimism-bedrock/src/dispute/PermissionedDisputeGame.sol"; +import {GameTypes} from "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; +import {MultisigScript} from "@base-contracts/script/universal/MultisigScript.sol"; +import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; + +/// @notice This script updates the FaultDisputeGame and PermissionedDisputeGame implementations in the +/// DisputeGameFactory contract. +contract UpdateRetirementTimestamp is MultisigScript { + using stdJson for string; + + // TODO: Confirm expected version + string public constant EXPECTED_VERSION = "1.4.1"; + + address public immutable OWNER_SAFE; + uint64 public immutable CURRENT_RETIREMENT_TIMESTAMP; + + SystemConfig internal _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); + + IAnchorStateRegistry anchorStateRegistry; + + constructor() { + OWNER_SAFE = vm.envAddress("OWNER_SAFE"); + CURRENT_RETIREMENT_TIMESTAMP = uint64(vm.envUint("CURRENT_RETIREMENT_TIMESTAMP")); + } + + function setUp() public { + DisputeGameFactory dgfProxy = DisputeGameFactory(_SYSTEM_CONFIG.disputeGameFactory()); + FaultDisputeGame currentFdg = FaultDisputeGame(address(dgfProxy.gameImpls(GameTypes.CANNON))); + anchorStateRegistry = currentFdg.anchorStateRegistry(); + + _precheckRetirementTimestamp(); + } + + // Checks that the current state matches the CURRENT_RETIREMENT_TIMESTAMP + function _precheckRetirementTimestamp() internal view { + console.log("pre-check current retirement timestamp", CURRENT_RETIREMENT_TIMESTAMP); + require(anchorStateRegistry.retirementTimestamp() == CURRENT_RETIREMENT_TIMESTAMP, "00"); + } + + // Confirm the CURRENT_RETIREMENT_TIMESTAMP is updated to the block time. + function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { + require(anchorStateRegistry.retirementTimestamp() == block.timestamp, "post-110"); + } + + // // Checks the anchor state for the source game type still exists after re-initialization. The actual anchor state + // // may have been updated since the task was defined so just assert it exists, not that it has a specific value. + // function _postcheckHasAnchorState(uint32 gameType) internal view { + // console.log("check anchor state exists", gameType); + + // IFaultDisputeGame impl = IFaultDisputeGame(dgfProxy.gameImpls(gameType)); + // (bytes32 root, uint256 rootBlockNumber) = IAnchorStateRegistry(impl.anchorStateRegistry()).anchors(gameType); + + // require(root != bytes32(0), "check-300"); + // require(rootBlockNumber != 0, "check-310"); + // } + + function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { + IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](2); + + calls[0] = IMulticall3.Call3Value({ + target: address(anchorStateRegistry), + allowFailure: false, + callData: abi.encodeCall(IAnchorStateRegistry.updateRetirementTimestamp, ()), + value: 0 + }); + + return calls; + } + + function _ownerSafe() internal view override returns (address) { + return OWNER_SAFE; + } +} From f76142439b5ccab41a1475aeb68e7990a490ca25 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 15 Oct 2025 22:42:12 -0400 Subject: [PATCH 02/27] update only template --- .../.env | 22 -- .../Makefile | 54 ----- .../README.md | 193 ------------------ .../foundry.toml | 20 -- .../script/UpdateRetirementTimestamp.s.sol | 83 -------- .../template-update-retirement-timestamp/.env | 9 +- .../Makefile | 32 +-- .../script/UpdateRetirementTimestamp.s.sol | 15 +- 8 files changed, 7 insertions(+), 421 deletions(-) delete mode 100644 mainnet/2025-10-15-update-retirement-timestamp/.env delete mode 100644 mainnet/2025-10-15-update-retirement-timestamp/Makefile delete mode 100644 mainnet/2025-10-15-update-retirement-timestamp/README.md delete mode 100644 mainnet/2025-10-15-update-retirement-timestamp/foundry.toml delete mode 100644 mainnet/2025-10-15-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol diff --git a/mainnet/2025-10-15-update-retirement-timestamp/.env b/mainnet/2025-10-15-update-retirement-timestamp/.env deleted file mode 100644 index 0185f43c..00000000 --- a/mainnet/2025-10-15-update-retirement-timestamp/.env +++ /dev/null @@ -1,22 +0,0 @@ -OP_COMMIT=ad12b8da0785da6938ebdb9c477c0f55d6ae834d -BASE_CONTRACTS_COMMIT=132ba0f33cb455ffff783924588df8864767bd9c - -CURRENT_RETIREMENT_TIMESTAMP=1759862579 - -# Mainnet Config -SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 - -OWNER_SAFE=0x7bB41C3008B3f03FE483B28b8DB90e19Cf07595c -CB_SIGNER_SAFE_ADDR=0x9855054731540A48b28990B63DcF4f33d8AE46A1 -CB_NESTED_SAFE_ADDR=0x20AcF55A3DCfe07fC4cecaCFa1628F788EC8A4Dd -CB_SC_SAFE_ADDR=0x9C4a57Feb77e294Fd7BF5EBE9AB01CAA0a90A110 -OP_SIGNER_SAFE_ADDR=0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A - -# # Sepolia Config -# SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 - -# OWNER_SAFE=0x0fe884546476dDd290eC46318785046ef68a0BA9 -# CB_SIGNER_SAFE_ADDR=0x646132A1667ca7aD00d36616AFBA1A28116C770A -# CB_NESTED_SAFE_ADDR=0x5dfEB066334B67355A15dc9b67317fD2a2e1f77f -# CB_SC_SAFE_ADDR=0x6AF0674791925f767060Dd52f7fB20984E8639d8 -# OP_SIGNER_SAFE_ADDR=0x6AF0674791925f767060Dd52f7fB20984E8639d8 diff --git a/mainnet/2025-10-15-update-retirement-timestamp/Makefile b/mainnet/2025-10-15-update-retirement-timestamp/Makefile deleted file mode 100644 index ce9b646e..00000000 --- a/mainnet/2025-10-15-update-retirement-timestamp/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -include ../../Makefile -include ../../Multisig.mk - -include ../.env -include .env - -ifndef LEDGER_ACCOUNT -override LEDGER_ACCOUNT = 0 -endif - -# Mainnet Commands - -# OWNER_SAFE/ -# ├── CB_SIGNER_SAFE_ADDR/ -# │ ├── CB_NESTED_SAFE_ADDR/ -# │ │ └── Signers -# │ └── CB_SC_SAFE_ADDR/ -# │ └── Signers -# └── OP_SIGNER_SAFE_ADDR/ -# └── Signers - -RPC_URL = $(L1_RPC_URL) -SCRIPT_NAME = UpdateRetirementTimestamp - -# CB -.PHONY: sign-cb -sign-cb: - $(call MULTISIG_SIGN,$(CB_NESTED_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR)) - -.PHONY: approve-cb -approve-cb: - $(call MULTISIG_APPROVE,$(CB_NESTED_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR),$(SIGNATURES)) - -.PHONY: sign-cb-sc -sign-cb-sc: - $(call MULTISIG_SIGN,$(CB_SC_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR)) - -.PHONY: approve-cb-sc -approve-cb-sc: - $(call MULTISIG_APPROVE,$(CB_SC_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR),$(SIGNATURES)) - -# OP -.PHONY: sign-op -sign-op: - $(call MULTISIG_SIGN,$(OP_SIGNER_SAFE_ADDR)) - -.PHONY: approve-op -approve-op: - $(call MULTISIG_APPROVE,$(OP_SIGNER_SAFE_ADDR),$(SIGNATURES)) - -# Execute -.PHONY: execute -execute: - $(call MULTISIG_EXECUTE,0x) diff --git a/mainnet/2025-10-15-update-retirement-timestamp/README.md b/mainnet/2025-10-15-update-retirement-timestamp/README.md deleted file mode 100644 index bbff6d1b..00000000 --- a/mainnet/2025-10-15-update-retirement-timestamp/README.md +++ /dev/null @@ -1,193 +0,0 @@ -# Upgrade Fault Proofs - -Status: PENDING - -## Description - -This task contains two scripts. One for deploying new versions of the `FaultDisputeGame` and `PermissionedDisputeGame` contracts, and one for updating the `DisputeGameFactory` contract to reference the new dispute game contracts. - -## Procedure - -### 1. Update repo: - -```bash -cd contract-deployments -git pull -cd /-upgrade-fault-proofs -make deps -``` - -### 2. Setup Ledger - -Your Ledger needs to be connected and unlocked. The Ethereum -application needs to be opened on Ledger with the message "Application -is ready". - -### 3. Run relevant script(s) - -#### 3.1 Deploy new Dispute Game Implementations - -```bash -make deploy -``` - -This will output the new addresses of the `FaultDisputeGame` and `PermissionedDisputeGame` contracts to an `addresses.json` file. You will need to commit this file to the repo before signers can sign. - -#### 3.2 Sign the transaction - -**If on testnet**: - -```bash -make sign -``` - -**If on mainnet**: - -Coinbase signer: - -```bash -make sign-cb -``` - -Op signer: - -```bash -make sign-op -``` - -You will see a "Simulation link" from the output. - -Paste this URL in your browser. A prompt may ask you to choose a -project, any project will do. You can create one if necessary. - -Click "Simulate Transaction". - -We will be performing 3 validations and extract the domain hash and message hash to approve on your Ledger: - -1. Validate integrity of the simulation. -2. Validate correctness of the state diff. -3. Validate and extract domain hash and message hash to approve. - -##### 3.2.1 Validate integrity of the simulation. - -Make sure you are on the "Summary" tab of the tenderly simulation, to -validate integrity of the simulation, we need to check the following: - -1. "Network": Check the network is Sepolia or Mainnet. -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 see the derivation path Note above. - -##### 3.2.2. Validate correctness of the state diff. - -Now click on the "State" tab, and refer to the [State Validations](./VALIDATION.md) instructions for the transaction you are signing. -Once complete return to this document to complete the signing. - -##### 3.2.3. Extract the domain hash and the message hash to approve. - -Now that we have verified the transaction performs the right -operation, we need to extract the domain hash and the message hash to -approve. - -Go back to the "Summary" tab, and find the -`GnosisSafe.checkSignatures` (for OP signers) or `Safe.checkSignatures` (for Coinbase signers) call. -This call's `data` parameter contains both the domain hash and the -message hash that will show up in your Ledger. - -It will be a concatenation of `0x1901`, the domain hash, and the -message hash: `0x1901[domain hash][message hash]`. - -Note down this value. You will need to compare it with the ones -displayed on the Ledger screen at signing. - -Once the validations are done, it's time to actually sign the -transaction. - -> [!WARNING] -> This is the most security critical part of the playbook: make sure the -> domain hash and message hash in the following two places match: -> -> 1. On your Ledger screen. -> 2. 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. -> -> There is no need to verify anything printed in the console. There is -> no need to open the new Tenderly simulation link either. - -After verification, sign the transaction. You will see the `Data`, -`Signer` and `Signature` printed in the console. Format should be -something like this: - -```shell -Data: -Signer:
-Signature: -``` - -Double check the signer address is the right one. - -##### 3.2.4 Send the output to Facilitator(s) - -Nothing has occurred onchain - these are offchain signatures which -will be collected by Facilitators for execution. Execution can occur -by anyone once a threshold of signatures are collected, so a -Facilitator will do the final execution for convenience. - -Share the `Data`, `Signer` and `Signature` with the Facilitator, and -congrats, you are done! - -### [For Facilitator ONLY] How to execute - -#### Execute the transaction - -1. IMPORTANT: Ensure op-challenger has been updated before executing. -1. Collect outputs from all participating signers. -1. Concatenate all signatures and export it as the `SIGNATURES` - environment variable, i.e. `export -SIGNATURES="[SIGNATURE1][SIGNATURE2]..."`. -1. Run the `make execute` or `make approve` command as described below to execute the transaction. - -For example, if the quorum is 2 and you get the following outputs: - -```shell -Data: 0xDEADBEEF -Signer: 0xC0FFEE01 -Signature: AAAA -``` - -```shell -Data: 0xDEADBEEF -Signer: 0xC0FFEE02 -Signature: BBBB -``` - -If on testnet, then you should run: - -Coinbase facilitator: - -```bash -SIGNATURES=AAAABBBB make execute -``` - -If on mainnet, then you should run: - -Coinbase facilitator: - -```bash -SIGNATURES=AAAABBBB make approve-cb -``` - -Optimism facilitator: - -```bash -SIGNATURES=AAAABBBB make approve-op -``` - -#### If on mainnet, execute the transaction - -Once the signatures have been submitted approving the transaction for all nested Safes run: - -```bash -make execute -``` diff --git a/mainnet/2025-10-15-update-retirement-timestamp/foundry.toml b/mainnet/2025-10-15-update-retirement-timestamp/foundry.toml deleted file mode 100644 index 7a443d45..00000000 --- a/mainnet/2025-10-15-update-retirement-timestamp/foundry.toml +++ /dev/null @@ -1,20 +0,0 @@ -[profile.default] -src = 'src' -out = 'out' -libs = ['lib'] -broadcast = 'records' -fs_permissions = [{ access = "read-write", path = "./" }] -optimizer = true -optimizer_runs = 200 -via-ir = false -remappings = [ - '@eth-optimism-bedrock/=lib/optimism/packages/contracts-bedrock/', - '@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts', - '@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts', - '@rari-capital/solmate/=lib/solmate/', - '@base-contracts/=lib/base-contracts', - 'solady/=lib/solady/src/', - '@lib-keccak/=lib/lib-keccak/contracts/lib', -] - -# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/mainnet/2025-10-15-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol b/mainnet/2025-10-15-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol deleted file mode 100644 index 7a0e5288..00000000 --- a/mainnet/2025-10-15-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {Vm} from "forge-std/Vm.sol"; -import {stdJson} from "forge-std/StdJson.sol"; -import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol"; -import {console} from "forge-std/console.sol"; -import {IAnchorStateRegistry} from "@eth-optimism-bedrock/src/dispute/FaultDisputeGame.sol"; -import {SystemConfig} from "@eth-optimism-bedrock/src/L1/SystemConfig.sol"; -import {DisputeGameFactory} from "@eth-optimism-bedrock/src/dispute/DisputeGameFactory.sol"; -import {FaultDisputeGame} from "@eth-optimism-bedrock/src/dispute/PermissionedDisputeGame.sol"; -import {GameTypes} from "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; -import {MultisigScript} from "@base-contracts/script/universal/MultisigScript.sol"; -import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; - -/// @notice This script updates the FaultDisputeGame and PermissionedDisputeGame implementations in the -/// DisputeGameFactory contract. -contract UpdateRetirementTimestamp is MultisigScript { - using stdJson for string; - - // TODO: Confirm expected version - string public constant EXPECTED_VERSION = "1.4.1"; - - address public immutable OWNER_SAFE; - uint64 public immutable CURRENT_RETIREMENT_TIMESTAMP; - - SystemConfig internal _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); - - IAnchorStateRegistry anchorStateRegistry; - - constructor() { - OWNER_SAFE = vm.envAddress("OWNER_SAFE"); - CURRENT_RETIREMENT_TIMESTAMP = uint64(vm.envUint("CURRENT_RETIREMENT_TIMESTAMP")); - } - - function setUp() public { - DisputeGameFactory dgfProxy = DisputeGameFactory(_SYSTEM_CONFIG.disputeGameFactory()); - FaultDisputeGame currentFdg = FaultDisputeGame(address(dgfProxy.gameImpls(GameTypes.CANNON))); - anchorStateRegistry = currentFdg.anchorStateRegistry(); - - _precheckRetirementTimestamp(); - } - - // Checks that the current state matches the CURRENT_RETIREMENT_TIMESTAMP - function _precheckRetirementTimestamp() internal view { - console.log("pre-check current retirement timestamp", CURRENT_RETIREMENT_TIMESTAMP); - require(anchorStateRegistry.retirementTimestamp() == CURRENT_RETIREMENT_TIMESTAMP, "00"); - } - - // Confirm the CURRENT_RETIREMENT_TIMESTAMP is updated to the block time. - function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { - require(anchorStateRegistry.retirementTimestamp() == block.timestamp, "post-110"); - } - - // // Checks the anchor state for the source game type still exists after re-initialization. The actual anchor state - // // may have been updated since the task was defined so just assert it exists, not that it has a specific value. - // function _postcheckHasAnchorState(uint32 gameType) internal view { - // console.log("check anchor state exists", gameType); - - // IFaultDisputeGame impl = IFaultDisputeGame(dgfProxy.gameImpls(gameType)); - // (bytes32 root, uint256 rootBlockNumber) = IAnchorStateRegistry(impl.anchorStateRegistry()).anchors(gameType); - - // require(root != bytes32(0), "check-300"); - // require(rootBlockNumber != 0, "check-310"); - // } - - function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { - IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](2); - - calls[0] = IMulticall3.Call3Value({ - target: address(anchorStateRegistry), - allowFailure: false, - callData: abi.encodeCall(IAnchorStateRegistry.updateRetirementTimestamp, ()), - value: 0 - }); - - return calls; - } - - function _ownerSafe() internal view override returns (address) { - return OWNER_SAFE; - } -} diff --git a/setup-templates/template-update-retirement-timestamp/.env b/setup-templates/template-update-retirement-timestamp/.env index 827f496b..7c10af70 100644 --- a/setup-templates/template-update-retirement-timestamp/.env +++ b/setup-templates/template-update-retirement-timestamp/.env @@ -1,14 +1,13 @@ OP_COMMIT= BASE_CONTRACTS_COMMIT= +CURRENT_RETIREMENT_TIMESTAMP= + # Mainnet Config SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 -OWNER_SAFE=0x7bB41C3008B3f03FE483B28b8DB90e19Cf07595c -CB_SIGNER_SAFE_ADDR=0x9855054731540A48b28990B63DcF4f33d8AE46A1 -CB_NESTED_SAFE_ADDR=0x20AcF55A3DCfe07fC4cecaCFa1628F788EC8A4Dd -CB_SC_SAFE_ADDR=0x9C4a57Feb77e294Fd7BF5EBE9AB01CAA0a90A110 -OP_SIGNER_SAFE_ADDR=0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A +OWNER_SAFE=0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2 # Optimism Guardian Multisig (controls Anchor State Registry) +OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 # Owner of Optimism Guardian Multisig # # Sepolia Config # SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 diff --git a/setup-templates/template-update-retirement-timestamp/Makefile b/setup-templates/template-update-retirement-timestamp/Makefile index ce9b646e..b63dfec4 100644 --- a/setup-templates/template-update-retirement-timestamp/Makefile +++ b/setup-templates/template-update-retirement-timestamp/Makefile @@ -8,45 +8,17 @@ ifndef LEDGER_ACCOUNT override LEDGER_ACCOUNT = 0 endif -# Mainnet Commands - -# OWNER_SAFE/ -# ├── CB_SIGNER_SAFE_ADDR/ -# │ ├── CB_NESTED_SAFE_ADDR/ -# │ │ └── Signers -# │ └── CB_SC_SAFE_ADDR/ -# │ └── Signers -# └── OP_SIGNER_SAFE_ADDR/ -# └── Signers - RPC_URL = $(L1_RPC_URL) SCRIPT_NAME = UpdateRetirementTimestamp -# CB -.PHONY: sign-cb -sign-cb: - $(call MULTISIG_SIGN,$(CB_NESTED_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR)) - -.PHONY: approve-cb -approve-cb: - $(call MULTISIG_APPROVE,$(CB_NESTED_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR),$(SIGNATURES)) - -.PHONY: sign-cb-sc -sign-cb-sc: - $(call MULTISIG_SIGN,$(CB_SC_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR)) - -.PHONY: approve-cb-sc -approve-cb-sc: - $(call MULTISIG_APPROVE,$(CB_SC_SAFE_ADDR) $(CB_SIGNER_SAFE_ADDR),$(SIGNATURES)) - # OP .PHONY: sign-op sign-op: - $(call MULTISIG_SIGN,$(OP_SIGNER_SAFE_ADDR)) + $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) .PHONY: approve-op approve-op: - $(call MULTISIG_APPROVE,$(OP_SIGNER_SAFE_ADDR),$(SIGNATURES)) + $(call MULTISIG_APPROVE,$(OP_SECURITY_COUNCIL_SAFE),$(SIGNATURES)) # Execute .PHONY: execute diff --git a/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol b/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol index 7a0e5288..b7a52b35 100644 --- a/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol +++ b/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol @@ -43,7 +43,6 @@ contract UpdateRetirementTimestamp is MultisigScript { // Checks that the current state matches the CURRENT_RETIREMENT_TIMESTAMP function _precheckRetirementTimestamp() internal view { - console.log("pre-check current retirement timestamp", CURRENT_RETIREMENT_TIMESTAMP); require(anchorStateRegistry.retirementTimestamp() == CURRENT_RETIREMENT_TIMESTAMP, "00"); } @@ -52,21 +51,9 @@ contract UpdateRetirementTimestamp is MultisigScript { require(anchorStateRegistry.retirementTimestamp() == block.timestamp, "post-110"); } - // // Checks the anchor state for the source game type still exists after re-initialization. The actual anchor state - // // may have been updated since the task was defined so just assert it exists, not that it has a specific value. - // function _postcheckHasAnchorState(uint32 gameType) internal view { - // console.log("check anchor state exists", gameType); - - // IFaultDisputeGame impl = IFaultDisputeGame(dgfProxy.gameImpls(gameType)); - // (bytes32 root, uint256 rootBlockNumber) = IAnchorStateRegistry(impl.anchorStateRegistry()).anchors(gameType); - - // require(root != bytes32(0), "check-300"); - // require(rootBlockNumber != 0, "check-310"); - // } function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { - IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](2); - + IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](1); calls[0] = IMulticall3.Call3Value({ target: address(anchorStateRegistry), allowFailure: false, From 28bf2bde4f66b4074fc0a76f542cceeeab646fd8 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 15 Oct 2025 23:02:11 -0400 Subject: [PATCH 03/27] rename to switch to permissioned game --- Makefile | 10 +++++----- .../.env | 7 ++----- .../Makefile | 0 .../README.md | 0 .../foundry.toml | 0 .../script/SwitchToPermissionedGame.sol} | 12 ++++++++++-- 6 files changed, 17 insertions(+), 12 deletions(-) rename setup-templates/{template-update-retirement-timestamp => template-switch-to-permissioned-game}/.env (58%) rename setup-templates/{template-update-retirement-timestamp => template-switch-to-permissioned-game}/Makefile (100%) rename setup-templates/{template-update-retirement-timestamp => template-switch-to-permissioned-game}/README.md (100%) rename setup-templates/{template-update-retirement-timestamp => template-switch-to-permissioned-game}/foundry.toml (100%) rename setup-templates/{template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol => template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol} (89%) diff --git a/Makefile b/Makefile index c77b5c4b..76ae0cfd 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ SAFE_MANAGEMENT_DIR = $(network)/$(shell date +'%Y-%m-%d')-safe-swap-owner FUNDING_DIR = $(network)/$(shell date +'%Y-%m-%d')-funding SET_BASE_BRIDGE_PARTNER_THRESHOLD_DIR = $(network)/$(shell date +'%Y-%m-%d')-pause-bridge-base PAUSE_BRIDGE_BASE_DIR = $(network)/$(shell date +'%Y-%m-%d')-pause-bridge-base -UPDATE_RETIREMENT_TIMESTAMP_DIR=$(network)/$(shell date +'%Y-%m-%d')-update-retirement-timestamp +SWITCH_TO_PERMISSIONED_GAME_DIR=$(network)/$(shell date +'%Y-%m-%d')-switch-to-permissioned-game TEMPLATE_GENERIC = setup-templates/template-generic TEMPLATE_GAS_INCREASE = setup-templates/template-gas-increase @@ -14,7 +14,7 @@ TEMPLATE_SAFE_MANAGEMENT = setup-templates/template-safe-management TEMPLATE_FUNDING = setup-templates/template-funding TEMPLATE_SET_BASE_BRIDGE_PARTNER_THRESHOLD = setup-templates/template-set-bridge-partner-threshold TEMPLATE_PAUSE_BRIDGE_BASE = setup-templates/template-pause-bridge-base -TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP= setup-templates/template-update-retirement-timestamp +TEMPLATE_SWITCH_TO_PERMISSIONED_GAME = setup-templates/template-switch-to-permissioned-game ifndef $(GOPATH) GOPATH=$(shell go env GOPATH) @@ -63,9 +63,9 @@ setup-bridge-pause: rm -rf $(TEMPLATE_PAUSE_BRIDGE_BASE)/cache $(TEMPLATE_PAUSE_BRIDGE_BASE)/lib $(TEMPLATE_PAUSE_BRIDGE_BASE)/out cp -r $(TEMPLATE_PAUSE_BRIDGE_BASE) $(PAUSE_BRIDGE_BASE_DIR) -setup-update-retirement-timestamp: - rm -rf $(TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP)/cache $(TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP)/lib $(TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP)/out - cp -r $(TEMPLATE_UPDATE_RETIREMENT_TIMESTAMP) $(UPDATE_RETIREMENT_TIMESTAMP_DIR) +setup-switch-to-permissioned-game: + rm -rf $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME)/cache $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME)/lib $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME)/out + cp -r $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME) $(SWITCH_TO_PERMISSIONED_GAME_DIR) ## # Solidity Setup diff --git a/setup-templates/template-update-retirement-timestamp/.env b/setup-templates/template-switch-to-permissioned-game/.env similarity index 58% rename from setup-templates/template-update-retirement-timestamp/.env rename to setup-templates/template-switch-to-permissioned-game/.env index 7c10af70..9cb2e0ad 100644 --- a/setup-templates/template-update-retirement-timestamp/.env +++ b/setup-templates/template-switch-to-permissioned-game/.env @@ -12,8 +12,5 @@ OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 # Owner of O # # Sepolia Config # SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 -# OWNER_SAFE=0x0fe884546476dDd290eC46318785046ef68a0BA9 -# CB_SIGNER_SAFE_ADDR=0x646132A1667ca7aD00d36616AFBA1A28116C770A -# CB_NESTED_SAFE_ADDR=0x5dfEB066334B67355A15dc9b67317fD2a2e1f77f -# CB_SC_SAFE_ADDR=0x6AF0674791925f767060Dd52f7fB20984E8639d8 -# OP_SIGNER_SAFE_ADDR=0x6AF0674791925f767060Dd52f7fB20984E8639d8 +# OWNER_SAFE=0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E # Optimism Guardian Multisig (controls Anchor State Registry) +# OP_SECURITY_COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 # Owner of Optimism Guardian Multisig diff --git a/setup-templates/template-update-retirement-timestamp/Makefile b/setup-templates/template-switch-to-permissioned-game/Makefile similarity index 100% rename from setup-templates/template-update-retirement-timestamp/Makefile rename to setup-templates/template-switch-to-permissioned-game/Makefile diff --git a/setup-templates/template-update-retirement-timestamp/README.md b/setup-templates/template-switch-to-permissioned-game/README.md similarity index 100% rename from setup-templates/template-update-retirement-timestamp/README.md rename to setup-templates/template-switch-to-permissioned-game/README.md diff --git a/setup-templates/template-update-retirement-timestamp/foundry.toml b/setup-templates/template-switch-to-permissioned-game/foundry.toml similarity index 100% rename from setup-templates/template-update-retirement-timestamp/foundry.toml rename to setup-templates/template-switch-to-permissioned-game/foundry.toml diff --git a/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol similarity index 89% rename from setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol rename to setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol index b7a52b35..067ec5ad 100644 --- a/setup-templates/template-update-retirement-timestamp/script/UpdateRetirementTimestamp.s.sol +++ b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol @@ -15,7 +15,7 @@ import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; /// @notice This script updates the FaultDisputeGame and PermissionedDisputeGame implementations in the /// DisputeGameFactory contract. -contract UpdateRetirementTimestamp is MultisigScript { +contract SwitchToPermissionedGame is MultisigScript { using stdJson for string; // TODO: Confirm expected version @@ -53,8 +53,16 @@ contract UpdateRetirementTimestamp is MultisigScript { function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { - IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](1); + IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](2); + calls[0] = IMulticall3.Call3Value({ + target: address(anchorStateRegistry), + allowFailure: false, + callData: abi.encodeCall(IAnchorStateRegistry.setRespectedGameType, (GameType.PERMISSIONED_CANNON)), + value: 0 + }); + + calls[1] = IMulticall3.Call3Value({ target: address(anchorStateRegistry), allowFailure: false, callData: abi.encodeCall(IAnchorStateRegistry.updateRetirementTimestamp, ()), From eda82fac3b624ab06a5242ee0fb12c3c962b9e59 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 15 Oct 2025 23:11:13 -0400 Subject: [PATCH 04/27] update script name --- setup-templates/template-switch-to-permissioned-game/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup-templates/template-switch-to-permissioned-game/Makefile b/setup-templates/template-switch-to-permissioned-game/Makefile index b63dfec4..da400129 100644 --- a/setup-templates/template-switch-to-permissioned-game/Makefile +++ b/setup-templates/template-switch-to-permissioned-game/Makefile @@ -9,7 +9,7 @@ override LEDGER_ACCOUNT = 0 endif RPC_URL = $(L1_RPC_URL) -SCRIPT_NAME = UpdateRetirementTimestamp +SCRIPT_NAME = SwitchToPermissionedGame # OP .PHONY: sign-op From 9fb2d57bdf735867055fc8875d0d720695787d10 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 15 Oct 2025 23:17:29 -0400 Subject: [PATCH 05/27] update readme --- .../README.md | 33 +++---------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/setup-templates/template-switch-to-permissioned-game/README.md b/setup-templates/template-switch-to-permissioned-game/README.md index bbff6d1b..9a6ba8f9 100644 --- a/setup-templates/template-switch-to-permissioned-game/README.md +++ b/setup-templates/template-switch-to-permissioned-game/README.md @@ -4,7 +4,8 @@ Status: PENDING ## Description -This task contains two scripts. One for deploying new versions of the `FaultDisputeGame` and `PermissionedDisputeGame` contracts, and one for updating the `DisputeGameFactory` contract to reference the new dispute game contracts. +This task contains a single script that will update the `respectedGameType` and `retirementTimestamp` in the AnchorStateRegistry. This can only be done by the +"Optimism Guardian Multisig" which is a single-nested multisig controlled by the OP Security Council. ## Procedure @@ -13,7 +14,7 @@ This task contains two scripts. One for deploying new versions of the `FaultDisp ```bash cd contract-deployments git pull -cd /-upgrade-fault-proofs +cd /-switch-to-permissioned-game make deps ``` @@ -25,30 +26,10 @@ is ready". ### 3. Run relevant script(s) -#### 3.1 Deploy new Dispute Game Implementations - -```bash -make deploy -``` - -This will output the new addresses of the `FaultDisputeGame` and `PermissionedDisputeGame` contracts to an `addresses.json` file. You will need to commit this file to the repo before signers can sign. - -#### 3.2 Sign the transaction - -**If on testnet**: - -```bash -make sign -``` +#### 3.1 Sign the transaction **If on mainnet**: -Coinbase signer: - -```bash -make sign-cb -``` - Op signer: ```bash @@ -172,12 +153,6 @@ SIGNATURES=AAAABBBB make execute If on mainnet, then you should run: -Coinbase facilitator: - -```bash -SIGNATURES=AAAABBBB make approve-cb -``` - Optimism facilitator: ```bash From 6a57626baf230632cce51799338ddd90333afd32 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Fri, 24 Oct 2025 11:09:30 -0400 Subject: [PATCH 06/27] fix typo --- .../script/SwitchToPermissionedGame.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol index 067ec5ad..f18d6f70 100644 --- a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol @@ -58,7 +58,7 @@ contract SwitchToPermissionedGame is MultisigScript { calls[0] = IMulticall3.Call3Value({ target: address(anchorStateRegistry), allowFailure: false, - callData: abi.encodeCall(IAnchorStateRegistry.setRespectedGameType, (GameType.PERMISSIONED_CANNON)), + callData: abi.encodeCall(IAnchorStateRegistry.setRespectedGameType, (GameTypes.PERMISSIONED_CANNON)), value: 0 }); From 4013a7ec2692b9571af28002721bfdbd7aeb3d63 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Fri, 24 Oct 2025 11:13:19 -0400 Subject: [PATCH 07/27] add postcheck for permissioned cannon --- .../script/SwitchToPermissionedGame.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol index f18d6f70..e505b2d7 100644 --- a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol @@ -49,6 +49,7 @@ contract SwitchToPermissionedGame is MultisigScript { // Confirm the CURRENT_RETIREMENT_TIMESTAMP is updated to the block time. function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { require(anchorStateRegistry.retirementTimestamp() == block.timestamp, "post-110"); + require(anchorStateRegistry.respectedGameType() == GameTypes.PERMISSIONED_CANNON, "post-111"); } From fc54b9701b6ff0ba63a2590562d3acf80f51dc17 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Fri, 24 Oct 2025 11:35:28 -0400 Subject: [PATCH 08/27] add gametype postcheck --- .../script/SwitchToPermissionedGame.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol index e505b2d7..fe3b79b6 100644 --- a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol @@ -9,7 +9,7 @@ import {IAnchorStateRegistry} from "@eth-optimism-bedrock/src/dispute/FaultDispu import {SystemConfig} from "@eth-optimism-bedrock/src/L1/SystemConfig.sol"; import {DisputeGameFactory} from "@eth-optimism-bedrock/src/dispute/DisputeGameFactory.sol"; import {FaultDisputeGame} from "@eth-optimism-bedrock/src/dispute/PermissionedDisputeGame.sol"; -import {GameTypes} from "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; +import {GameTypes, GameType} from "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; import {MultisigScript} from "@base-contracts/script/universal/MultisigScript.sol"; import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; @@ -49,7 +49,7 @@ contract SwitchToPermissionedGame is MultisigScript { // Confirm the CURRENT_RETIREMENT_TIMESTAMP is updated to the block time. function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { require(anchorStateRegistry.retirementTimestamp() == block.timestamp, "post-110"); - require(anchorStateRegistry.respectedGameType() == GameTypes.PERMISSIONED_CANNON, "post-111"); + require(GameType.unwrap(anchorStateRegistry.respectedGameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), "post-111"); } From 88d35c97c98fe628bb7cf1d6bfe0c8119f646e01 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Fri, 24 Oct 2025 11:47:21 -0400 Subject: [PATCH 09/27] add filled in senders for base simulation --- .../template-switch-to-permissioned-game/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/setup-templates/template-switch-to-permissioned-game/Makefile b/setup-templates/template-switch-to-permissioned-game/Makefile index da400129..12f0b7b0 100644 --- a/setup-templates/template-switch-to-permissioned-game/Makefile +++ b/setup-templates/template-switch-to-permissioned-game/Makefile @@ -24,3 +24,12 @@ approve-op: .PHONY: execute execute: $(call MULTISIG_EXECUTE,0x) + +# Base -- used for simulating the transcations as op-signers by base engineers +.PHONY: sign-base-sepolia +sign-base-mainnet: + $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e + +.PHONY: sign-base-sepolia +sign-base-sepolia: + $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1084092Ac2f04c866806CF3d4a385Afa4F6A6C97 From 1c06c684bfc914df3549988f92a42d531cccc2be Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Fri, 24 Oct 2025 16:53:22 -0400 Subject: [PATCH 10/27] add blacklist and rename retire --- Makefile | 16 +- .../.env | 16 ++ .../Makefile | 0 .../README.md | 0 .../foundry.toml | 0 .../script/SwitchToPermissionedGame.sol | 87 +++++++++ .../.env | 0 .../Makefile | 35 ++++ .../README.md | 168 ++++++++++++++++++ .../foundry.toml | 20 +++ .../script/SwitchToPermissionedGame.sol | 0 11 files changed, 337 insertions(+), 5 deletions(-) create mode 100644 setup-templates/template-switch-to-permissioned-game-blacklist/.env rename setup-templates/{template-switch-to-permissioned-game => template-switch-to-permissioned-game-blacklist}/Makefile (100%) rename setup-templates/{template-switch-to-permissioned-game => template-switch-to-permissioned-game-blacklist}/README.md (100%) rename setup-templates/{template-switch-to-permissioned-game => template-switch-to-permissioned-game-blacklist}/foundry.toml (100%) create mode 100644 setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol rename setup-templates/{template-switch-to-permissioned-game => template-switch-to-permissioned-game-retire}/.env (100%) create mode 100644 setup-templates/template-switch-to-permissioned-game-retire/Makefile create mode 100644 setup-templates/template-switch-to-permissioned-game-retire/README.md create mode 100644 setup-templates/template-switch-to-permissioned-game-retire/foundry.toml rename setup-templates/{template-switch-to-permissioned-game => template-switch-to-permissioned-game-retire}/script/SwitchToPermissionedGame.sol (100%) diff --git a/Makefile b/Makefile index cff3ba4c..5c31d21d 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,8 @@ SAFE_MANAGEMENT_DIR = $(network)/$(shell date +'%Y-%m-%d')-safe-swap-owner FUNDING_DIR = $(network)/$(shell date +'%Y-%m-%d')-funding SET_BASE_BRIDGE_PARTNER_THRESHOLD_DIR = $(network)/$(shell date +'%Y-%m-%d')-pause-bridge-base PAUSE_BRIDGE_BASE_DIR = $(network)/$(shell date +'%Y-%m-%d')-pause-bridge-base -SWITCH_TO_PERMISSIONED_GAME_DIR=$(network)/$(shell date +'%Y-%m-%d')-switch-to-permissioned-game +SWITCH_TO_PERMISSIONED_GAME_RETIRE_DIR=$(network)/$(shell date +'%Y-%m-%d')-switch-to-permissioned-game-retire +SWITCH_TO_PERMISSIONED_GAME_BLACKLIST_DIR=$(network)/$(shell date +'%Y-%m-%d')-switch-to-permissioned-game-blacklist TEMPLATE_GENERIC = setup-templates/template-generic TEMPLATE_GAS_INCREASE = setup-templates/template-gas-increase @@ -16,7 +17,8 @@ TEMPLATE_SAFE_MANAGEMENT = setup-templates/template-safe-management TEMPLATE_FUNDING = setup-templates/template-funding TEMPLATE_SET_BASE_BRIDGE_PARTNER_THRESHOLD = setup-templates/template-set-bridge-partner-threshold TEMPLATE_PAUSE_BRIDGE_BASE = setup-templates/template-pause-bridge-base -TEMPLATE_SWITCH_TO_PERMISSIONED_GAME = setup-templates/template-switch-to-permissioned-game +TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_RETIRE = setup-templates/template-switch-to-permissioned-game-retire +TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_BLACKLIST = setup-templates/template-switch-to-permissioned-game-blacklist ifndef $(GOPATH) GOPATH=$(shell go env GOPATH) @@ -65,9 +67,13 @@ setup-bridge-pause: rm -rf $(TEMPLATE_PAUSE_BRIDGE_BASE)/cache $(TEMPLATE_PAUSE_BRIDGE_BASE)/lib $(TEMPLATE_PAUSE_BRIDGE_BASE)/out cp -r $(TEMPLATE_PAUSE_BRIDGE_BASE) $(PAUSE_BRIDGE_BASE_DIR) -setup-switch-to-permissioned-game: - rm -rf $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME)/cache $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME)/lib $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME)/out - cp -r $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME) $(SWITCH_TO_PERMISSIONED_GAME_DIR) +setup-switch-to-permissioned-game-retire: + rm -rf $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_RETIRE)/cache $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_RETIRE)/lib $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_RETIRE)/out + cp -r $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_RETIRE) $(SWITCH_TO_PERMISSIONED_GAME_RETIRE_DIR) + +setup-switch-to-permissioned-game-blacklist: + rm -rf $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_BLACKLIST)/cache $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_BLACKLIST)/lib $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_BLACKLIST)/out + cp -r $(TEMPLATE_SWITCH_TO_PERMISSIONED_GAME_BLACKLIST) $(SWITCH_TO_PERMISSIONED_GAME_BLACKLIST_DIR) ## # Solidity Setup diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/.env b/setup-templates/template-switch-to-permissioned-game-blacklist/.env new file mode 100644 index 00000000..82680eaa --- /dev/null +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/.env @@ -0,0 +1,16 @@ +OP_COMMIT= +BASE_CONTRACTS_COMMIT= + +L2_DIVERGENCE_BLOCK_NUMBER= + +# Mainnet Config +SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 + +OWNER_SAFE=0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2 # Optimism Guardian Multisig (controls Anchor State Registry) +OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 # Owner of Optimism Guardian Multisig + +# # Sepolia Config +# SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 + +# OWNER_SAFE=0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E # Optimism Guardian Multisig (controls Anchor State Registry) +# OP_SECURITY_COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 # Owner of Optimism Guardian Multisig diff --git a/setup-templates/template-switch-to-permissioned-game/Makefile b/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile similarity index 100% rename from setup-templates/template-switch-to-permissioned-game/Makefile rename to setup-templates/template-switch-to-permissioned-game-blacklist/Makefile diff --git a/setup-templates/template-switch-to-permissioned-game/README.md b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md similarity index 100% rename from setup-templates/template-switch-to-permissioned-game/README.md rename to setup-templates/template-switch-to-permissioned-game-blacklist/README.md diff --git a/setup-templates/template-switch-to-permissioned-game/foundry.toml b/setup-templates/template-switch-to-permissioned-game-blacklist/foundry.toml similarity index 100% rename from setup-templates/template-switch-to-permissioned-game/foundry.toml rename to setup-templates/template-switch-to-permissioned-game-blacklist/foundry.toml diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol new file mode 100644 index 00000000..2d10ae9c --- /dev/null +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import {Vm} from "forge-std/Vm.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol"; +import {console} from "forge-std/console.sol"; +import {IAnchorStateRegistry} from "@eth-optimism-bedrock/src/dispute/FaultDisputeGame.sol"; +import {SystemConfig} from "@eth-optimism-bedrock/src/L1/SystemConfig.sol"; +import {IDisputeGame, GameStatus} from "@eth-optimism-bedrock/src/dispute/AnchorStateRegistry.sol"; +import {IDisputeGameFactory} from "@eth-optimism-bedrock/interfaces/dispute/IDisputeGameFactory.sol"; +import {FaultDisputeGame} from "@eth-optimism-bedrock/src/dispute/PermissionedDisputeGame.sol"; +import {GameTypes, GameType} from "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; +import {MultisigScript} from "@base-contracts/script/universal/MultisigScript.sol"; +import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; + +/// @notice This script updates the FaultDisputeGame and PermissionedDisputeGame implementations in the +/// DisputeGameFactory contract. +contract SwitchToPermissionedGame is MultisigScript { + using stdJson for string; + + // TODO: Confirm expected version + string public constant EXPECTED_VERSION = "1.4.1"; + + address public immutable OWNER_SAFE; + uint256 public immutable L2_DIVERGENCE_BLOCK_NUMBER; + + SystemConfig internal _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); + + IAnchorStateRegistry anchorStateRegistry; + IDisputeGame[] gamesToBlacklist; + + constructor() { + OWNER_SAFE = vm.envAddress("OWNER_SAFE"); + L2_DIVERGENCE_BLOCK_NUMBER = uint64(vm.envUint("L2_DIVERGENCE_BLOCK_NUMBER")); + } + + function setUp() public { + IDisputeGameFactory dgfProxy = IDisputeGameFactory(_SYSTEM_CONFIG.disputeGameFactory()); + FaultDisputeGame currentFdg = FaultDisputeGame(address(dgfProxy.gameImpls(GameTypes.CANNON))); + anchorStateRegistry = currentFdg.anchorStateRegistry(); + + getGamesToBlacklist(dgfProxy); + } + + function getGamesToBlacklist(IDisputeGameFactory dgfProxy) internal { + uint256 totalNumGames = dgfProxy.gameCount(); + console.log("total games to search", totalNumGames); + + for (uint256 i = 0; i < totalNumGames; i = i + 1) { + (, , IDisputeGame game) = dgfProxy.gameAtIndex(i); + if (game.status() == GameStatus.IN_PROGRESS && game.l2SequenceNumber() >= L2_DIVERGENCE_BLOCK_NUMBER) { + // this game is in progress and challenges a block at or after the divergence block + gamesToBlacklist.push(game); + } + } + + console.log("total games to blacklist", gamesToBlacklist.length); + } + + // Confirm the CURRENT_RETIREMENT_TIMESTAMP is updated to the block time. + function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { + for (uint256 i = 0; i < gamesToBlacklist.length; i = i + 1) { + require(anchorStateRegistry.isGameBlacklisted(gamesToBlacklist[i]), "post-110"); + } + } + + + function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { + IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](gamesToBlacklist.length); + + for (uint256 i = 0; i < gamesToBlacklist.length; i = i + 1) { + calls[i] = IMulticall3.Call3Value({ + target: address(anchorStateRegistry), + allowFailure: false, + callData: abi.encodeCall(IAnchorStateRegistry.blacklistDisputeGame, (gamesToBlacklist[i])), + value: 0 + }); + } + + return calls; + } + + function _ownerSafe() internal view override returns (address) { + return OWNER_SAFE; + } +} diff --git a/setup-templates/template-switch-to-permissioned-game/.env b/setup-templates/template-switch-to-permissioned-game-retire/.env similarity index 100% rename from setup-templates/template-switch-to-permissioned-game/.env rename to setup-templates/template-switch-to-permissioned-game-retire/.env diff --git a/setup-templates/template-switch-to-permissioned-game-retire/Makefile b/setup-templates/template-switch-to-permissioned-game-retire/Makefile new file mode 100644 index 00000000..12f0b7b0 --- /dev/null +++ b/setup-templates/template-switch-to-permissioned-game-retire/Makefile @@ -0,0 +1,35 @@ +include ../../Makefile +include ../../Multisig.mk + +include ../.env +include .env + +ifndef LEDGER_ACCOUNT +override LEDGER_ACCOUNT = 0 +endif + +RPC_URL = $(L1_RPC_URL) +SCRIPT_NAME = SwitchToPermissionedGame + +# OP +.PHONY: sign-op +sign-op: + $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) + +.PHONY: approve-op +approve-op: + $(call MULTISIG_APPROVE,$(OP_SECURITY_COUNCIL_SAFE),$(SIGNATURES)) + +# Execute +.PHONY: execute +execute: + $(call MULTISIG_EXECUTE,0x) + +# Base -- used for simulating the transcations as op-signers by base engineers +.PHONY: sign-base-sepolia +sign-base-mainnet: + $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e + +.PHONY: sign-base-sepolia +sign-base-sepolia: + $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1084092Ac2f04c866806CF3d4a385Afa4F6A6C97 diff --git a/setup-templates/template-switch-to-permissioned-game-retire/README.md b/setup-templates/template-switch-to-permissioned-game-retire/README.md new file mode 100644 index 00000000..9a6ba8f9 --- /dev/null +++ b/setup-templates/template-switch-to-permissioned-game-retire/README.md @@ -0,0 +1,168 @@ +# Upgrade Fault Proofs + +Status: PENDING + +## Description + +This task contains a single script that will update the `respectedGameType` and `retirementTimestamp` in the AnchorStateRegistry. This can only be done by the +"Optimism Guardian Multisig" which is a single-nested multisig controlled by the OP Security Council. + +## Procedure + +### 1. Update repo: + +```bash +cd contract-deployments +git pull +cd /-switch-to-permissioned-game +make deps +``` + +### 2. Setup Ledger + +Your Ledger needs to be connected and unlocked. The Ethereum +application needs to be opened on Ledger with the message "Application +is ready". + +### 3. Run relevant script(s) + +#### 3.1 Sign the transaction + +**If on mainnet**: + +Op signer: + +```bash +make sign-op +``` + +You will see a "Simulation link" from the output. + +Paste this URL in your browser. A prompt may ask you to choose a +project, any project will do. You can create one if necessary. + +Click "Simulate Transaction". + +We will be performing 3 validations and extract the domain hash and message hash to approve on your Ledger: + +1. Validate integrity of the simulation. +2. Validate correctness of the state diff. +3. Validate and extract domain hash and message hash to approve. + +##### 3.2.1 Validate integrity of the simulation. + +Make sure you are on the "Summary" tab of the tenderly simulation, to +validate integrity of the simulation, we need to check the following: + +1. "Network": Check the network is Sepolia or Mainnet. +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 see the derivation path Note above. + +##### 3.2.2. Validate correctness of the state diff. + +Now click on the "State" tab, and refer to the [State Validations](./VALIDATION.md) instructions for the transaction you are signing. +Once complete return to this document to complete the signing. + +##### 3.2.3. Extract the domain hash and the message hash to approve. + +Now that we have verified the transaction performs the right +operation, we need to extract the domain hash and the message hash to +approve. + +Go back to the "Summary" tab, and find the +`GnosisSafe.checkSignatures` (for OP signers) or `Safe.checkSignatures` (for Coinbase signers) call. +This call's `data` parameter contains both the domain hash and the +message hash that will show up in your Ledger. + +It will be a concatenation of `0x1901`, the domain hash, and the +message hash: `0x1901[domain hash][message hash]`. + +Note down this value. You will need to compare it with the ones +displayed on the Ledger screen at signing. + +Once the validations are done, it's time to actually sign the +transaction. + +> [!WARNING] +> This is the most security critical part of the playbook: make sure the +> domain hash and message hash in the following two places match: +> +> 1. On your Ledger screen. +> 2. 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. +> +> There is no need to verify anything printed in the console. There is +> no need to open the new Tenderly simulation link either. + +After verification, sign the transaction. You will see the `Data`, +`Signer` and `Signature` printed in the console. Format should be +something like this: + +```shell +Data: +Signer:
+Signature: +``` + +Double check the signer address is the right one. + +##### 3.2.4 Send the output to Facilitator(s) + +Nothing has occurred onchain - these are offchain signatures which +will be collected by Facilitators for execution. Execution can occur +by anyone once a threshold of signatures are collected, so a +Facilitator will do the final execution for convenience. + +Share the `Data`, `Signer` and `Signature` with the Facilitator, and +congrats, you are done! + +### [For Facilitator ONLY] How to execute + +#### Execute the transaction + +1. IMPORTANT: Ensure op-challenger has been updated before executing. +1. Collect outputs from all participating signers. +1. Concatenate all signatures and export it as the `SIGNATURES` + environment variable, i.e. `export +SIGNATURES="[SIGNATURE1][SIGNATURE2]..."`. +1. Run the `make execute` or `make approve` command as described below to execute the transaction. + +For example, if the quorum is 2 and you get the following outputs: + +```shell +Data: 0xDEADBEEF +Signer: 0xC0FFEE01 +Signature: AAAA +``` + +```shell +Data: 0xDEADBEEF +Signer: 0xC0FFEE02 +Signature: BBBB +``` + +If on testnet, then you should run: + +Coinbase facilitator: + +```bash +SIGNATURES=AAAABBBB make execute +``` + +If on mainnet, then you should run: + +Optimism facilitator: + +```bash +SIGNATURES=AAAABBBB make approve-op +``` + +#### If on mainnet, execute the transaction + +Once the signatures have been submitted approving the transaction for all nested Safes run: + +```bash +make execute +``` diff --git a/setup-templates/template-switch-to-permissioned-game-retire/foundry.toml b/setup-templates/template-switch-to-permissioned-game-retire/foundry.toml new file mode 100644 index 00000000..7a443d45 --- /dev/null +++ b/setup-templates/template-switch-to-permissioned-game-retire/foundry.toml @@ -0,0 +1,20 @@ +[profile.default] +src = 'src' +out = 'out' +libs = ['lib'] +broadcast = 'records' +fs_permissions = [{ access = "read-write", path = "./" }] +optimizer = true +optimizer_runs = 200 +via-ir = false +remappings = [ + '@eth-optimism-bedrock/=lib/optimism/packages/contracts-bedrock/', + '@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts', + '@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts', + '@rari-capital/solmate/=lib/solmate/', + '@base-contracts/=lib/base-contracts', + 'solady/=lib/solady/src/', + '@lib-keccak/=lib/lib-keccak/contracts/lib', +] + +# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-retire/script/SwitchToPermissionedGame.sol similarity index 100% rename from setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol rename to setup-templates/template-switch-to-permissioned-game-retire/script/SwitchToPermissionedGame.sol From c553fcae8776ebf55139ebf75594924fb98f1eb9 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Fri, 24 Oct 2025 16:55:11 -0400 Subject: [PATCH 11/27] update readmes --- .../README.md | 6 +++--- .../template-switch-to-permissioned-game-retire/README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md index 9a6ba8f9..b275381c 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md @@ -4,8 +4,8 @@ Status: PENDING ## Description -This task contains a single script that will update the `respectedGameType` and `retirementTimestamp` in the AnchorStateRegistry. This can only be done by the -"Optimism Guardian Multisig" which is a single-nested multisig controlled by the OP Security Council. +This task contains a single script that will blacklist fault dispute games after a provided L2 block number in the AnchorStateRegistry. +This can only be done by the "Optimism Guardian Multisig" which is a single-nested multisig controlled by the OP Security Council. ## Procedure @@ -14,7 +14,7 @@ This task contains a single script that will update the `respectedGameType` and ```bash cd contract-deployments git pull -cd /-switch-to-permissioned-game +cd /-switch-to-permissioned-game-blacklist make deps ``` diff --git a/setup-templates/template-switch-to-permissioned-game-retire/README.md b/setup-templates/template-switch-to-permissioned-game-retire/README.md index 9a6ba8f9..d19c5e90 100644 --- a/setup-templates/template-switch-to-permissioned-game-retire/README.md +++ b/setup-templates/template-switch-to-permissioned-game-retire/README.md @@ -14,7 +14,7 @@ This task contains a single script that will update the `respectedGameType` and ```bash cd contract-deployments git pull -cd /-switch-to-permissioned-game +cd /-switch-to-permissioned-game-retire make deps ``` From 8db838c203c98908795d2a4600d6cee7ce8021d7 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Fri, 24 Oct 2025 16:56:10 -0400 Subject: [PATCH 12/27] add expected time to readme --- .../template-switch-to-permissioned-game-blacklist/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md index b275381c..44fea261 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md @@ -6,6 +6,7 @@ Status: PENDING This task contains a single script that will blacklist fault dispute games after a provided L2 block number in the AnchorStateRegistry. This can only be done by the "Optimism Guardian Multisig" which is a single-nested multisig controlled by the OP Security Council. +This task may take 10+ minutes to complete. ## Procedure From 23f3cb0e823f3cc7537c0efab56ce7e0d6b77b66 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 29 Oct 2025 16:59:38 -0400 Subject: [PATCH 13/27] update game finding --- .../.env | 3 +- .../script/SwitchToPermissionedGame.sol | 20 ++- .../script/fetch_dispute_games.py | 123 ++++++++++++++++++ 3 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 setup-templates/template-switch-to-permissioned-game-blacklist/script/fetch_dispute_games.py diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/.env b/setup-templates/template-switch-to-permissioned-game-blacklist/.env index 82680eaa..7627edc5 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/.env +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/.env @@ -1,7 +1,8 @@ OP_COMMIT= BASE_CONTRACTS_COMMIT= -L2_DIVERGENCE_BLOCK_NUMBER= +# Comma seperated array of addresses to blacklist +ADDRESSES_TO_BLACKLIST= # Mainnet Config SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol index 2d10ae9c..8488cea8 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol @@ -23,7 +23,7 @@ contract SwitchToPermissionedGame is MultisigScript { string public constant EXPECTED_VERSION = "1.4.1"; address public immutable OWNER_SAFE; - uint256 public immutable L2_DIVERGENCE_BLOCK_NUMBER; + string public immutable RAW_ADDRESSES_TO_BLACKLIST; SystemConfig internal _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); @@ -32,7 +32,7 @@ contract SwitchToPermissionedGame is MultisigScript { constructor() { OWNER_SAFE = vm.envAddress("OWNER_SAFE"); - L2_DIVERGENCE_BLOCK_NUMBER = uint64(vm.envUint("L2_DIVERGENCE_BLOCK_NUMBER")); + RAW_ADDRESSES_TO_BLACKLIST = vm.envString("ADDRESSES_TO_BLACKLIST"); } function setUp() public { @@ -40,7 +40,18 @@ contract SwitchToPermissionedGame is MultisigScript { FaultDisputeGame currentFdg = FaultDisputeGame(address(dgfProxy.gameImpls(GameTypes.CANNON))); anchorStateRegistry = currentFdg.anchorStateRegistry(); - getGamesToBlacklist(dgfProxy); + // Split by commas + string[] memory parts = vm.split(RAW_ADDRESSES_TO_BLACKLIST, ","); + if (parts.length == 0) { + for (uint256 i; i < parts.length; i++) { + address_to_blacklist = vm.parseAddress(parts[i]); + gamesToBlacklist.push(address_to_blacklist); + } + } else { + getGamesToBlacklist(dgfProxy); + } + + console.log("total games to blacklist", gamesToBlacklist.length); } function getGamesToBlacklist(IDisputeGameFactory dgfProxy) internal { @@ -54,8 +65,6 @@ contract SwitchToPermissionedGame is MultisigScript { gamesToBlacklist.push(game); } } - - console.log("total games to blacklist", gamesToBlacklist.length); } // Confirm the CURRENT_RETIREMENT_TIMESTAMP is updated to the block time. @@ -65,7 +74,6 @@ contract SwitchToPermissionedGame is MultisigScript { } } - function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](gamesToBlacklist.length); diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/fetch_dispute_games.py b/setup-templates/template-switch-to-permissioned-game-blacklist/script/fetch_dispute_games.py new file mode 100644 index 00000000..36c4f34b --- /dev/null +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/fetch_dispute_games.py @@ -0,0 +1,123 @@ +from web3 import Web3 +import sys +from eth_hash.auto import keccak +from concurrent.futures import ThreadPoolExecutor, as_completed + +# ------------------------------- +# Configuration +# ------------------------------- + +# Example: replace with your Ethereum JSON-RPC endpoint +RPC_URL = "https://ethereum-full-sepolia-k8s-prod-proxy.cbhq.net" + +# Replace with your contract address +CONTRACT_ADDRESS = "0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1" + +# The storage slot index where the array is stored (integer) +ARRAY_SLOT = 104 + +# Number of elements to fetch (optional limit if you don’t want to fetch all) +MAX_ELEMENTS = 100 + +abi = [ + { + "inputs": [], + "name": "l2BlockNumber", + "outputs": [{"internalType": "uint256", "name": "l2SequenceNumber_", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + } +] + +# ------------------------------- +# Setup Web3 +# ------------------------------- + +w3 = Web3(Web3.HTTPProvider(RPC_URL)) + +if not w3.is_connected(): + print("Failed to connect to the Ethereum node.") + sys.exit(1) + +# ------------------------------- +# Helper functions +# ------------------------------- + +def keccak256(value: bytes) -> bytes: + """Compute keccak256 hash of given bytes.""" + return keccak(value) + +def get_storage_at(address, slot): + """Read raw 32-byte storage value from the given slot.""" + return w3.eth.get_storage_at(address, slot) + +def read_dispute_game_addresses(address, base_slot, max_elements=None, max_workers=10): + """ + Reads a dynamic array of addresses from storage in parallel threads. + """ + # 1️⃣ Read array length + length_data = get_storage_at(address, base_slot) + length = int.from_bytes(length_data, byteorder="big") + print(f"Array length: {length}") + + if max_elements: + length = min(length, max_elements) + + # 2️⃣ Compute starting slot for elements: keccak256(p) + base_hash = keccak256(base_slot.to_bytes(32, byteorder="big")) + base_int = int.from_bytes(base_hash, byteorder="big") + + # 3️⃣ Prepare list of slots to read + slots = [base_int + i for i in range(length)] + + # 4️⃣ Worker function for fetching a single address + def fetch_address(i, slot): + value_bytes = get_storage_at(address, slot) + value_int = int.from_bytes(value_bytes, byteorder="big") + addr_hex = hex(value_int)[2:].rjust(64, "0")[-40:] + return i, Web3.to_checksum_address("0x" + addr_hex) + + # 5️⃣ Launch parallel reads + addresses = [None] * length + with ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = [executor.submit(fetch_address, i, slot) for i, slot in enumerate(slots)] + for future in as_completed(futures): + i, addr = future.result() + addresses[i] = addr + print(f"[{i}] {addr}") + + return addresses + +def filter_dispute_game_addresses_by_l2_divergence_block_number(addresses, l2_divergence_block_number, max_workers=10): + # 1️⃣ Worker function to fetch the l2 block number of a dispute game + def fetch_l2_block_number(i, contract_address): + contract = w3.eth.contract(address=contract_address, abi=abi) + l2_block_number = contract.functions.l2BlockNumber().call() + return i, contract_address, l2_block_number + + + # 2️⃣ Launch parallel reads + filtered_address = [None] * len(addresses) + with ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = [executor.submit(fetch_l2_block_number, i, contract_address) for i, contract_address in enumerate(addresses)] + for future in as_completed(futures): + i, contract_address, l2_block_number = future.result() + filtered_address[i] = (contract_address, l2_block_number) + print(f"[{i}] {l2_block_number}") + + filtered_address = [x[0] for x in filtered_address if x is not None and x[1] >= l2_divergence_block_number] + return filtered_address + +def array_to_comma_seperated_string(array): + return ",".join(array) + +# ------------------------------- +# Run +# ------------------------------- +if __name__ == "__main__": + print(f"Reading array from contract {CONTRACT_ADDRESS} at slot {ARRAY_SLOT}...") + addresses = read_dispute_game_addresses(CONTRACT_ADDRESS, ARRAY_SLOT, max_elements=5) + addresses = filter_dispute_game_addresses_by_l2_divergence_block_number(addresses, 1) + + print(f"\nFound {len(addresses)} dispute game addresses.") + print(f"\nAddresses: {array_to_comma_seperated_string(addresses)}") From 6ec114649927af45702c443890c756dcd2e996f9 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 29 Oct 2025 17:01:58 -0400 Subject: [PATCH 14/27] add log statements --- .../script/SwitchToPermissionedGame.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol index 8488cea8..8bfd1d5c 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol @@ -43,11 +43,13 @@ contract SwitchToPermissionedGame is MultisigScript { // Split by commas string[] memory parts = vm.split(RAW_ADDRESSES_TO_BLACKLIST, ","); if (parts.length == 0) { + console.log("using provided address_to_blacklist list"); for (uint256 i; i < parts.length; i++) { address_to_blacklist = vm.parseAddress(parts[i]); gamesToBlacklist.push(address_to_blacklist); } } else { + console.log("searching for addresses to blacklist"); getGamesToBlacklist(dgfProxy); } From 24e12ed68f9e7c6d2838d41d5d6387ff947239f0 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 14:13:21 -0400 Subject: [PATCH 15/27] fix scripts --- .../.env | 4 ++ .../Makefile | 10 +++- .../script/SwitchToPermissionedGame.sol | 10 ++-- .../script/fetch_dispute_games.py | 52 ++++++++++++------- .../script/requirements.txt | 2 + 5 files changed, 55 insertions(+), 23 deletions(-) create mode 100644 setup-templates/template-switch-to-permissioned-game-blacklist/script/requirements.txt diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/.env b/setup-templates/template-switch-to-permissioned-game-blacklist/.env index 7627edc5..35fe1cec 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/.env +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/.env @@ -1,6 +1,8 @@ OP_COMMIT= BASE_CONTRACTS_COMMIT= +# The block number at which the divergence occurred +L2_DIVERGENCE_BLOCK_NUMBER= # Comma seperated array of addresses to blacklist ADDRESSES_TO_BLACKLIST= @@ -9,9 +11,11 @@ SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 OWNER_SAFE=0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2 # Optimism Guardian Multisig (controls Anchor State Registry) OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 # Owner of Optimism Guardian Multisig +DISPUTE_GAME_FACTORY=0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e # # Sepolia Config # SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 # OWNER_SAFE=0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E # Optimism Guardian Multisig (controls Anchor State Registry) # OP_SECURITY_COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 # Owner of Optimism Guardian Multisig +# DISPUTE_GAME_FACTORY=0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1 diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile b/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile index 12f0b7b0..e422e111 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile @@ -26,10 +26,18 @@ execute: $(call MULTISIG_EXECUTE,0x) # Base -- used for simulating the transcations as op-signers by base engineers -.PHONY: sign-base-sepolia +.PHONY: sign-base-mainnet sign-base-mainnet: $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e .PHONY: sign-base-sepolia sign-base-sepolia: $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1084092Ac2f04c866806CF3d4a385Afa4F6A6C97 + +.PHONY: find-dispute-games-offchain +find-dispute-games-offchain: pip-install + RPC_URL=$(RPC_URL) DISPUTE_GAME_FACTORY=$(DISPUTE_GAME_FACTORY) L2_DIVERGENCE_BLOCK_NUMBER=$(L2_DIVERGENCE_BLOCK_NUMBER) \ + python3 script/fetch_dispute_games.py + +.PHONY: pip-install + pip3 install -r script/requirements.txt diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol index 8bfd1d5c..48eeded3 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol @@ -23,7 +23,8 @@ contract SwitchToPermissionedGame is MultisigScript { string public constant EXPECTED_VERSION = "1.4.1"; address public immutable OWNER_SAFE; - string public immutable RAW_ADDRESSES_TO_BLACKLIST; + uint64 public immutable L2_DIVERGENCE_BLOCK_NUMBER; + string public RAW_ADDRESSES_TO_BLACKLIST; SystemConfig internal _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); @@ -33,6 +34,7 @@ contract SwitchToPermissionedGame is MultisigScript { constructor() { OWNER_SAFE = vm.envAddress("OWNER_SAFE"); RAW_ADDRESSES_TO_BLACKLIST = vm.envString("ADDRESSES_TO_BLACKLIST"); + L2_DIVERGENCE_BLOCK_NUMBER = uint64(vm.envUint("L2_DIVERGENCE_BLOCK_NUMBER")); } function setUp() public { @@ -42,11 +44,11 @@ contract SwitchToPermissionedGame is MultisigScript { // Split by commas string[] memory parts = vm.split(RAW_ADDRESSES_TO_BLACKLIST, ","); - if (parts.length == 0) { + if (parts.length != 0) { console.log("using provided address_to_blacklist list"); for (uint256 i; i < parts.length; i++) { - address_to_blacklist = vm.parseAddress(parts[i]); - gamesToBlacklist.push(address_to_blacklist); + address address_to_blacklist = vm.parseAddress(parts[i]); + gamesToBlacklist.push(IDisputeGame(address_to_blacklist)); } } else { console.log("searching for addresses to blacklist"); diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/fetch_dispute_games.py b/setup-templates/template-switch-to-permissioned-game-blacklist/script/fetch_dispute_games.py index 36c4f34b..47e82656 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/script/fetch_dispute_games.py +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/fetch_dispute_games.py @@ -1,5 +1,6 @@ from web3 import Web3 import sys +import os from eth_hash.auto import keccak from concurrent.futures import ThreadPoolExecutor, as_completed @@ -7,11 +8,26 @@ # Configuration # ------------------------------- -# Example: replace with your Ethereum JSON-RPC endpoint -RPC_URL = "https://ethereum-full-sepolia-k8s-prod-proxy.cbhq.net" - -# Replace with your contract address -CONTRACT_ADDRESS = "0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1" +try: + RPC_URL = os.environ['RPC_URL'] + print(f"RPC_URL environment variable: {RPC_URL}") +except KeyError: + print("RPC_URL environment variable not set.") + os.exit(1) + +try: + DISPUTE_GAME_FACTORY = os.environ['DISPUTE_GAME_FACTORY'] + print(f"DISPUTE_GAME_FACTORY environment variable: {DISPUTE_GAME_FACTORY}") +except KeyError: + print("DISPUTE_GAME_FACTORY environment variable not set.") + os.exit(1) + +try: + L2_DIVERGENCE_BLOCK_NUMBER = int(os.environ['L2_DIVERGENCE_BLOCK_NUMBER']) + print(f"L2_DIVERGENCE_BLOCK_NUMBER environment variable: {L2_DIVERGENCE_BLOCK_NUMBER}") +except KeyError: + print("L2_DIVERGENCE_BLOCK_NUMBER environment variable not set.") + os.exit(1) # The storage slot index where the array is stored (integer) ARRAY_SLOT = 104 @@ -58,7 +74,7 @@ def read_dispute_game_addresses(address, base_slot, max_elements=None, max_worke # 1️⃣ Read array length length_data = get_storage_at(address, base_slot) length = int.from_bytes(length_data, byteorder="big") - print(f"Array length: {length}") + print(f"Total number of dispute games: {length}") if max_elements: length = min(length, max_elements) @@ -84,26 +100,26 @@ def fetch_address(i, slot): for future in as_completed(futures): i, addr = future.result() addresses[i] = addr - print(f"[{i}] {addr}") + print(f"Dispute Game Address [{i}]: {addr}") return addresses def filter_dispute_game_addresses_by_l2_divergence_block_number(addresses, l2_divergence_block_number, max_workers=10): # 1️⃣ Worker function to fetch the l2 block number of a dispute game - def fetch_l2_block_number(i, contract_address): - contract = w3.eth.contract(address=contract_address, abi=abi) + def fetch_l2_block_number(i, DISPUTE_GAME_FACTORY): + contract = w3.eth.contract(address=DISPUTE_GAME_FACTORY, abi=abi) l2_block_number = contract.functions.l2BlockNumber().call() - return i, contract_address, l2_block_number + return i, DISPUTE_GAME_FACTORY, l2_block_number # 2️⃣ Launch parallel reads filtered_address = [None] * len(addresses) with ThreadPoolExecutor(max_workers=max_workers) as executor: - futures = [executor.submit(fetch_l2_block_number, i, contract_address) for i, contract_address in enumerate(addresses)] + futures = [executor.submit(fetch_l2_block_number, i, DISPUTE_GAME_FACTORY) for i, DISPUTE_GAME_FACTORY in enumerate(addresses)] for future in as_completed(futures): - i, contract_address, l2_block_number = future.result() - filtered_address[i] = (contract_address, l2_block_number) - print(f"[{i}] {l2_block_number}") + i, DISPUTE_GAME_FACTORY, l2_block_number = future.result() + filtered_address[i] = (DISPUTE_GAME_FACTORY, l2_block_number) + print(f"Dispute Game L2 Block Number: [{i}] {l2_block_number}") filtered_address = [x[0] for x in filtered_address if x is not None and x[1] >= l2_divergence_block_number] return filtered_address @@ -115,9 +131,9 @@ def array_to_comma_seperated_string(array): # Run # ------------------------------- if __name__ == "__main__": - print(f"Reading array from contract {CONTRACT_ADDRESS} at slot {ARRAY_SLOT}...") - addresses = read_dispute_game_addresses(CONTRACT_ADDRESS, ARRAY_SLOT, max_elements=5) - addresses = filter_dispute_game_addresses_by_l2_divergence_block_number(addresses, 1) + print(f"Reading array from contract {DISPUTE_GAME_FACTORY} at slot {ARRAY_SLOT}...") + addresses = read_dispute_game_addresses(DISPUTE_GAME_FACTORY, ARRAY_SLOT, max_elements=None) + addresses = filter_dispute_game_addresses_by_l2_divergence_block_number(addresses, L2_DIVERGENCE_BLOCK_NUMBER) print(f"\nFound {len(addresses)} dispute game addresses.") - print(f"\nAddresses: {array_to_comma_seperated_string(addresses)}") + print(f"\nADDRESSES_TO_BLACKLIST={array_to_comma_seperated_string(addresses)}") diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/requirements.txt b/setup-templates/template-switch-to-permissioned-game-blacklist/script/requirements.txt new file mode 100644 index 00000000..ca6f8ec0 --- /dev/null +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/requirements.txt @@ -0,0 +1,2 @@ +web3>=6.0.0 +eth-hash>=0.5.2 From 8839fb302a9c8e37c16c8ed78c96d234c3232252 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 14:22:26 -0400 Subject: [PATCH 16/27] update readme --- .../README.md | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md index 44fea261..37f665fa 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md @@ -4,9 +4,22 @@ Status: PENDING ## Description -This task contains a single script that will blacklist fault dispute games after a provided L2 block number in the AnchorStateRegistry. +This task contains scripts that will blacklist fault dispute games after a provided L2 block number in the AnchorStateRegistry. This can only be done by the "Optimism Guardian Multisig" which is a single-nested multisig controlled by the OP Security Council. -This task may take 10+ minutes to complete. + +Because this requires searching through all dispute games, the time required for the task to execute may take some time. There are +two options: + +1. If the ADDRESSES_TO_BLACKLIST environemnt variable is NOT set, the forge script will attempt to search for dispute games + Note: this may take 10+ minutes + +2. If the ADDRESSES_TO_BLACKLIST environemnt variable IS set, the forge script will NOT search and will just blacklist the addresses + provided. + + There is a python script provided that can be run with `make find-dispute-games-offchain` that will use the provided + RPC_URL to search for the list of games to blacklist _offchain_. This typically takes a minute or two. The output + is the comma-separated ADDRESSES_TO_BLACKLIST environment variable that can be copied over to the `.env` file, so that + the forge script can directly blacklist just those addresses. ## Procedure @@ -29,14 +42,18 @@ is ready". #### 3.1 Sign the transaction -**If on mainnet**: - Op signer: ```bash make sign-op ``` +Base engineer: + +```bash +make sign-base- +``` + You will see a "Simulation link" from the output. Paste this URL in your browser. A prompt may ask you to choose a From 6c193ea652a6e5b8ea681097c44ea5a245e53748 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 14:24:00 -0400 Subject: [PATCH 17/27] fix readme --- .../README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md index 37f665fa..45ebe0d6 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md @@ -1,4 +1,4 @@ -# Upgrade Fault Proofs +# Switch to Permissioned Game and Blacklist addresses Status: PENDING @@ -10,15 +10,15 @@ This can only be done by the "Optimism Guardian Multisig" which is a single-nest Because this requires searching through all dispute games, the time required for the task to execute may take some time. There are two options: -1. If the ADDRESSES_TO_BLACKLIST environemnt variable is NOT set, the forge script will attempt to search for dispute games +1. If the `ADDRESSES_TO_BLACKLIST` environemnt variable is NOT set, the forge script will attempt to search for dispute games Note: this may take 10+ minutes -2. If the ADDRESSES_TO_BLACKLIST environemnt variable IS set, the forge script will NOT search and will just blacklist the addresses +2. If the `ADDRESSES_TO_BLACKLIST` environemnt variable IS set, the forge script will NOT search and will just blacklist the addresses provided. There is a python script provided that can be run with `make find-dispute-games-offchain` that will use the provided RPC_URL to search for the list of games to blacklist _offchain_. This typically takes a minute or two. The output - is the comma-separated ADDRESSES_TO_BLACKLIST environment variable that can be copied over to the `.env` file, so that + is the comma-separated `ADDRESSES_TO_BLACKLIST` environment variable that can be copied over to the `.env` file, so that the forge script can directly blacklist just those addresses. ## Procedure From 15386a8c52ec96903fe8c434844ba1147ded4862 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 14:24:16 -0400 Subject: [PATCH 18/27] fix readme --- .../template-switch-to-permissioned-game-blacklist/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md index 45ebe0d6..262d6eff 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md @@ -1,4 +1,4 @@ -# Switch to Permissioned Game and Blacklist addresses +# Switch to Permissioned Game and Blacklist Addresses Status: PENDING From 94c1451a2a30f9980dd44ddc4a45e1e5fc56b551 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 14:24:52 -0400 Subject: [PATCH 19/27] fix readme --- .../template-switch-to-permissioned-game-blacklist/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md index 262d6eff..79f9c793 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md @@ -10,10 +10,10 @@ This can only be done by the "Optimism Guardian Multisig" which is a single-nest Because this requires searching through all dispute games, the time required for the task to execute may take some time. There are two options: -1. If the `ADDRESSES_TO_BLACKLIST` environemnt variable is NOT set, the forge script will attempt to search for dispute games +1. If the `ADDRESSES_TO_BLACKLIST` environment variable is NOT set, the forge script will attempt to search for dispute games Note: this may take 10+ minutes -2. If the `ADDRESSES_TO_BLACKLIST` environemnt variable IS set, the forge script will NOT search and will just blacklist the addresses +2. If the `ADDRESSES_TO_BLACKLIST` environment variable IS set, the forge script will NOT search and will just blacklist the addresses provided. There is a python script provided that can be run with `make find-dispute-games-offchain` that will use the provided From a01a582c0d4a0b7d16af6b1c774a1f891eead18e Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 15:08:00 -0400 Subject: [PATCH 20/27] set respected game type --- .../script/SwitchToPermissionedGame.sol | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol index 48eeded3..d483c2bc 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol @@ -79,10 +79,17 @@ contract SwitchToPermissionedGame is MultisigScript { } function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { - IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](gamesToBlacklist.length); + IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](gamesToBlacklist.length + 1); + + calls[0] = IMulticall3.Call3Value({ + target: address(anchorStateRegistry), + allowFailure: false, + callData: abi.encodeCall(IAnchorStateRegistry.setRespectedGameType, (GameTypes.PERMISSIONED_CANNON)), + value: 0 + }); for (uint256 i = 0; i < gamesToBlacklist.length; i = i + 1) { - calls[i] = IMulticall3.Call3Value({ + calls[i+1] = IMulticall3.Call3Value({ target: address(anchorStateRegistry), allowFailure: false, callData: abi.encodeCall(IAnchorStateRegistry.blacklistDisputeGame, (gamesToBlacklist[i])), From 7384d6a83c1ce87677ee3385d865ec0065ab963b Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 15:09:15 -0400 Subject: [PATCH 21/27] update readme --- setup-templates/template-switch-to-permissioned-game/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup-templates/template-switch-to-permissioned-game/README.md b/setup-templates/template-switch-to-permissioned-game/README.md index 9a6ba8f9..9a55a1e1 100644 --- a/setup-templates/template-switch-to-permissioned-game/README.md +++ b/setup-templates/template-switch-to-permissioned-game/README.md @@ -1,4 +1,4 @@ -# Upgrade Fault Proofs +# Switch to Permissioned Game and Retire Games Status: PENDING From e483c92d7f225e830560805b6f4bd806032986f3 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 15:10:10 -0400 Subject: [PATCH 22/27] fix makefile --- setup-templates/template-switch-to-permissioned-game/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup-templates/template-switch-to-permissioned-game/Makefile b/setup-templates/template-switch-to-permissioned-game/Makefile index 12f0b7b0..710e2cb9 100644 --- a/setup-templates/template-switch-to-permissioned-game/Makefile +++ b/setup-templates/template-switch-to-permissioned-game/Makefile @@ -26,7 +26,7 @@ execute: $(call MULTISIG_EXECUTE,0x) # Base -- used for simulating the transcations as op-signers by base engineers -.PHONY: sign-base-sepolia +.PHONY: sign-base-mainnet sign-base-mainnet: $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e From f2d28462c4a873b433180b6ddd41f8f612b8cbb2 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 15:12:18 -0400 Subject: [PATCH 23/27] fix makefile --- .../template-switch-to-permissioned-game-blacklist/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile b/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile index e422e111..b1b1fbd3 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile @@ -40,4 +40,5 @@ find-dispute-games-offchain: pip-install python3 script/fetch_dispute_games.py .PHONY: pip-install +pip-install: pip3 install -r script/requirements.txt From 65e420cb88f2710ef05e61b953fe5b841f9761fa Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Thu, 30 Oct 2025 15:31:12 -0400 Subject: [PATCH 24/27] add post check for permissioned --- .../script/SwitchToPermissionedGame.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol index d483c2bc..ce638683 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol @@ -76,6 +76,7 @@ contract SwitchToPermissionedGame is MultisigScript { for (uint256 i = 0; i < gamesToBlacklist.length; i = i + 1) { require(anchorStateRegistry.isGameBlacklisted(gamesToBlacklist[i]), "post-110"); } + require(GameType.unwrap(anchorStateRegistry.respectedGameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), "post-111"); } function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { From a52bdbdab181c0c75136c2fb3758bcbf6e56dd16 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 3 Dec 2025 17:44:46 -0500 Subject: [PATCH 25/27] fmt --- README.md | 4 +- .../.env | 17 +- .../Makefile | 23 ++- .../script/SwitchToPermissionedGame.sol | 19 ++- .../.env | 24 ++- .../Makefile | 24 ++- .../README.md | 161 +++--------------- .../script/SwitchToPermissionedGame.sol | 30 +--- .../template-switch-to-permissioned-game/.env | 25 --- .../Makefile | 33 ---- .../README.md | 51 ------ .../foundry.toml | 20 --- .../script/SwitchToPermissionedGame.sol | 65 ------- 13 files changed, 96 insertions(+), 400 deletions(-) delete mode 100644 setup-templates/template-switch-to-permissioned-game/.env delete mode 100644 setup-templates/template-switch-to-permissioned-game/Makefile delete mode 100644 setup-templates/template-switch-to-permissioned-game/README.md delete mode 100644 setup-templates/template-switch-to-permissioned-game/foundry.toml delete mode 100644 setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol diff --git a/README.md b/README.md index 46cae10e..8522ee9e 100644 --- a/README.md +++ b/README.md @@ -194,12 +194,12 @@ This template is used to pause or un-pause [Base Bridge](https://github.com/base 1. Check in the task when it's ready to sign and request the facilitators to collect signatures from signers. 1. Once executed, check in the records files and mark the task `EXECUTED` in the README. -## Using the Switch to Permissioned Game template +## Using the Switch to Permissioned Game Retire/Blacklist template This template is used to switch Base to a Permissioned Game. 1. Ensure you have followed the instructions above in `setup`. -1. Run `make setup-switch-to-permissioned-game network=` and go to the folder that was created by this command. +1. Run `make setup-switch-to-permissioned-game- network=` and go to the folder that was created by this command. 1. Specify the commit of [Optimism code](https://github.com/ethereum-optimism/optimism) and [Base contracts code](https://github.com/base/contracts) you intend to use in the `.env` file. 1. Run `make deps`. 1. Ensure only the Sepolia or Mainnet variables are in the `.env` file depending on what network this task is for. diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/.env b/setup-templates/template-switch-to-permissioned-game-blacklist/.env index 35fe1cec..631c25c4 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/.env +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/.env @@ -1,6 +1,8 @@ OP_COMMIT= BASE_CONTRACTS_COMMIT= +RECORD_STATE_DIFF=true + # The block number at which the divergence occurred L2_DIVERGENCE_BLOCK_NUMBER= # Comma seperated array of addresses to blacklist @@ -9,13 +11,20 @@ ADDRESSES_TO_BLACKLIST= # Mainnet Config SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 -OWNER_SAFE=0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2 # Optimism Guardian Multisig (controls Anchor State Registry) -OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 # Owner of Optimism Guardian Multisig +# Optimism Guardian Multisig (controls Anchor State Registry) +OWNER_SAFE=0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2 +# Owner of Optimism Guardian Multisig +OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 DISPUTE_GAME_FACTORY=0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e +SENDER=0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e # # Sepolia Config # SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 -# OWNER_SAFE=0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E # Optimism Guardian Multisig (controls Anchor State Registry) -# OP_SECURITY_COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 # Owner of Optimism Guardian Multisig +# # Optimism Guardian Multisig (controls Anchor State Registry) +# OWNER_SAFE=0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E +# # Owner of Optimism Guardian Multisig +# OP_SECURITY_COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 # DISPUTE_GAME_FACTORY=0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1 +# # used to simulate +# SENDER=0x1084092Ac2f04c866806CF3d4a385Afa4F6A6C97 diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile b/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile index b1b1fbd3..419d1c4c 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/Makefile @@ -11,10 +11,17 @@ endif RPC_URL = $(L1_RPC_URL) SCRIPT_NAME = SwitchToPermissionedGame -# OP -.PHONY: sign-op -sign-op: - $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) +.PHONY: gen-validation +gen-validation: checkout-signer-tool run-script + +.PHONY: run-script +run-script: + mkdir validations; \ + cd $(SIGNER_TOOL_PATH); \ + npm ci; \ + bun run scripts/genValidationFile.ts --rpc-url $(RPC_URL) \ + --workdir .. --forge-cmd 'forge script --rpc-url $(RPC_URL) \ + $(SCRIPT_NAME) --sig "sign(address[])" ["$(OP_SECURITY_COUNCIL_SAFE)"] --sender $(SENDER)' --out ../validations/op-signer.json; .PHONY: approve-op approve-op: @@ -25,14 +32,6 @@ approve-op: execute: $(call MULTISIG_EXECUTE,0x) -# Base -- used for simulating the transcations as op-signers by base engineers -.PHONY: sign-base-mainnet -sign-base-mainnet: - $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e - -.PHONY: sign-base-sepolia -sign-base-sepolia: - $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1084092Ac2f04c866806CF3d4a385Afa4F6A6C97 .PHONY: find-dispute-games-offchain find-dispute-games-offchain: pip-install diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol index ce638683..08174b15 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/script/SwitchToPermissionedGame.sol @@ -44,15 +44,17 @@ contract SwitchToPermissionedGame is MultisigScript { // Split by commas string[] memory parts = vm.split(RAW_ADDRESSES_TO_BLACKLIST, ","); - if (parts.length != 0) { + + // vm.split("", ",") return [""] with size 1 + if (parts.length == 0 || (parts.length == 1 && bytes(parts[0]).length == 0)) { + console.log("searching for addresses to blacklist"); + getGamesToBlacklist(dgfProxy); + } else { console.log("using provided address_to_blacklist list"); for (uint256 i; i < parts.length; i++) { address address_to_blacklist = vm.parseAddress(parts[i]); gamesToBlacklist.push(IDisputeGame(address_to_blacklist)); } - } else { - console.log("searching for addresses to blacklist"); - getGamesToBlacklist(dgfProxy); } console.log("total games to blacklist", gamesToBlacklist.length); @@ -63,7 +65,7 @@ contract SwitchToPermissionedGame is MultisigScript { console.log("total games to search", totalNumGames); for (uint256 i = 0; i < totalNumGames; i = i + 1) { - (, , IDisputeGame game) = dgfProxy.gameAtIndex(i); + (,, IDisputeGame game) = dgfProxy.gameAtIndex(i); if (game.status() == GameStatus.IN_PROGRESS && game.l2SequenceNumber() >= L2_DIVERGENCE_BLOCK_NUMBER) { // this game is in progress and challenges a block at or after the divergence block gamesToBlacklist.push(game); @@ -76,7 +78,10 @@ contract SwitchToPermissionedGame is MultisigScript { for (uint256 i = 0; i < gamesToBlacklist.length; i = i + 1) { require(anchorStateRegistry.isGameBlacklisted(gamesToBlacklist[i]), "post-110"); } - require(GameType.unwrap(anchorStateRegistry.respectedGameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), "post-111"); + require( + GameType.unwrap(anchorStateRegistry.respectedGameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), + "post-111" + ); } function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { @@ -90,7 +95,7 @@ contract SwitchToPermissionedGame is MultisigScript { }); for (uint256 i = 0; i < gamesToBlacklist.length; i = i + 1) { - calls[i+1] = IMulticall3.Call3Value({ + calls[i + 1] = IMulticall3.Call3Value({ target: address(anchorStateRegistry), allowFailure: false, callData: abi.encodeCall(IAnchorStateRegistry.blacklistDisputeGame, (gamesToBlacklist[i])), diff --git a/setup-templates/template-switch-to-permissioned-game-retire/.env b/setup-templates/template-switch-to-permissioned-game-retire/.env index 9cb2e0ad..a70fdcec 100644 --- a/setup-templates/template-switch-to-permissioned-game-retire/.env +++ b/setup-templates/template-switch-to-permissioned-game-retire/.env @@ -1,16 +1,26 @@ OP_COMMIT= BASE_CONTRACTS_COMMIT= -CURRENT_RETIREMENT_TIMESTAMP= +RECORD_STATE_DIFF=true # Mainnet Config SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 -OWNER_SAFE=0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2 # Optimism Guardian Multisig (controls Anchor State Registry) -OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 # Owner of Optimism Guardian Multisig +# Optimism Guardian Multisig (controls Anchor State Registry) +OWNER_SAFE=0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2 +# Owner of Optimism Guardian Multisig +OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 -# # Sepolia Config -# SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 +# used to simulate +SENDER=0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e -# OWNER_SAFE=0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E # Optimism Guardian Multisig (controls Anchor State Registry) -# OP_SECURITY_COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 # Owner of Optimism Guardian Multisig +# #Sepolia Config +#SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 + +# #Optimism Guardian Multisig (controls Anchor State Registry) +#OWNER_SAFE=0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E +# #Owner of Optimism Guardian Multisig +#OP_SECURITY_COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 + +# # used to simulate +#SENDER=0x1084092Ac2f04c866806CF3d4a385Afa4F6A6C97 \ No newline at end of file diff --git a/setup-templates/template-switch-to-permissioned-game-retire/Makefile b/setup-templates/template-switch-to-permissioned-game-retire/Makefile index 710e2cb9..66549ed2 100644 --- a/setup-templates/template-switch-to-permissioned-game-retire/Makefile +++ b/setup-templates/template-switch-to-permissioned-game-retire/Makefile @@ -11,10 +11,17 @@ endif RPC_URL = $(L1_RPC_URL) SCRIPT_NAME = SwitchToPermissionedGame -# OP -.PHONY: sign-op -sign-op: - $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) +.PHONY: gen-validation +gen-validation: checkout-signer-tool run-script + +.PHONY: run-script +run-script: + mkdir validations; \ + cd $(SIGNER_TOOL_PATH); \ + npm ci; \ + bun run scripts/genValidationFile.ts --rpc-url $(RPC_URL) \ + --workdir .. --forge-cmd 'forge script --rpc-url $(RPC_URL) \ + $(SCRIPT_NAME) --sig "sign(address[])" ["$(OP_SECURITY_COUNCIL_SAFE)"] --sender $(SENDER)' --out ../validations/op-signer.json; .PHONY: approve-op approve-op: @@ -24,12 +31,3 @@ approve-op: .PHONY: execute execute: $(call MULTISIG_EXECUTE,0x) - -# Base -- used for simulating the transcations as op-signers by base engineers -.PHONY: sign-base-mainnet -sign-base-mainnet: - $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e - -.PHONY: sign-base-sepolia -sign-base-sepolia: - $(call MULTISIG_SIGN,$(OP_SECURITY_COUNCIL_SAFE)) --sender 0x1084092Ac2f04c866806CF3d4a385Afa4F6A6C97 diff --git a/setup-templates/template-switch-to-permissioned-game-retire/README.md b/setup-templates/template-switch-to-permissioned-game-retire/README.md index e11d56ed..0aa31893 100644 --- a/setup-templates/template-switch-to-permissioned-game-retire/README.md +++ b/setup-templates/template-switch-to-permissioned-game-retire/README.md @@ -1,168 +1,51 @@ -# Switch to Permissioned Game and Retire Games +# Switch to Permissioned Games -Status: PENDING +Status: READY TO SIGN ## Description -This task contains a single script that will update the `respectedGameType` and `retirementTimestamp` in the AnchorStateRegistry. This can only be done by the -"Optimism Guardian Multisig" which is a single-nested multisig controlled by the OP Security Council. +Switches Base to Permissioned Fault Dispute Games and retires existing games. -## Procedure +## Install dependencies -### 1. Update repo: +### 1. Update foundry ```bash -cd contract-deployments -git pull -cd /-switch-to-permissioned-game-retire -make deps +foundryup ``` -### 2. Setup Ledger - -Your Ledger needs to be connected and unlocked. The Ethereum -application needs to be opened on Ledger with the message "Application -is ready". - -### 3. Run relevant script(s) - -#### 3.1 Sign the transaction +### 2. Install Node.js if needed -**If on mainnet**: - -Op signer: +First, check if you have node installed ```bash -make sign-op -``` - -You will see a "Simulation link" from the output. - -Paste this URL in your browser. A prompt may ask you to choose a -project, any project will do. You can create one if necessary. - -Click "Simulate Transaction". - -We will be performing 3 validations and extract the domain hash and message hash to approve on your Ledger: - -1. Validate integrity of the simulation. -2. Validate correctness of the state diff. -3. Validate and extract domain hash and message hash to approve. - -##### 3.2.1 Validate integrity of the simulation. - -Make sure you are on the "Summary" tab of the tenderly simulation, to -validate integrity of the simulation, we need to check the following: - -1. "Network": Check the network is Sepolia or Mainnet. -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 see the derivation path Note above. - -##### 3.2.2. Validate correctness of the state diff. - -Now click on the "State" tab, and refer to the [State Validations](./VALIDATION.md) instructions for the transaction you are signing. -Once complete return to this document to complete the signing. - -##### 3.2.3. Extract the domain hash and the message hash to approve. - -Now that we have verified the transaction performs the right -operation, we need to extract the domain hash and the message hash to -approve. - -Go back to the "Summary" tab, and find the -`GnosisSafe.checkSignatures` (for OP signers) or `Safe.checkSignatures` (for Coinbase signers) call. -This call's `data` parameter contains both the domain hash and the -message hash that will show up in your Ledger. - -It will be a concatenation of `0x1901`, the domain hash, and the -message hash: `0x1901[domain hash][message hash]`. - -Note down this value. You will need to compare it with the ones -displayed on the Ledger screen at signing. - -Once the validations are done, it's time to actually sign the -transaction. - -> [!WARNING] -> This is the most security critical part of the playbook: make sure the -> domain hash and message hash in the following two places match: -> -> 1. On your Ledger screen. -> 2. 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. -> -> There is no need to verify anything printed in the console. There is -> no need to open the new Tenderly simulation link either. - -After verification, sign the transaction. You will see the `Data`, -`Signer` and `Signature` printed in the console. Format should be -something like this: - -```shell -Data: -Signer:
-Signature: +node --version ``` -Double check the signer address is the right one. - -##### 3.2.4 Send the output to Facilitator(s) - -Nothing has occurred onchain - these are offchain signatures which -will be collected by Facilitators for execution. Execution can occur -by anyone once a threshold of signatures are collected, so a -Facilitator will do the final execution for convenience. - -Share the `Data`, `Signer` and `Signature` with the Facilitator, and -congrats, you are done! - -### [For Facilitator ONLY] How to execute - -#### Execute the transaction - -1. IMPORTANT: Ensure op-challenger has been updated before executing. -1. Collect outputs from all participating signers. -1. Concatenate all signatures and export it as the `SIGNATURES` - environment variable, i.e. `export -SIGNATURES="[SIGNATURE1][SIGNATURE2]..."`. -1. Run the `make execute` or `make approve` command as described below to execute the transaction. +If you see a version output from the above command, you can move on. Otherwise, install node -For example, if the quorum is 2 and you get the following outputs: - -```shell -Data: 0xDEADBEEF -Signer: 0xC0FFEE01 -Signature: AAAA -``` - -```shell -Data: 0xDEADBEEF -Signer: 0xC0FFEE02 -Signature: BBBB +```bash +brew install node ``` -If on testnet, then you should run: +## Sign Task -Coinbase facilitator: +### 1. Update repo: ```bash -SIGNATURES=AAAABBBB make execute +cd contract-deployments +git pull ``` -If on mainnet, then you should run: - -Optimism facilitator: +### 2. Run the signing tool (NOTE: do not enter the task directory. Run this command from the project's root). ```bash -SIGNATURES=AAAABBBB make approve-op +make sign-task ``` -#### If on mainnet, execute the transaction +### 3. Open the UI at [http://localhost:3000](http://localhost:3000) -Once the signatures have been submitted approving the transaction for all nested Safes run: +### 4. Send signature to facilitator + +You may now kill the Signer Tool process in your terminal window by running `Ctrl + C`. -```bash -make execute -``` diff --git a/setup-templates/template-switch-to-permissioned-game-retire/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game-retire/script/SwitchToPermissionedGame.sol index fe3b79b6..c11beb7b 100644 --- a/setup-templates/template-switch-to-permissioned-game-retire/script/SwitchToPermissionedGame.sol +++ b/setup-templates/template-switch-to-permissioned-game-retire/script/SwitchToPermissionedGame.sol @@ -2,9 +2,7 @@ pragma solidity 0.8.15; import {Vm} from "forge-std/Vm.sol"; -import {stdJson} from "forge-std/StdJson.sol"; import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol"; -import {console} from "forge-std/console.sol"; import {IAnchorStateRegistry} from "@eth-optimism-bedrock/src/dispute/FaultDisputeGame.sol"; import {SystemConfig} from "@eth-optimism-bedrock/src/L1/SystemConfig.sol"; import {DisputeGameFactory} from "@eth-optimism-bedrock/src/dispute/DisputeGameFactory.sol"; @@ -13,46 +11,34 @@ import {GameTypes, GameType} from "@eth-optimism-bedrock/src/dispute/lib/Types.s import {MultisigScript} from "@base-contracts/script/universal/MultisigScript.sol"; import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; -/// @notice This script updates the FaultDisputeGame and PermissionedDisputeGame implementations in the -/// DisputeGameFactory contract. +/// @notice This script updates the respectedGameType and retires existing games in the AnchorStateRegistry. contract SwitchToPermissionedGame is MultisigScript { - using stdJson for string; - - // TODO: Confirm expected version - string public constant EXPECTED_VERSION = "1.4.1"; - address public immutable OWNER_SAFE; - uint64 public immutable CURRENT_RETIREMENT_TIMESTAMP; - SystemConfig internal _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); + SystemConfig internal immutable _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); IAnchorStateRegistry anchorStateRegistry; constructor() { OWNER_SAFE = vm.envAddress("OWNER_SAFE"); - CURRENT_RETIREMENT_TIMESTAMP = uint64(vm.envUint("CURRENT_RETIREMENT_TIMESTAMP")); } function setUp() public { DisputeGameFactory dgfProxy = DisputeGameFactory(_SYSTEM_CONFIG.disputeGameFactory()); FaultDisputeGame currentFdg = FaultDisputeGame(address(dgfProxy.gameImpls(GameTypes.CANNON))); anchorStateRegistry = currentFdg.anchorStateRegistry(); - - _precheckRetirementTimestamp(); } - // Checks that the current state matches the CURRENT_RETIREMENT_TIMESTAMP - function _precheckRetirementTimestamp() internal view { - require(anchorStateRegistry.retirementTimestamp() == CURRENT_RETIREMENT_TIMESTAMP, "00"); - } - - // Confirm the CURRENT_RETIREMENT_TIMESTAMP is updated to the block time. + // Confirm the retirementTimestamp is updated to the block time and the + // respectedGameType is updated to PERMISSIONED_CANNON. function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { require(anchorStateRegistry.retirementTimestamp() == block.timestamp, "post-110"); - require(GameType.unwrap(anchorStateRegistry.respectedGameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), "post-111"); + require( + GameType.unwrap(anchorStateRegistry.respectedGameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), + "post-111" + ); } - function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](2); diff --git a/setup-templates/template-switch-to-permissioned-game/.env b/setup-templates/template-switch-to-permissioned-game/.env deleted file mode 100644 index 2c7d9882..00000000 --- a/setup-templates/template-switch-to-permissioned-game/.env +++ /dev/null @@ -1,25 +0,0 @@ -OP_COMMIT= -BASE_CONTRACTS_COMMIT= - -RECORD_STATE_DIFF=true - -# Mainnet Config -SYSTEM_CONFIG=0x73a79Fab69143498Ed3712e519A88a918e1f4072 - -# Optimism Guardian Multisig (controls Anchor State Registry) -OWNER_SAFE=0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2 -# Owner of Optimism Guardian Multisig -OP_SECURITY_COUNCIL_SAFE=0xc2819DC788505Aac350142A7A707BF9D03E3Bd03 - -SENDER=0x1822b35B09f5ce1C78ecbC06AC0A4e17885b925e # used to simulate - -# #Sepolia Config -#SYSTEM_CONFIG=0xf272670eb55e895584501d564AfEB048bEd26194 - -# #Optimism Guardian Multisig (controls Anchor State Registry) -#OWNER_SAFE=0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E -# #Owner of Optimism Guardian Multisig -#OP_SECURITY_COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 - -# # used to simulate -#SENDER=0x1084092Ac2f04c866806CF3d4a385Afa4F6A6C97 \ No newline at end of file diff --git a/setup-templates/template-switch-to-permissioned-game/Makefile b/setup-templates/template-switch-to-permissioned-game/Makefile deleted file mode 100644 index 66549ed2..00000000 --- a/setup-templates/template-switch-to-permissioned-game/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -include ../../Makefile -include ../../Multisig.mk - -include ../.env -include .env - -ifndef LEDGER_ACCOUNT -override LEDGER_ACCOUNT = 0 -endif - -RPC_URL = $(L1_RPC_URL) -SCRIPT_NAME = SwitchToPermissionedGame - -.PHONY: gen-validation -gen-validation: checkout-signer-tool run-script - -.PHONY: run-script -run-script: - mkdir validations; \ - cd $(SIGNER_TOOL_PATH); \ - npm ci; \ - bun run scripts/genValidationFile.ts --rpc-url $(RPC_URL) \ - --workdir .. --forge-cmd 'forge script --rpc-url $(RPC_URL) \ - $(SCRIPT_NAME) --sig "sign(address[])" ["$(OP_SECURITY_COUNCIL_SAFE)"] --sender $(SENDER)' --out ../validations/op-signer.json; - -.PHONY: approve-op -approve-op: - $(call MULTISIG_APPROVE,$(OP_SECURITY_COUNCIL_SAFE),$(SIGNATURES)) - -# Execute -.PHONY: execute -execute: - $(call MULTISIG_EXECUTE,0x) diff --git a/setup-templates/template-switch-to-permissioned-game/README.md b/setup-templates/template-switch-to-permissioned-game/README.md deleted file mode 100644 index 0aa31893..00000000 --- a/setup-templates/template-switch-to-permissioned-game/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Switch to Permissioned Games - -Status: READY TO SIGN - -## Description - -Switches Base to Permissioned Fault Dispute Games and retires existing games. - -## Install dependencies - -### 1. Update foundry - -```bash -foundryup -``` - -### 2. Install Node.js if needed - -First, check if you have node installed - -```bash -node --version -``` - -If you see a version output from the above command, you can move on. Otherwise, install node - -```bash -brew install node -``` - -## Sign Task - -### 1. Update repo: - -```bash -cd contract-deployments -git pull -``` - -### 2. Run the signing tool (NOTE: do not enter the task directory. Run this command from the project's root). - -```bash -make sign-task -``` - -### 3. Open the UI at [http://localhost:3000](http://localhost:3000) - -### 4. Send signature to facilitator - -You may now kill the Signer Tool process in your terminal window by running `Ctrl + C`. - diff --git a/setup-templates/template-switch-to-permissioned-game/foundry.toml b/setup-templates/template-switch-to-permissioned-game/foundry.toml deleted file mode 100644 index 7a443d45..00000000 --- a/setup-templates/template-switch-to-permissioned-game/foundry.toml +++ /dev/null @@ -1,20 +0,0 @@ -[profile.default] -src = 'src' -out = 'out' -libs = ['lib'] -broadcast = 'records' -fs_permissions = [{ access = "read-write", path = "./" }] -optimizer = true -optimizer_runs = 200 -via-ir = false -remappings = [ - '@eth-optimism-bedrock/=lib/optimism/packages/contracts-bedrock/', - '@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts', - '@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts', - '@rari-capital/solmate/=lib/solmate/', - '@base-contracts/=lib/base-contracts', - 'solady/=lib/solady/src/', - '@lib-keccak/=lib/lib-keccak/contracts/lib', -] - -# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol b/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol deleted file mode 100644 index c11beb7b..00000000 --- a/setup-templates/template-switch-to-permissioned-game/script/SwitchToPermissionedGame.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {Vm} from "forge-std/Vm.sol"; -import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol"; -import {IAnchorStateRegistry} from "@eth-optimism-bedrock/src/dispute/FaultDisputeGame.sol"; -import {SystemConfig} from "@eth-optimism-bedrock/src/L1/SystemConfig.sol"; -import {DisputeGameFactory} from "@eth-optimism-bedrock/src/dispute/DisputeGameFactory.sol"; -import {FaultDisputeGame} from "@eth-optimism-bedrock/src/dispute/PermissionedDisputeGame.sol"; -import {GameTypes, GameType} from "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; -import {MultisigScript} from "@base-contracts/script/universal/MultisigScript.sol"; -import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; - -/// @notice This script updates the respectedGameType and retires existing games in the AnchorStateRegistry. -contract SwitchToPermissionedGame is MultisigScript { - address public immutable OWNER_SAFE; - - SystemConfig internal immutable _SYSTEM_CONFIG = SystemConfig(vm.envAddress("SYSTEM_CONFIG")); - - IAnchorStateRegistry anchorStateRegistry; - - constructor() { - OWNER_SAFE = vm.envAddress("OWNER_SAFE"); - } - - function setUp() public { - DisputeGameFactory dgfProxy = DisputeGameFactory(_SYSTEM_CONFIG.disputeGameFactory()); - FaultDisputeGame currentFdg = FaultDisputeGame(address(dgfProxy.gameImpls(GameTypes.CANNON))); - anchorStateRegistry = currentFdg.anchorStateRegistry(); - } - - // Confirm the retirementTimestamp is updated to the block time and the - // respectedGameType is updated to PERMISSIONED_CANNON. - function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { - require(anchorStateRegistry.retirementTimestamp() == block.timestamp, "post-110"); - require( - GameType.unwrap(anchorStateRegistry.respectedGameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), - "post-111" - ); - } - - function _buildCalls() internal view override returns (IMulticall3.Call3Value[] memory) { - IMulticall3.Call3Value[] memory calls = new IMulticall3.Call3Value[](2); - - calls[0] = IMulticall3.Call3Value({ - target: address(anchorStateRegistry), - allowFailure: false, - callData: abi.encodeCall(IAnchorStateRegistry.setRespectedGameType, (GameTypes.PERMISSIONED_CANNON)), - value: 0 - }); - - calls[1] = IMulticall3.Call3Value({ - target: address(anchorStateRegistry), - allowFailure: false, - callData: abi.encodeCall(IAnchorStateRegistry.updateRetirementTimestamp, ()), - value: 0 - }); - - return calls; - } - - function _ownerSafe() internal view override returns (address) { - return OWNER_SAFE; - } -} From ad4b6d222505382165293034ccf70068b49272cf Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 3 Dec 2025 17:49:35 -0500 Subject: [PATCH 26/27] fix readme --- .../README.md | 155 ++---------------- 1 file changed, 17 insertions(+), 138 deletions(-) diff --git a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md index 79f9c793..b211a674 100644 --- a/setup-templates/template-switch-to-permissioned-game-blacklist/README.md +++ b/setup-templates/template-switch-to-permissioned-game-blacklist/README.md @@ -21,166 +21,45 @@ two options: is the comma-separated `ADDRESSES_TO_BLACKLIST` environment variable that can be copied over to the `.env` file, so that the forge script can directly blacklist just those addresses. -## Procedure +## Install dependencies -### 1. Update repo: +### 1. Update foundry ```bash -cd contract-deployments -git pull -cd /-switch-to-permissioned-game-blacklist -make deps +foundryup ``` -### 2. Setup Ledger - -Your Ledger needs to be connected and unlocked. The Ethereum -application needs to be opened on Ledger with the message "Application -is ready". - -### 3. Run relevant script(s) - -#### 3.1 Sign the transaction +### 2. Install Node.js if needed -Op signer: +First, check if you have node installed ```bash -make sign-op +node --version ``` -Base engineer: +If you see a version output from the above command, you can move on. Otherwise, install node ```bash -make sign-base- -``` - -You will see a "Simulation link" from the output. - -Paste this URL in your browser. A prompt may ask you to choose a -project, any project will do. You can create one if necessary. - -Click "Simulate Transaction". - -We will be performing 3 validations and extract the domain hash and message hash to approve on your Ledger: - -1. Validate integrity of the simulation. -2. Validate correctness of the state diff. -3. Validate and extract domain hash and message hash to approve. - -##### 3.2.1 Validate integrity of the simulation. - -Make sure you are on the "Summary" tab of the tenderly simulation, to -validate integrity of the simulation, we need to check the following: - -1. "Network": Check the network is Sepolia or Mainnet. -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 see the derivation path Note above. - -##### 3.2.2. Validate correctness of the state diff. - -Now click on the "State" tab, and refer to the [State Validations](./VALIDATION.md) instructions for the transaction you are signing. -Once complete return to this document to complete the signing. - -##### 3.2.3. Extract the domain hash and the message hash to approve. - -Now that we have verified the transaction performs the right -operation, we need to extract the domain hash and the message hash to -approve. - -Go back to the "Summary" tab, and find the -`GnosisSafe.checkSignatures` (for OP signers) or `Safe.checkSignatures` (for Coinbase signers) call. -This call's `data` parameter contains both the domain hash and the -message hash that will show up in your Ledger. - -It will be a concatenation of `0x1901`, the domain hash, and the -message hash: `0x1901[domain hash][message hash]`. - -Note down this value. You will need to compare it with the ones -displayed on the Ledger screen at signing. - -Once the validations are done, it's time to actually sign the -transaction. - -> [!WARNING] -> This is the most security critical part of the playbook: make sure the -> domain hash and message hash in the following two places match: -> -> 1. On your Ledger screen. -> 2. 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. -> -> There is no need to verify anything printed in the console. There is -> no need to open the new Tenderly simulation link either. - -After verification, sign the transaction. You will see the `Data`, -`Signer` and `Signature` printed in the console. Format should be -something like this: - -```shell -Data: -Signer:
-Signature: -``` - -Double check the signer address is the right one. - -##### 3.2.4 Send the output to Facilitator(s) - -Nothing has occurred onchain - these are offchain signatures which -will be collected by Facilitators for execution. Execution can occur -by anyone once a threshold of signatures are collected, so a -Facilitator will do the final execution for convenience. - -Share the `Data`, `Signer` and `Signature` with the Facilitator, and -congrats, you are done! - -### [For Facilitator ONLY] How to execute - -#### Execute the transaction - -1. IMPORTANT: Ensure op-challenger has been updated before executing. -1. Collect outputs from all participating signers. -1. Concatenate all signatures and export it as the `SIGNATURES` - environment variable, i.e. `export -SIGNATURES="[SIGNATURE1][SIGNATURE2]..."`. -1. Run the `make execute` or `make approve` command as described below to execute the transaction. - -For example, if the quorum is 2 and you get the following outputs: - -```shell -Data: 0xDEADBEEF -Signer: 0xC0FFEE01 -Signature: AAAA +brew install node ``` -```shell -Data: 0xDEADBEEF -Signer: 0xC0FFEE02 -Signature: BBBB -``` - -If on testnet, then you should run: +## Sign Task -Coinbase facilitator: +### 1. Update repo: ```bash -SIGNATURES=AAAABBBB make execute +cd contract-deployments +git pull ``` -If on mainnet, then you should run: - -Optimism facilitator: +### 2. Run the signing tool (NOTE: do not enter the task directory. Run this command from the project's root). ```bash -SIGNATURES=AAAABBBB make approve-op +make sign-task ``` -#### If on mainnet, execute the transaction +### 3. Open the UI at [http://localhost:3000](http://localhost:3000) -Once the signatures have been submitted approving the transaction for all nested Safes run: +### 4. Send signature to facilitator -```bash -make execute -``` +You may now kill the Signer Tool process in your terminal window by running `Ctrl + C`. From e69c6a761b22c367ee66d93a4283fca18c5525f9 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Wed, 3 Dec 2025 17:54:25 -0500 Subject: [PATCH 27/27] fix main readme --- README.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8522ee9e..39d14bd2 100644 --- a/README.md +++ b/README.md @@ -194,13 +194,31 @@ This template is used to pause or un-pause [Base Bridge](https://github.com/base 1. Check in the task when it's ready to sign and request the facilitators to collect signatures from signers. 1. Once executed, check in the records files and mark the task `EXECUTED` in the README. -## Using the Switch to Permissioned Game Retire/Blacklist template +## Using the Switch to Permissioned Game Retire template -This template is used to switch Base to a Permissioned Game. +This template is used to switch Base to a Permissioned Game and retire existing games. 1. Ensure you have followed the instructions above in `setup`. -1. Run `make setup-switch-to-permissioned-game- network=` and go to the folder that was created by this command. +1. Run `make setup-switch-to-permissioned-game-retire network=` and go to the folder that was created by this command. 1. Specify the commit of [Optimism code](https://github.com/ethereum-optimism/optimism) and [Base contracts code](https://github.com/base/contracts) you intend to use in the `.env` file. +1. Set the `L2_DIVERGENCE_BLOCK_NUMBER` to the blocknumber that the chain has diverged at. +1. Run `make deps`. +1. Ensure only the Sepolia or Mainnet variables are in the `.env` file depending on what network this task is for. +1. Build the contracts with `forge build`. +1. Generate the validation file for signers with `make gen-validation`. +1. Check in the task when it's ready to sign and request the facilitators to collect signatures from signers. +1. Once executed, check in the records files and mark the task `EXECUTED` in the README. + +## Using the Switch to Permissioned Game Blacklist template + +This template is used to switch Base to a Permissioned Game and blacklist existing games. + +1. Ensure you have followed the instructions above in `setup`. +1. Run `make setup-switch-to-permissioned-game-blacklist network=` and go to the folder that was created by this command. +1. Specify the commit of [Optimism code](https://github.com/ethereum-optimism/optimism) and [Base contracts code](https://github.com/base/contracts) you intend to use in the `.env` file. +1. Set the `L2_DIVERGENCE_BLOCK_NUMBER` to the blocknumber that the chain has diverged at. +1. The `ADDRESSES_TO_BLACKLIST` can be left blank, in which case the addresses to blacklist will be searched for onchain. This may take some time. Alternatively, +you may run `make find-dispute-games-offchain` which will search for the addresses off-chain and `ADDRESSES_TO_BLACKLIST` can be set to the output. 1. Run `make deps`. 1. Ensure only the Sepolia or Mainnet variables are in the `.env` file depending on what network this task is for. 1. Build the contracts with `forge build`.