diff --git a/Makefile b/Makefile index 5361c82c..eac85c8f 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,7 @@ forge-deps: ## # Task Signer Tool ## -SIGNER_TOOL_COMMIT=1fc76441a1cde3581c224023adfa79b8cfdb2fa4 +SIGNER_TOOL_COMMIT=8c19f7ca258de19a8eca2b3e64abdfd8b2d30e7c SIGNER_TOOL_PATH=signer-tool .PHONY: checkout-signer-tool diff --git a/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/FACILITATOR.md b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/FACILITATOR.md new file mode 100644 index 00000000..ff9f2f31 --- /dev/null +++ b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/FACILITATOR.md @@ -0,0 +1,50 @@ +# Facilitator Guide + +Guide for updating the Base Sepolia `BalanceTracker` profit wallet. + +## 1. Install dependencies and verify current state + +Run every task command with the network selected explicitly: + +```bash +cd active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet +make TASK_NETWORK=sepolia deps +make TASK_NETWORK=sepolia verify-current +``` + +## 2. Deploy the implementation + +Connect the Ledger account for `PROXY_ADMIN`, then run: + +```bash +make TASK_NETWORK=sepolia deploy +``` + +This deploys a `BalanceTracker` implementation whose immutable `PROFIT_WALLET` +is the company wallet used on mainnet. Review and commit: + +- `config/sepolia/addresses.json` +- the deployment record under `records/DeployBalanceTracker.s.sol/11155111/` + +## 3. Execute the upgrade + +The existing proxy admin is an EOA, not a Safe, so this task does not generate a +signer validation file or collect multisig approvals. The connected +`PROXY_ADMIN` Ledger executes the upgrade directly: + +```bash +make TASK_NETWORK=sepolia upgrade +``` + +The script verifies that the proxy implementation and profit wallet change +while both existing system addresses and target balances remain unchanged. + +## 4. Verify and archive + +```bash +make TASK_NETWORK=sepolia verify +``` + +Set `Status: [EXECUTED]()` in +`config/sepolia/README.md`, commit the upgrade record, then run +`make archive-task` from the repository root. diff --git a/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/Makefile b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/Makefile new file mode 100644 index 00000000..69bd4ffc --- /dev/null +++ b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/Makefile @@ -0,0 +1,75 @@ +include ../../../../Makefile +include $(REPO_ROOT)/Multisig.mk + +ifneq ($(origin TASK_NETWORK),command line) +$(error TASK_NETWORK must be set on the command line, for example: make TASK_NETWORK=sepolia ) +endif +ifneq ($(TASK_NETWORK),sepolia) +$(error unsupported TASK_NETWORK: $(TASK_NETWORK)) +endif + +PROJECT_DIR := $(abspath ../..) + +include $(REPO_ROOT)/config/$(TASK_NETWORK).env +include config/$(TASK_NETWORK)/.env + +ADDRESSES_JSON := $(CURDIR)/config/$(TASK_NETWORK)/addresses.json +export FOUNDRY_BROADCAST := $(CURDIR)/records +DEPLOY_SCRIPT := tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/script/DeployBalanceTracker.s.sol:DeployBalanceTracker +UPGRADE_SCRIPT := tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/script/UpgradeBalanceTracker.s.sol:UpgradeBalanceTracker +TASK_ENV := BALANCE_TRACKER=$(BALANCE_TRACKER) \ + CURRENT_PROFIT_WALLET=$(CURRENT_PROFIT_WALLET) \ + NEW_PROFIT_WALLET=$(NEW_PROFIT_WALLET) \ + ADDRESSES_JSON=$(ADDRESSES_JSON) +UPGRADE_ENV := $(TASK_ENV) \ + PROXY_ADMIN=$(PROXY_ADMIN) \ + SYSTEM_ADDRESS_0=$(SYSTEM_ADDRESS_0) \ + SYSTEM_ADDRESS_1=$(SYSTEM_ADDRESS_1) \ + TARGET_BALANCE_0=$(TARGET_BALANCE_0) \ + TARGET_BALANCE_1=$(TARGET_BALANCE_1) + +.PHONY: deps +deps: task-extra-deps + +.PHONY: task-extra-deps +task-extra-deps: + cd $(PROJECT_DIR)/lib/contracts && $(MISE_EXEC) forge install --no-git \ + OpenZeppelin/openzeppelin-contracts-upgradeable@$(OZ_UPGRADEABLE_TAG) + +.PHONY: validate-ledger-admin +validate-ledger-admin: + @test "$$($(MISE_EXEC) cast wallet address --ledger --mnemonic-derivation-path $(LEDGER_HD_PATH))" = "$(PROXY_ADMIN)" || \ + (echo "connected Ledger account is not PROXY_ADMIN" && exit 1) + +.PHONY: validate-deployment +validate-deployment: + @test -f "$(ADDRESSES_JSON)" || (echo "run make TASK_NETWORK=$(TASK_NETWORK) deploy first" && exit 1) + @jq -e '.balanceTrackerImplementation' "$(ADDRESSES_JSON)" >/dev/null + +.PHONY: deploy +deploy: validate-ledger-admin + cd $(PROJECT_DIR) && $(TASK_ENV) $(MISE_EXEC) forge script --rpc-url $(L1_RPC_URL) $(DEPLOY_SCRIPT) \ + --ledger --hd-paths $(LEDGER_HD_PATH) --sender $(PROXY_ADMIN) --broadcast -vvvv + +.PHONY: upgrade +upgrade: validate-ledger-admin validate-deployment + cd $(PROJECT_DIR) && $(UPGRADE_ENV) $(MISE_EXEC) forge script --rpc-url $(L1_RPC_URL) $(UPGRADE_SCRIPT) \ + --ledger --hd-paths $(LEDGER_HD_PATH) --sender $(PROXY_ADMIN) --broadcast -vvvv + +.PHONY: verify-current +verify-current: + @test "$$($(MISE_EXEC) cast call $(BALANCE_TRACKER) 'PROFIT_WALLET()(address)' --rpc-url $(L1_RPC_URL))" = \ + "$(CURRENT_PROFIT_WALLET)" + +.PHONY: verify +verify: validate-deployment + @test "$$($(MISE_EXEC) cast call $(BALANCE_TRACKER) 'PROFIT_WALLET()(address)' --rpc-url $(L1_RPC_URL))" = \ + "$(NEW_PROFIT_WALLET)" + @test "$$($(MISE_EXEC) cast call $(BALANCE_TRACKER) 'systemAddresses(uint256)(address)' 0 --rpc-url $(L1_RPC_URL))" = \ + "$(SYSTEM_ADDRESS_0)" + @test "$$($(MISE_EXEC) cast call $(BALANCE_TRACKER) 'systemAddresses(uint256)(address)' 1 --rpc-url $(L1_RPC_URL))" = \ + "$(SYSTEM_ADDRESS_1)" + @test "$$($(MISE_EXEC) cast call $(BALANCE_TRACKER) 'targetBalances(uint256)(uint256)' 0 --rpc-url $(L1_RPC_URL) | cut -d' ' -f1)" = \ + "$(TARGET_BALANCE_0)" + @test "$$($(MISE_EXEC) cast call $(BALANCE_TRACKER) 'targetBalances(uint256)(uint256)' 1 --rpc-url $(L1_RPC_URL) | cut -d' ' -f1)" = \ + "$(TARGET_BALANCE_1)" diff --git a/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/config/sepolia/.env b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/config/sepolia/.env new file mode 100644 index 00000000..72c97de6 --- /dev/null +++ b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/config/sepolia/.env @@ -0,0 +1,16 @@ +# https://github.com/base/contracts/commit/b8e2246fd0f8ce342c574e2a783f865ea82d38d4 +BASE_CONTRACTS_COMMIT=b8e2246fd0f8ce342c574e2a783f865ea82d38d4 +RECORD_STATE_DIFF=true + +# Existing Base Sepolia BalanceTracker proxy admin. +PROXY_ADMIN=0x4672425C27A942bB27e7b9709c1b21ab89a3cA13 + +# Replace the current personal profit wallet with the company wallet used on mainnet. +CURRENT_PROFIT_WALLET=0x5A822ea15764a6090b86B1EABfFc051cEC99AFE9 +NEW_PROFIT_WALLET=0xEc8103eb573150cB92f8AF612e0072843db2295F + +# Existing BalanceTracker configuration that must remain unchanged. +SYSTEM_ADDRESS_0=0x037637067c1DbE6d2430616d8f54Cb774Daa5999 +TARGET_BALANCE_0=200000000000000000000 +SYSTEM_ADDRESS_1=0xfc56E7272EEBBBA5bC6c544e159483C4a38f8bA3 +TARGET_BALANCE_1=1000000000000000000000 diff --git a/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/config/sepolia/README.md b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/config/sepolia/README.md new file mode 100644 index 00000000..1247ce95 --- /dev/null +++ b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/config/sepolia/README.md @@ -0,0 +1,17 @@ +# Update Sepolia `BalanceTracker` Profit Wallet + +Status: READY TO SIGN + +## Description + +Replace the Base Sepolia `BalanceTracker` profit wallet +`0x5A822ea15764a6090b86B1EABfFc051cEC99AFE9` with the company-owned wallet +used on mainnet, `0xEc8103eb573150cB92f8AF612e0072843db2295F`. + +The existing system addresses and target balances remain unchanged. + +## Execution + +The `BalanceTracker` proxy is administered by an EOA, so no multisig signature +is required. The facilitator executes the upgrade with the existing proxy admin +Ledger. diff --git a/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/script/DeployBalanceTracker.s.sol b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/script/DeployBalanceTracker.s.sol new file mode 100644 index 00000000..fd1ea400 --- /dev/null +++ b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/script/DeployBalanceTracker.s.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import {Script} from "forge-std/Script.sol"; + +import {BalanceTracker} from "@base-contracts/src/L1/BalanceTracker.sol"; + +contract DeployBalanceTracker is Script { + address payable internal immutable BALANCE_TRACKER; + address payable internal immutable CURRENT_PROFIT_WALLET; + address payable internal immutable NEW_PROFIT_WALLET; + + constructor() { + BALANCE_TRACKER = payable(vm.envAddress("BALANCE_TRACKER")); + CURRENT_PROFIT_WALLET = payable(vm.envAddress("CURRENT_PROFIT_WALLET")); + NEW_PROFIT_WALLET = payable(vm.envAddress("NEW_PROFIT_WALLET")); + + require( + BalanceTracker(BALANCE_TRACKER).PROFIT_WALLET() == CURRENT_PROFIT_WALLET, "current profit wallet mismatch" + ); + } + + function run() external { + vm.broadcast(); + BalanceTracker implementation = new BalanceTracker(NEW_PROFIT_WALLET); + + require(implementation.PROFIT_WALLET() == NEW_PROFIT_WALLET, "new profit wallet mismatch"); + + string memory json = vm.serializeAddress("deployment", "balanceTrackerImplementation", address(implementation)); + vm.writeJson(json, vm.envString("ADDRESSES_JSON")); + } +} diff --git a/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/script/UpgradeBalanceTracker.s.sol b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/script/UpgradeBalanceTracker.s.sol new file mode 100644 index 00000000..5f5f4f87 --- /dev/null +++ b/active/evm/tasks/2026-08-25-update-sepolia-balance-tracker-profit-wallet/script/UpgradeBalanceTracker.s.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import {Script} from "forge-std/Script.sol"; + +import {BalanceTracker} from "@base-contracts/src/L1/BalanceTracker.sol"; +import {Proxy} from "@base-contracts/src/universal/Proxy.sol"; + +contract UpgradeBalanceTracker is Script { + address internal immutable PROXY_ADMIN; + address payable internal immutable BALANCE_TRACKER; + address payable internal immutable CURRENT_PROFIT_WALLET; + address payable internal immutable NEW_PROFIT_WALLET; + address internal immutable NEW_IMPLEMENTATION; + address payable internal immutable SYSTEM_ADDRESS_0; + address payable internal immutable SYSTEM_ADDRESS_1; + uint256 internal immutable TARGET_BALANCE_0; + uint256 internal immutable TARGET_BALANCE_1; + + constructor() { + PROXY_ADMIN = vm.envAddress("PROXY_ADMIN"); + BALANCE_TRACKER = payable(vm.envAddress("BALANCE_TRACKER")); + CURRENT_PROFIT_WALLET = payable(vm.envAddress("CURRENT_PROFIT_WALLET")); + NEW_PROFIT_WALLET = payable(vm.envAddress("NEW_PROFIT_WALLET")); + SYSTEM_ADDRESS_0 = payable(vm.envAddress("SYSTEM_ADDRESS_0")); + SYSTEM_ADDRESS_1 = payable(vm.envAddress("SYSTEM_ADDRESS_1")); + TARGET_BALANCE_0 = vm.envUint("TARGET_BALANCE_0"); + TARGET_BALANCE_1 = vm.envUint("TARGET_BALANCE_1"); + + string memory json = vm.readFile(vm.envString("ADDRESSES_JSON")); + NEW_IMPLEMENTATION = vm.parseJsonAddress(json, ".balanceTrackerImplementation"); + + require(NEW_IMPLEMENTATION.code.length > 0, "implementation has no code"); + require( + BalanceTracker(payable(NEW_IMPLEMENTATION)).PROFIT_WALLET() == NEW_PROFIT_WALLET, + "implementation profit wallet mismatch" + ); + vm.prank(PROXY_ADMIN); + require(Proxy(BALANCE_TRACKER).admin() == PROXY_ADMIN, "proxy admin mismatch"); + _checkState(CURRENT_PROFIT_WALLET); + } + + function run() external { + vm.broadcast(PROXY_ADMIN); + Proxy(BALANCE_TRACKER).upgradeTo(NEW_IMPLEMENTATION); + + vm.prank(PROXY_ADMIN); + require(Proxy(BALANCE_TRACKER).implementation() == NEW_IMPLEMENTATION, "implementation mismatch"); + _checkState(NEW_PROFIT_WALLET); + } + + function _checkState(address expectedProfitWallet) internal view { + BalanceTracker balanceTracker = BalanceTracker(BALANCE_TRACKER); + + require(balanceTracker.PROFIT_WALLET() == expectedProfitWallet, "profit wallet mismatch"); + require(balanceTracker.systemAddresses(0) == SYSTEM_ADDRESS_0, "system address 0 mismatch"); + require(balanceTracker.systemAddresses(1) == SYSTEM_ADDRESS_1, "system address 1 mismatch"); + require(balanceTracker.targetBalances(0) == TARGET_BALANCE_0, "target balance 0 mismatch"); + require(balanceTracker.targetBalances(1) == TARGET_BALANCE_1, "target balance 1 mismatch"); + } +}