Skip to content

Add governance proposal 24: de-whitelist same-address multisig, nominee cleanup, GuardCM allowlist#308

Merged
DavidMinarsch merged 6 commits into
mainfrom
feat/proposal-24-dewhitelist-sameaddr-and-unnominate
Jun 23, 2026
Merged

Add governance proposal 24: de-whitelist same-address multisig, nominee cleanup, GuardCM allowlist#308
DavidMinarsch merged 6 commits into
mainfrom
feat/proposal-24-dewhitelist-sameaddr-and-unnominate

Conversation

@kupermind

Copy link
Copy Markdown
Contributor

Summary

Adds the staging builder, description, Arbitrum cost estimator, and fork tests for GovernorOLAS proposal 24 — a single proposal bundling 41 actions:

  1. De-whitelist GnosisSafeSameAddressMultisig (8) — changeMultisigPermission(adapter, false) on ServiceRegistry (Ethereum) and ServiceRegistryL2 (Gnosis, Polygon, Arbitrum, Optimism, Base, Celo, Mode). Mainnet is a direct Timelock call; each L2 is bridged through its mediator (AMB / FxRoot / Arbitrum Inbox retryable / OP-stack messenger). Removes the same-address multisig adoption path from service deployment.
  2. Un-nominate staking contracts (32) — VoteWeighting.removeNominee(bytes32, uint256) for retired (account, chainId) pairs across Ethereum, Gnosis, Base, Polygon, Optimism, Celo, Arbitrum.
  3. Extend the GuardCM allowlist (1) — setTargetSelectorChainIds(...) adding 19 emergency-pause / drain triples (Dispenser setPauseState, ServiceManager / RegistriesManager pause, per-L2 TargetDispenserL2.pause, plus the Mode drain backfill). All statuses = true.

Bridge encodings mirror the autonolas-governance proposal-11 builder; the GuardCM batch mirrors its Phase-0 setTargetSelectorChainIds. Arbitrum retryable params are SDK-estimated (proposal_15 method: +1000% buffers, value = deposit × 10) and baked concrete, so the staging proposalId is the one that will be submitted.

Fork tests

  • test/Proposal24ForkL1.t.sol — full propose → vote → queue → execute on a mainnet fork through the live GovernorOLAS; asserts the mainnet de-whitelist, all 32 nominee removals, and all 19 GuardCM triples. Arbitrum retryable is executor-funded (Timelock keeps no balance).
  • test/Proposal24ForkL2OpStack.t.sol — Optimism / Base / Celo / Mode mediator-replay → adapter de-whitelisted.
  • test/Proposal24ForkL2Other.t.sol — Gnosis (AMB) / Polygon (FxRoot) / Arbitrum (aliased Timelock) → adapter de-whitelisted.

All 10 pass locally. They self-fork via vm.createSelectFork (public RPC defaults, overridable via *_RPC env). They are not run in CI (CI runs only the Staking / PolySafeCreator forge matches) — run locally with forge test --match-contract Proposal24Fork.

Operational notes

  • Nominee-removal timing: Dispenser.removeNominee reverts within the last week of the ongoing epoch — execute this proposal with > 7 days left in the epoch (epoch length 14 days).
  • Re-run estimate_arb_submission_cost.js right before submission to refresh the baked Arbitrum ARB_* constants against L1 basefee drift.

Notes

  • Staging only — no contracts changed; the builder/tests live under scripts/proposals/ and test/.
  • proposalId = 0xd33102bf0356f624d51130dc7099a7285d3e125bb03687b488c3df66bfd825ba (recomputed if the Arbitrum params are refreshed at submission).

kupermind and others added 6 commits June 19, 2026 16:53
…s multisig, nominee cleanup, GuardCM allowlist)

Adds the staging builder + fork tests for a single GovernorOLAS proposal (41 actions):
- de-whitelist GnosisSafeSameAddressMultisig on ServiceRegistry (L1) / ServiceRegistryL2 (7 L2s) via
  changeMultisigPermission(addr,false) — mainnet direct, L2s bridged through their mediators;
- remove 32 retired staking nominees from VoteWeighting via removeNominee(bytes32,uint256);
- extend the GuardCM allowlist via setTargetSelectorChainIds with 19 emergency-pause/drain triples.

Bridge encodings mirror the autonolas-governance proposal-11 builder; the GuardCM batch mirrors its Phase-0
setTargetSelectorChainIds. Arbitrum retryable params are SDK-estimated (proposal_15 method: +1000% buffers,
value = deposit*10) and baked concrete.

Fork tests (test/Proposal24Fork*.t.sol): full propose->vote->queue->execute on a mainnet fork (asserts the
mainnet de-whitelist, all 32 nominee removals, and all 19 GuardCM triples) plus per-L2 bridge-delivery sims for
Optimism/Base/Celo/Mode (OP-stack) and Gnosis/Polygon/Arbitrum. Not run in CI (CI only runs Staking/PolySafe
forge matches); run locally with forge test --match-contract Proposal24Fork.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
annotate.js decodes the Forge builder's authoritative calldata (calldata.json) into a self-contained,
color-coded HTML breakdown of all 41 entries (de-whitelist / removeNominee / GuardCM setTargetSelectorChainIds,
including the bridged L2 payloads). proposalId in the HTML matches the builder and the L1 fork test
(0xd33102bf...25ba). Mirrors the autonolas-governance proposal-11 annotate.js.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ic address, false positive)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…k test (false positive)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lygon

Polygon has a second same-address adapter, PolySafeSameAddressMultisig
(0xBcb1BAC84B5BcAb350C89c50ADc9064eD15a4485) — the same adopt-an-existing-Safe primitive as
GnosisSafeSameAddressMultisig (identical bytecode/artifact, proxyHash + DEFAULT_DATA_LENGTH=20), currently
whitelisted on the Polygon ServiceRegistryL2. It was missing from the de-whitelist, leaving the same-address
adoption path open on Polygon. (configuration.json sweep confirms this is the only such gap; all 8
GnosisSafeSameAddressMultisig were already covered.)

Both Polygon adapters are now batched as two concatenated tuples in the single FxRoot message
(FxGovernorTunnel.processMessageFromRoot loops over them), so the proposal stays at 41 entries. The Polygon L2
fork test asserts both adapters flip to de-whitelisted. Regenerated description.txt / calldata.json / HTML.
New proposalId 0x0b61f9b79b549a6601b530c83a032cf8fa848170ca8663772f2e5c029d78e39e.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Overfunding msg.value does not change the retryable ticket's gas bid: the ticket uses the explicit
maxFeePerGas argument. The estimator was baking the raw current L2 gas price (~0.02 gwei) instead of the
SDK's buffered p.maxFeePerGas (+1000%), so a rise in Arbitrum L2 gas before execution could leave the
retryable underbid and not auto-redeemed (still manually redeemable, but not the intended behaviour for a
governance action). Now bakes the buffered maxFeePerGas (220_000_000 ~ 0.22 gwei) and refreshes
maxSubmissionCost/value from a fresh estimate; value (deposit*10) already covered the buffered deposit.

estimate_arb_submission_cost.js now uses p.maxFeePerGas (not getGasPrice). Regenerated calldata.json + HTML.
New proposalId 0x73e8480bad6a2e344017aeeb789a356653a82d275cba156c8a889c0d5f1a7f49.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@77ph

77ph commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Independent review — Proposal 24 (de-whitelist + nominee cleanup + GuardCM allowlist)

Reviewed all three bundled actions against current on-chain state and the proposal payload (calldata.json / builder). Verdict: construction is correct and safe to execute; no blocking issues. Checks below.

1. De-whitelist same-address adapters — ✅ complete

Enumerated the whitelisted adopt-existing-Safe multisig implementations directly on-chain via mapMultisigs(address) on each network's ServiceRegistry/ServiceRegistryL2. There are 9 active such entries, and the proposal de-whitelists every one:

Network(s) Adapter on-chain now in proposal
Ethereum, Gnosis, Polygon, Arbitrum, Optimism, Base, Celo, Mode GnosisSafeSameAddressMultisig (per chain) true ×8
Polygon PolySafeSameAddressMultisig true

changeMultisigPermission(address,bool) selector appears 9×; every adapter + target-registry address matches the on-chain set; each call passes false; the Polygon FxRoot message batches both Polygon adapters. Fork tests assert pre(true)→post(false) for all 9; re-ran the Polygon fork locally — PASS (both Polygon adapters flip).

2. Nominee removals (32×) — ✅ sound

  • Encoding: removeNominee(bytes32,uint256) on VoteWeighting (0x9541…c5c1), account = bytes32(uint160(addr)), owner-only (Timelock). Correct.
  • removeNominee reverts NomineeDoesNotExist when mapNomineeIds == 0, i.e. it only succeeds for a currently-active nominee — so a single stale/duplicate entry would revert the entire proposal. Checked all 32 on-chain: every one has mapNomineeIds > 0 → none reverts. (One transient empty RPC read was re-confirmed = 44 on three independent endpoints.)
  • Timing: removal cascades to Dispenser.removeNominee, which reverts in the last week of an epoch — execute with > 7 days left (already noted in the README).
  • Which nominees to retire is a DAO product decision; this review confirms only that each is currently removable.

3. GuardCM allowlist extension (19 triples) — ✅ sound

  • Target = the live GuardCM (0xC0b1…c6B); all 19 statuses = true (additions only).
  • Selectors decode exactly: pause() 0x8456cb59, setPauseState(uint8) 0x63096509, drain() 0x9890220b, drain(address) 0xece53132.
  • All entries are emergency pause / drain across mainnet + 7 L2s (Dispenser setPauseState, ServiceManager / RegistriesManager pause, per-L2 TargetDispenserL2.pause, + the Mode ServiceRegistryL2 / ServiceRegistryTokenUtility drain backfill). No selector beyond pause/drain is added.
  • Target contracts verified present on-chain; sampled triples currently read false on the guard → genuine additions, not duplicates.

Notes (non-blocking)

  • De-whitelist completeness is asserted against the known same-address adapter set; changeMultisigPermission emits no event, so a one-time confirmation that no other adopt-arbitrary implementation is whitelisted outside that set is worthwhile (a MultisigPermissionChanged event would make this auditable going forward).
  • Arbitrum retryable params are baked estimates — re-run the estimator right before submission (already flagged in the proposal).

— audit-claude, 2026-06-22

@DavidMinarsch DavidMinarsch merged commit 1910c23 into main Jun 23, 2026
3 checks passed
@DavidMinarsch DavidMinarsch deleted the feat/proposal-24-dewhitelist-sameaddr-and-unnominate branch June 23, 2026 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants