From cb7535fc65e220c5dcdbf40a1d58ebd8d995b5ea Mon Sep 17 00:00:00 2001 From: Thanh Trinh Date: Tue, 21 Jul 2026 15:18:31 -0400 Subject: [PATCH] feat(CHAIN-4707): add active Zeronet ownership transfer task Co-authored-by: Codex --- Makefile | 7 ++- Multisig.mk | 4 +- active/evm/Makefile | 40 +++++++++++++ active/evm/README.md | 34 +++++++++++ .../FACILITATOR.md | 60 +++++++++++++++++++ .../config/zeronet/.env | 8 +++ .../config/zeronet/README.md | 25 ++++++++ .../config/zeronet/foundry.toml | 20 +++++++ .../config/zeronet/network.env | 9 +++ .../TransferSystemConfigOwnership.s.sol | 48 +++++++++++++++ .../config/zeronet/validations/.gitkeep | 1 + 11 files changed, 252 insertions(+), 4 deletions(-) create mode 100644 active/evm/Makefile create mode 100644 active/evm/README.md create mode 100644 active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/FACILITATOR.md create mode 100644 active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/.env create mode 100644 active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/README.md create mode 100644 active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/foundry.toml create mode 100644 active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/network.env create mode 100644 active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/script/TransferSystemConfigOwnership.s.sol create mode 100644 active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/validations/.gitkeep diff --git a/Makefile b/Makefile index a1556703a..e71f932c9 100644 --- a/Makefile +++ b/Makefile @@ -118,6 +118,7 @@ setup-superchain-config-pause: # Pinned tag for openzeppelin-contracts-upgradeable, installed via clone-oz-upgradeable. OZ_UPGRADEABLE_TAG=v4.7.3 LIB_KECCAK_COMMIT=3b1e7bbb4cc23e9228097cfebe42aedaf3b8f2b9 +PROJECT_DIR ?= $(CURDIR) .PHONY: deps deps: bootstrap-mise install-eip712sign clean-lib forge-deps @@ -128,12 +129,12 @@ install-eip712sign: .PHONY: clean-lib clean-lib: - rm -rf lib + rm -rf $(PROJECT_DIR)/lib .PHONY: forge-deps forge-deps: [ -n "$(BASE_CONTRACTS_COMMIT)" ] || (echo "BASE_CONTRACTS_COMMIT must be set in .env" && exit 1) - $(MISE_EXEC) forge install --no-git github.com/foundry-rs/forge-std@0844d7e1fc5e60d77b68e469bff60265f236c398 \ + cd $(PROJECT_DIR) && $(MISE_EXEC) forge install --no-git github.com/foundry-rs/forge-std@0844d7e1fc5e60d77b68e469bff60265f236c398 \ github.com/Vectorized/solady@502cc1ea718e6fa73b380635ee0868b0740595f0 \ github.com/ethereum-optimism/lib-keccak@$(LIB_KECCAK_COMMIT) \ github.com/base/contracts@$(BASE_CONTRACTS_COMMIT) @@ -141,7 +142,7 @@ forge-deps: ## # Task Signer Tool ## -SIGNER_TOOL_COMMIT=8b50397aa06533e2ccbad1fe8b0694367177d87f +SIGNER_TOOL_COMMIT=566102238bc78fb023f495372d6f80282efa05dd SIGNER_TOOL_PATH=signer-tool .PHONY: checkout-signer-tool diff --git a/Multisig.mk b/Multisig.mk index 6f0cc2817..c3cded746 100644 --- a/Multisig.mk +++ b/Multisig.mk @@ -55,6 +55,8 @@ endef # committed file is portable; the trade-off is that `mise` must be discoverable # on the signer-tool subprocess's PATH (see the bootstrap-mise warning and the # README "Toolchain (mise)" section for the PATH requirement). +VALIDATIONS_DIR ?= $(CURDIR)/validations + define GEN_VALIDATION $(call require_vars,GEN_VALIDATION,RPC_URL LEDGER_ACCOUNT) \ cd $(SIGNER_TOOL_PATH) && \ @@ -63,7 +65,7 @@ $(call require_vars,GEN_VALIDATION,RPC_URL LEDGER_ACCOUNT) \ --workdir $(CURDIR) \ --forge-cmd '$(if $(5),$(5) )mise exec -- forge script --rpc-url $(RPC_URL) $(1) --sig "sign(address[])" "[$(2)]" --sender $(3)' \ --ledger-id $(LEDGER_ACCOUNT) \ - --out $(CURDIR)/validations/$(4) + --out $(VALIDATIONS_DIR)/$(4) endef # ---------- Helpers ---------- diff --git a/active/evm/Makefile b/active/evm/Makefile new file mode 100644 index 000000000..ce550f479 --- /dev/null +++ b/active/evm/Makefile @@ -0,0 +1,40 @@ +include ../../Makefile +include ../../Multisig.mk + +TASK_ID ?= 2026-07-10-transfer-systemconfig-ownership +TASK_NETWORK ?= zeronet +TASK_DIR = tasks/$(TASK_ID) +TASK_CONFIG_DIR = $(TASK_DIR)/config/$(TASK_NETWORK) + +include $(TASK_CONFIG_DIR)/network.env +include $(TASK_CONFIG_DIR)/.env + +export PROXY_ADMIN_OWNER +export INCIDENT_MULTISIG +export SYSTEM_CONFIG + +SIGNER_TOOL_PATH = $(REPO_ROOT)/signer-tool +VALIDATIONS_DIR = $(CURDIR)/$(TASK_CONFIG_DIR)/validations +PROJECT_DIR = $(CURDIR)/$(TASK_CONFIG_DIR) +RPC_URL = $(L1_RPC_URL) +SCRIPT_NAME = --root $(TASK_CONFIG_DIR) $(TASK_CONFIG_DIR)/script/TransferSystemConfigOwnership.s.sol:TransferSystemConfigOwnership + +.PHONY: gen-validation-cb +gen-validation-cb: deps-signer-tool + $(call GEN_VALIDATION,$(SCRIPT_NAME),$(CB_MULTISIG),$(VALIDATION_SENDER),base-signer.json,PROXY_ADMIN_OWNER=$(PROXY_ADMIN_OWNER) INCIDENT_MULTISIG=$(INCIDENT_MULTISIG) SYSTEM_CONFIG=$(SYSTEM_CONFIG)) + +.PHONY: gen-validation-sc +gen-validation-sc: deps-signer-tool + $(call GEN_VALIDATION,$(SCRIPT_NAME),$(BASE_SECURITY_COUNCIL),$(VALIDATION_SENDER),security-council-signer.json,PROXY_ADMIN_OWNER=$(PROXY_ADMIN_OWNER) INCIDENT_MULTISIG=$(INCIDENT_MULTISIG) SYSTEM_CONFIG=$(SYSTEM_CONFIG)) + +.PHONY: approve-cb +approve-cb: + $(call MULTISIG_APPROVE,$(CB_MULTISIG),$(SIGNATURES)) + +.PHONY: approve-sc +approve-sc: + $(call MULTISIG_APPROVE,$(BASE_SECURITY_COUNCIL),$(SIGNATURES)) + +.PHONY: execute +execute: + $(call MULTISIG_EXECUTE,0x) diff --git a/active/evm/README.md b/active/evm/README.md new file mode 100644 index 000000000..24f20e60d --- /dev/null +++ b/active/evm/README.md @@ -0,0 +1,34 @@ +# Active EVM Tasks + +Active EVM tasks live under `tasks//`, with per-network task files under `config//`. + +```text +active/evm/ +├── Makefile +└── tasks/ + └── 2026-07-10-transfer-systemconfig-ownership/ + ├── FACILITATOR.md + ├── config/ + │ └── zeronet/ + │ ├── .env + │ ├── foundry.toml + │ ├── network.env + │ ├── README.md + │ ├── lib/ + │ ├── script/ + │ └── validations/ + └── signatures/ + └── zeronet/ +``` + +Run task commands from `active/evm`: + +```bash +cd active/evm +make deps +make gen-validation-cb +make gen-validation-sc +``` + +The signer tool runs from `active/evm` and discovers date-prefixed task directories containing `config//validations`. +Task-origin signatures, when required, live under `tasks//signatures//`. diff --git a/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/FACILITATOR.md b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/FACILITATOR.md new file mode 100644 index 000000000..b9dcf98d6 --- /dev/null +++ b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/FACILITATOR.md @@ -0,0 +1,60 @@ +# Facilitator Guide + +Guide for facilitators managing the Zeronet `SystemConfig` owner transfer. + +## 1. Generate validation files + +Run this after any change to the task config or script: + +```bash +cd contract-deployments/active/evm +make deps +make gen-validation-cb +make gen-validation-sc +``` + +This produces: + +- `tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/validations/base-signer.json` +- `tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/validations/security-council-signer.json` + +Check that both `cmd` fields use: + +```text +--sender 0x821Ff2A3fB66B008fA668B40Eca9d3535B246575 +``` + +Because this is a Zeronet task, set this field at the JSON root in both validation files: + +```json +"skipTaskOriginValidation": true +``` + +## 2. Collect signatures + +Ask signers to run `make sign-task` from the repository root and select **Transfer Zeronet `SystemConfig` Owner**. + +## 3. Approve and execute + +From `active/evm`, execute the Coinbase and Security Council approvals: + +```bash +SIGNATURES=AAABBBCCC make approve-cb +SIGNATURES=AAABBBCCC make approve-sc +make execute +``` + +## 4. Verify onchain + +```bash +cast call 0x0a111C7980152bDe41D71f48e2E1d8184f5f6187 "owner()(address)" \ + --rpc-url https://c3-chainproxy-eth-hoodi-full-dev.cbhq.net +``` + +Expected result: + +```text +0x856611ed7e07d83243b15e93f6321f2df6865852 +``` + +Then update the task status to `EXECUTED` with the transaction link and commit the execution records. diff --git a/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/.env b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/.env new file mode 100644 index 000000000..af9c1414e --- /dev/null +++ b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/.env @@ -0,0 +1,8 @@ +BASE_CONTRACTS_COMMIT=be7c7a642e430fa64b04b63203839f8c81f48466 + +PROXY_ADMIN_OWNER=0x3d59999977e0896ee1f8783bB8251DF16fb483E9 +INCIDENT_MULTISIG=0x856611ed7e07d83243b15e93f6321f2df6865852 +SYSTEM_CONFIG=0x0a111C7980152bDe41D71f48e2E1d8184f5f6187 +VALIDATION_SENDER=0x821Ff2A3fB66B008fA668B40Eca9d3535B246575 + +RECORD_STATE_DIFF=true diff --git a/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/README.md b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/README.md new file mode 100644 index 000000000..8d0bcd8f1 --- /dev/null +++ b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/README.md @@ -0,0 +1,25 @@ +# Transfer Zeronet `SystemConfig` Owner + +Status: READY TO SIGN + +## Description + +Transfer the Zeronet `SystemConfig` owner from the proxy admin owner Safe to the incident multisig. + +## Addresses + +| Role | Address | +| -- | -- | +| `SystemConfig` | `0x0a111C7980152bDe41D71f48e2E1d8184f5f6187` | +| Current owner | `0x3d59999977e0896ee1f8783bB8251DF16fb483E9` | +| New owner | `0x856611ed7e07d83243b15e93f6321f2df6865852` | + +## Sign + +From the repository root: + +```bash +make sign-task +``` + +Open [http://localhost:3000](http://localhost:3000), select this Zeronet task, sign, and send the signature to the facilitator. diff --git a/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/foundry.toml b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/foundry.toml new file mode 100644 index 000000000..4af5624c8 --- /dev/null +++ b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/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 = 999999 +solc_version = "0.8.15" +via-ir = false +evm_version = "shanghai" +remappings = [ + '@base-contracts/=lib/contracts/', + '@lib-keccak/=lib/lib-keccak/contracts/lib/', + '@solady/=lib/solady/src/', + 'forge-std/=lib/forge-std/src/', +] + +[lint] +lint_on_build = false diff --git a/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/network.env b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/network.env new file mode 100644 index 000000000..5561e5281 --- /dev/null +++ b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/network.env @@ -0,0 +1,9 @@ +NETWORK=zeronet +L1_RPC_URL=https://c3-chainproxy-eth-hoodi-full-dev.cbhq.net +L2_RPC_URL=https://base-zeronet-reth-mempool-k8s-donotuse.cbhq.net:8545 +L1_CHAIN_ID=560048 +L2_CHAIN_ID=763360 +LEDGER_ACCOUNT=1 + +BASE_SECURITY_COUNCIL=0xC4c0aD998B5DfA4CF4B298970F21b9015a5eE7bA +CB_MULTISIG=0x856611ed7e07d83243b15e93f6321f2df6865852 diff --git a/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/script/TransferSystemConfigOwnership.s.sol b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/script/TransferSystemConfigOwnership.s.sol new file mode 100644 index 000000000..b722fb674 --- /dev/null +++ b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/script/TransferSystemConfigOwnership.s.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import {Vm} from "forge-std/Vm.sol"; + +import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; +import {MultisigScript} from "@base-contracts/script/universal/MultisigScript.sol"; +import {Enum} from "@base-contracts/script/universal/IGnosisSafe.sol"; + +interface IOwnable { + function owner() external view returns (address); + function transferOwnership(address newOwner) external; +} + +contract TransferSystemConfigOwnership is MultisigScript { + address internal immutable PROXY_ADMIN_OWNER; + address internal immutable INCIDENT_MULTISIG; + address internal immutable SYSTEM_CONFIG; + + constructor() { + PROXY_ADMIN_OWNER = vm.envAddress("PROXY_ADMIN_OWNER"); + INCIDENT_MULTISIG = vm.envAddress("INCIDENT_MULTISIG"); + SYSTEM_CONFIG = vm.envAddress("SYSTEM_CONFIG"); + + require(IOwnable(SYSTEM_CONFIG).owner() == PROXY_ADMIN_OWNER, "current owner mismatch"); + } + + function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal view override { + require(IOwnable(SYSTEM_CONFIG).owner() == INCIDENT_MULTISIG, "new owner mismatch"); + } + + function _buildCalls() internal view override returns (Call[] memory) { + Call[] memory calls = new Call[](1); + + calls[0] = Call({ + operation: Enum.Operation.Call, + target: SYSTEM_CONFIG, + data: abi.encodeCall(IOwnable.transferOwnership, (INCIDENT_MULTISIG)), + value: 0 + }); + + return calls; + } + + function _ownerSafe() internal view override returns (address) { + return PROXY_ADMIN_OWNER; + } +} diff --git a/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/validations/.gitkeep b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/validations/.gitkeep new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/active/evm/tasks/2026-07-10-transfer-systemconfig-ownership/config/zeronet/validations/.gitkeep @@ -0,0 +1 @@ +