Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -128,20 +129,20 @@ 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)

##
# Task Signer Tool
##
SIGNER_TOOL_COMMIT=8b50397aa06533e2ccbad1fe8b0694367177d87f
SIGNER_TOOL_COMMIT=566102238bc78fb023f495372d6f80282efa05dd
SIGNER_TOOL_PATH=signer-tool

.PHONY: checkout-signer-tool
Expand Down
4 changes: 3 additions & 1 deletion Multisig.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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) && \
Expand All @@ -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 ----------
Expand Down
40 changes: 40 additions & 0 deletions active/evm/Makefile
Original file line number Diff line number Diff line change
@@ -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)
34 changes: 34 additions & 0 deletions active/evm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Active EVM Tasks

Active EVM tasks live under `tasks/<task-id>/`, with per-network task files under `config/<network>/`.

```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/<network>/validations`.
Task-origin signatures, when required, live under `tasks/<task-id>/signatures/<network>/`.
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading