Governance ZIP Changelog

Governance ZIP — Changelog & Implementation Notes

Companion post for DRAFT Governance ZIP v2 for Comment (kept separate to stay within forum post limits): the pre-merge implementation checklist, then the changelog (newest first).

Required pre-merge updates (Reference Implementation checklist)

  1. Fork-height activation for both heights; nothing conditioned on an on-chain spork object.

  2. Bridge/Liquidity admin changes removed from the governance PR — the migration is its own PR.

  3. Pillar-owner-only proposing; open-action cap.

  4. Propose-time allowlist, emergency-flag, and zero-address validation.

  5. Legacy spork-path removal at the fork.

  6. Deposit escrow: exact amount, no setter, refund/donate settlement.

  7. Type-1E: absolute conditions, immediate execution, early-reject, expiry.

  8. Per-round ActivePillarSnapshot, never read live.

  9. Type-2 direct write: codec not dispatchable; round-0 immediate, ratchet delayed; ExecutableAt; no send on approval.

  10. networkAdministrator with fallback; deterministic GetNetworkAdministrator().

  11. Automated readiness signaling (§11.3a) with measurement tooling.

  12. GetPillarVotes, GetNetworkAdministrator, Type-2 MultisigRecordInfo inlining.

  13. No Multisig-contract changes beyond its own ZIP’s activation gate; independent review confirms nothing else rides along.

  14. Migration PR: implement the §6.3 disposition table with table-driven tests for every row (incl. Fund/BurnZnn re-gating, redefined Bridge Emergency, Liquidity Emergency unresolvable, guardian-less surviving callers); deprecated-field assertions (never read post-height, zeroed on first write, pre-height bytes decode identically); plasma check in ReceiveBlock; Halt accepts TSS from a non-admin; end-to-end threshold-signed admin call; GovernanceAddress retained for replay only, no other non-test consumer.

  15. Open as upstream PRs.

Changelog

v2.2 — hard-fork activation for the Multisig; readiness criterion specified (2026-07-27).

  • The Multisig ZIP activates by hard fork (MultisigForkHeight), not by MultisigSpork. Both contracts are now enabled by hard fork; the heights are independent, schedulable in either order, and MAY coincide — a single shared-height fork is the preferred deployment when release timing allows. This removes the governance-first activation ordering, the two-Type-1-action spork dance for the multisig, and the extra placeholder-replacement release it required. It costs one small change to PR #72 (the activation gate swaps from the dormant spork check to a fork-height check — see Multisig ZIP v1.2). The two-action implemented-spork release protocol is retained in §6.1 as the normative procedure for all future governance-activated sporks, where the consensus-safety lesson still applies.

  • Readiness signaling fully specified (§11.3a/3b). Pillars signal via automated once-per-epoch zero-amount blocks from the producer address carrying a feature marker — consensus-neutral under pre-fork rules, attributable via the Pillar registry, measurable by anyone. The momentum Version field is explicitly ruled out (the verifier pins it exactly pre-fork). The below-threshold path is now explicit: after a suggested 90-day campaign, the height MAY be scheduled anyway with ≥90 days’ lead — the criterion is pacing guidance, never an adoption veto.

  • Editorial: comparative references to the superseded v1 draft were moved out of the specification body and into this changelog. For the record, relative to v1: the GovernanceForkHeight == MultisigForkHeight hard coupling was dropped (now optional rather than required); the requirement that the multisig’s ChangeSignerSet accept GovernanceContract as a caller was withdrawn as infeasible and weaker (Type-2 became SetNetworkAdministrator); the propose-time rejection of Destination == MultisigContract became moot when MultisigContract left the destination set; and the Type-2 payload changed from a raw signer list (no on-chain object to inspect) to an address with a queryable live policy.

v2.1 — adversarial-review fixes (2026-07-26). Addresses the findings of the independent adversarial audit (2026-07-26-codex-adversarial-review.md):

  • CRITICAL-1: the MultisigSpork activation sequence now specifies two Type-1 actions with a mandatory real-SporkId binary release between CreateSpork and ActivateSpork (§2); collapsing them terminates every upgraded node at enforcement (os.Exit(2) on an active unimplemented spork).

  • CRITICAL-2: Liquidity Fund and BurnZnn — gated today on the unreachable legacy spork signer and therefore already stranded — are re-gated to networkAdmin in the migration (§6.3).

  • CRITICAL-3: Emergency semantics defined: Bridge Emergency is retained, redefined as networkAdmin-gated TSS-clear + halt (no administrator zeroing, no guardian predicate); Liquidity Emergency is removed as redundant with SetIsHalted (§6.3).

  • CRITICAL-4: persisted composite storage (bridgeInfo, liquidityInfo, securityInfo) keeps its ABI codec unchanged; deprecated fields are ignored by consensus logic and zeroed on first post-height write — “removal” is from authorization/dispatch/RPC, never from the storage encoding (§6.3).

  • HIGH-2: the guardian-count predicate is removed from CheckSecurityInitialized post-height so surviving callers (SetTokenTuple, SetAllowKeygen, ChangeTssECDSAPubKey, Emergency) don’t brick; AdministratorDelay is explicitly deprecated (all consumers removed).

  • HIGH-3: the claim that a round-0 Type-2 vote “outruns” the TSS time challenge is corrected to a race with mandatory monitoring — the challenge floor is one epoch (~24h) and the protocol guarantees no vote latency.

  • MEDIUM-1/2/3: Type-2 approval-vs-effect semantics unambiguous (internal write in whichever ExecuteAction performs it; ratchet rounds separate approval and effect by 72h by design); “three heights” corrected to two hard forks plus a spork, stray MultisigForkHeight reference removed; runtime vs scheduling prerequisites distinguished in §2.

  • LOW-1/3: threshold-floor figures stated per track (Type-2 ~21.8%, Type-1 ~26.4%, asymptotic); proposal input validation fully specified (30/240-byte limits, exact URL regex).

  • §6.3 now carries the complete privileged-method disposition table (Bridge 16 admin-aware methods, Liquidity 10), replacing the enumerate-it-later requirement.

v2 — networkAdmin (2026-07-26). Incorporates the multisig-implementation review and the plasma/GovernanceAddress finding:

  • Type-2 redefined: SetNetworkAdministrator on GovernanceContract, replacing ChangeSignerSet on MultisigContract. The v1 action was infeasible against the actual Multisig implementation (go-zenon#72): the method is ChangePolicy, it operates only on its own sender, the account verifier hard-rejects blocks lacking threshold signatures (which a contract-send cannot carry), and Locked is monotonic. It was also the weaker design: rotation recovers only from compromised signers, while repointing recovers from a compromised, locked, or abandoned admin. Type-2 now writes governance storage directly (no contract-send), exempting it from the non-atomic-execution caveat. Thresholds, ratchet schedule, periods, and the 72h ratchet-round delay are unchanged.

  • The Multisig contract is untouched. v1’s requirement that it accept GovernanceContract as an authorized caller is withdrawn. The multisig manages only its own signing policy; its power as admin derives entirely from other contracts honoring its address.

  • Single networkAdmin replaces all per-contract admin state. New networkAdministrator governance variable with InitialNetworkAdministrator fallback (hardcoded to the community Multisig, published and verified per the new §11.5 gate). At a new third height, Bridge and Liquidity drop Administrator, guardians, ChangeAdministrator/ProposeAdministrator/NominateGuardians, and InitialBridgeAdministrator; admin-gated methods check GetNetworkAdministrator(). Fund-equivalent time challenges (ChangeTssECDSAPubKey) and HaltMethod’s dual admin/TSS path are retained. Bridge/Liquidity RPC keeps the administrator field, populated from governance.

  • Plasma parameters become admin-set, resolving the GovernanceAddress trap. ZIP-3’s SetVariables was gated on a placeholder user address whose planned repoint to the governance contract would have made the setter permanently unreachable (no action type can target PlasmaContract). Instead, plasma joins the migration: SetVariables checks GetNetworkAdministrator() (in ReceiveBlock — send-side validation has no state access), the placeholder is retired, and the current single-keyholder backdoor closes. Boundary made explicit: the governance contract sets networkAdmin and nothing else; it has no path, direct or indirect, to plasma variables.

  • Same-height coupling removed. Merge order between the two implementations is unconstrained; the Multisig ZIP activates via MultisigSpork (expected: Type-1 actions per the §2 release protocol, the first production use of this machinery; genesis pre-activation on new networks), and AdminMigrationForkHeight requires governance active, MultisigSpork active, and the §11.5 publication gate (address, (creatorPubKey, nonce) for offline recomputation, signer identities, locked == false, pending == null). The v1 propose-time rejection of Destination == MultisigContract is obsolete — it is no longer a destination at all.

  • No callable setter. SetNetworkAdministrator exists only as the Type-2 payload codec and is absent from the dispatch table; the vote is the only write path. Explicitly not the Bridge ChangeAdministrator pattern, under which a captured admin could transfer authority without a vote.

  • Type-2 target validation: reject only the zero address (ErrInvalidNetworkAdministrator); no IsMultisigAddress requirement — the type check is false assurance (a 2-of-2 held by one person passes) and forecloses future embedded-contract admins. In its place, a hard RPC requirement: Type-2 action views MUST inline the proposed address’s MultisigRecordInfo, defending the new pending-policy bait-and-switch and locked-target considerations. New GetNetworkAdministrator RPC with the same inlining.

  • New security material: malicious admin repointing (replacing malicious signer rotation), admin control of plasma parameters, an emergency admin-replacement runbook (creator-must-be-a-signer constraint, round-0 fast path, exposure-window bounds), migration completeness, and the orchestrator administrator-mode retirement documented under Backward Compatibility.

  • New constants AdminMigrationForkHeight, InitialNetworkAdministrator, ErrInvalidNetworkAdministrator; the GovernanceForkHeight == MultisigForkHeight constraint is removed.

v1 revisions (retained for history). Incorporates community review: the Multisig dependency is pinned (shared fork height, normative interface); a Type-1E emergency spork track is added (7 days, Yes from >66% of all active Pillars); the Type-2 ratchet floor rises >25% → >33% with a 72h delay on ratchet-round rotations; NoDecision now refunds the deposit; per-round Pillar snapshots, re-vote semantics, a 2-open-actions cap, and a measurable fork-height readiness signal are specified; and signer-set legitimacy is assigned to the Pillar vote rather than a nomination filter.

v1 — fixed deposit. The proposal deposit is a fixed protocol constant of 100 ZNN for all action types. SetProposalDeposit, the [10, 1,000] ZNN bounds, the Type-2 pricing exemption, and the GetProposalDeposit RPC are removed. Rationale: Pillar-only proposing plus the 2-open-actions cap already bound spam, so the adjustment lever added attack surface (deposit-as-censorship, and the only Multisig-to-governance authorization edge) without benefit; the deposit can now change only by Pillar-approved protocol upgrade.