DRAFT Governance ZIP v2 for Comment
| Field | Description |
|---|---|
| zip | ZIP:-XXXX (to be assigned by sponsoring Pillar) |
| title | Pillar-Governed Embedded Governance Contract (Spork- and Admin-Scoped) |
| author | 0x3639 |
| status | Draft |
| type | Hard Fork |
| acceptance | Community review; forks proceed at their heights regardless of adoption (§11). |
| activation | Two hard-fork heights (TBD), scheduled per §11; the companion Multisig ZIP activates at its own height — either order, or the same height (§2). |
| created | 2026-05-31 |
| updated | 2026-07-28 |
| requires | Multisig Embedded Contract ZIP (go-zenon#72) — for AdminMigrationForkHeight only (§2). |
| license | GNU General Public License v3.0 |
| link | TBD — upstream PR to zenon-network/go-zenon |
| branch | codex/governance-ratchet (81c2474), pending updates below |
| original | sumoshi21, go-zenon PR #47 |
| changelog | Separate post: Governance ZIP — Changelog & Implementation Notes |
Abstract
This ZIP adds GovernanceContract, letting Pillars propose, vote on, and execute exactly two classes of action: (1) creating and activating Sporks — a deliberate standard track or a supermajority emergency track; and (2) setting networkAdmin, a single address holding all operational admin authority. Proposals require a Pillar’s registered owner address and a refundable 100 ZNN deposit: returned on approval or expiry, donated to Accelerator-Z on rejection.
networkAdmin replaces every existing operational admin identity. At AdminMigrationForkHeight, Bridge and Liquidity drop their per-contract Administrator state and guardians, Plasma’s SetVariables stops honoring the GovernanceAddress placeholder key, and all three authorize admin methods against networkAdmin, read from governance storage. The intended admin is the community Multisig of the companion ZIP — which this ZIP does not modify; governance stores its address as an opaque value.
At GovernanceForkHeight, the legacy spork-signer and CommunitySporkAddress paths are removed: GovernanceContract becomes the sole spork authority (background).
Motivation
Sporks are consensus changes warranting deliberate Pillar votes; bridge halts, keygens, token pairs, liquidity parameters, and plasma tuning need responses in hours — and testnet experience (the PR #47 lineage) showed Pillars will not vote on routine operations. The split:
- Governance (this ZIP): spork creation/activation, plus one escape hatch — setting
networkAdmin— so Pillars retain authority over who holds operational control, and nothing else. - Operations (
networkAdmin): all admin methods on Bridge, Liquidity, Plasma, and future contracts authorize against one address that can act in hours and holds no embedded-contract funds. The intended holder is the community Multisig, whose address derives from its creation event and is stable across signer rotation.
The urgency is concrete: the legacy spork signer’s whereabouts are unknown — the network has no reachable spork-activation authority. Hence hard-fork activation (§11), removal of the defunct paths (§6), and the Type-1E emergency track (§4).
A second motivation surfaced in review: dynamic plasma (ZIP-3) gates plasma.SetVariables on types.GovernanceAddress — a placeholder user address with a TODO to repoint it at the governance contract. Completing the TODO would permanently strand the setter (PlasmaContract is on no action allowlist); leaving it lets one keyholder change live consensus parameters. This ZIP resolves both: the placeholder is retired and plasma becomes networkAdmin-set (§6.3).
Specification
1. New Embedded Contract
z1qxemdeddedxg0vernancexxxxxxxxxxxklyh23 // GovernanceContract
Added to types.EmbeddedContracts; callable only from GovernanceForkHeight. The types.GovernanceAddress placeholder is not repointed by this ZIP; it is retired at AdminMigrationForkHeight (§6.3).
2. Activation by Hard Fork
Constants: GovernanceForkHeight, AdminMigrationForkHeight (both TBD, set per §11)
Reference: MultisigForkHeight (companion ZIP; independent, MAY equal GovernanceForkHeight)
Enforcement: IsGovernanceForkEnforced() / IsAdminMigrationForkEnforced() at each height
Prerequisites: runtime none (forks proceed regardless of adoption); scheduling per
§11.3, plus for AdminMigrationForkHeight both prior heights and §11.5
Spork-based activation is unavailable (it would require the unreachable legacy signer); implementations MUST NOT condition enforcement on any on-chain spork object.
Both contracts activate by hard fork, at independent heights, in either order. The dependency graph is acyclic: the Multisig depends on nothing, governance depends on nothing (an address is opaque to it), and only the migration adds a read-only edge. Consequences:
- Merge order of the two implementations is unconstrained.
- The two heights MAY be scheduled in either order — or as the same height, preferred when one release carries both: one coordination event, no window where one contract exists without the other. The coupling is a convenience, never a dependency.
AdminMigrationForkHeightMUST NOT be scheduled until both heights pass and the §11.5 gate is satisfied.- Between the two heights
networkAdminis inert — nothing reads it — yet a Type-2 vote there is legal and persists, so the initial value can be corrected before it takes effect. - Legacy Bridge/Liquidity administrators and the plasma
GovernanceAddressgate remain authoritative untilAdminMigrationForkHeight.
3. Contract ABI
function ProposeAction(
string name,
string description,
string url,
address destination,
string data,
bool emergency // valid only when destination == SporkContract (§4)
)
function ExecuteAction(hash id)
function VoteByName(hash id, string name, uint8 vote)
function VoteByProdAddress(hash id, uint8 vote)
// Type-2 payload codec ONLY — NOT dispatchable; no callable setter (§6.2)
function SetNetworkAdministrator(address administrator)
variable action(owner, name, description, url, destination, data,
creationTimestamp, type, round, currentVoteId, roundStartTimestamp,
activePillarSnapshot, // active-Pillar count fixed at round start
approvalTimestamp, // drives Type-2 ratchet delay (§5)
status, executed, deposit)
variable networkAdministrator(address administrator)
vote = 0 is Yes, vote = 1 is No.
4. Action Types, Rounds, and Thresholds
Type derives from destination plus the emergency flag; SporkContract and GovernanceContract are the only destinations (ErrForbiddenDestination); emergency is valid only with SporkContract (ErrInvalidEmergencyFlag).
| Type | Destination | Allowed methods | Execution | Track |
|---|---|---|---|---|
| 1 | SporkContract |
CreateSpork, ActivateSpork |
Emits contract-send | Standard; ratcheted rounds |
| 1E | SporkContract |
CreateSpork, ActivateSpork |
Emits contract-send | Emergency; one 7-day round, Yes from >66% of all active Pillars |
| 2 | GovernanceContract |
SetNetworkAdministrator |
Direct storage write (§5) | Admin repointing; ratcheted rounds |
Type-1E counts abstentions and non-votes against approval, so it is strictly harder than Type-1 at any realistic turnout — the flag buys speed only when support is overwhelming. Type-2 repoints networkAdmin: governance stops pointing at an admin rather than reaching into it. The decoded selector is validated at propose time; a Type-2 payload decoding to the zero address is rejected (ErrInvalidNetworkAdministrator); any other well-formed address is accepted — the vote is the filter, informed by §8 inlining.
An undecided initial round enters a bounded ratchet — each round lowers participation but raises the directional (Yes+No, excluding abstentions) bar:
| Type | Round | Active-Pillar threshold | Directional threshold | Period |
|---|---|---|---|---|
| 1 | 0 | >66% | >50% | 45 days |
| 1 | 1 | >55% | >55% | 21 days |
| 1 | 2 | >45% | >60% | 21 days |
| 1 | 3 | >40% floor | >66% | 21 days |
| 2 | 0 | >50% | >50% | 30 days |
| 2 | 1 | >40% | >60% | 14 days |
| 2 | 2 | >33% floor | >66% | 14 days |
activePillars is the round-start activePillarSnapshot — registry churn cannot move a live round’s thresholds. A round approves when:
(yes + no) * 100 > activePillars * activePillarThreshold
yes * 100 > (yes + no) * directionalThreshold
and rejects when participation holds and no * 100 > (yes + no) * directionalThreshold.
Type-1E approves the moment yes*100 > activePillars*66 and rejects the moment no*100 >= activePillars*34 (approval impossible). A lapsed 7-day window expires as NoDecision; re-propose as Type-1.
Abstentions count toward VoteBreakdown.Total but toward neither threshold. The last vote before round close counts; votes do not carry across rounds (fresh tally and vote id; old votes stay queryable).
5. Proposal Lifecycle
Propose. ProposeAction MUST come from the registered owner address of an active Pillar (ErrNotPillarOwner), carrying exactly ProposalDeposit (100 ZNN); at most 2 open actions per owner (ErrTooManyOpenActions). Validation: Name 1–30 bytes; Description 1–240 bytes; Url non-empty matching ^([Hh][Tt][Tt][Pp][Ss]?://)?[a-zA-Z0-9]{2,60}\.[a-zA-Z]{1,6}([-a-zA-Z0-9()@:%_+.~#?&/=]{0,100})$; Data valid base64; destination/method on the §4 allowlist; emergency false unless spork-bound; Type-2 address non-zero. Url SHOULD point to the action’s public deliberation — the thread specifying the change, and for Type-2 the post publishing (creatorPubKey, nonce) and signer identities — and is informational only, never consensus-verified (the binding Type-2 verification is §8’s policy inlining). The contract assigns Id = sendBlock.Hash, records round-0 state and ActivePillarSnapshot, escrows the deposit, and opens a VotableHash on the existing pillar-voting machinery.
Vote. One standing vote per Pillar per round via VoteByName/VoteByProdAddress, against CurrentVoteId (differs from Id after round 0).
Finalize / Execute. Any address MAY call ExecuteAction(id) (execution is uncensorable):
- Nonexistent id →
ErrDataNonExistent; terminal actions return silently. - Thresholds use the round’s recorded snapshot, never the live count; abstentions excluded.
- Type-1 cannot finalize before its period elapses; Type-1E and Type-2 finalize the moment thresholds cross.
- On approval:
Status = Approved,ApprovalTimestampset, deposit refunded. Type-1/1E emit the contract-send immediately. Type-2 emits nothing:ExecuteActionwritesnetworkAdmindirectly — immediately in round 0; for ratchet rounds, only at/afterApprovalTimestamp + Type2ExecutionDelay(72h), the pending repoint visible meanwhile. - On rejection:
Status = Rejected, deposit donated to Accelerator-Z, no send. - Round elapsed undecided: next round opens (fresh
CurrentVoteIdand snapshot); final round undecided →NoDecision, deposit refunded.
Type-2 has no external destination — the write happens in whichever ExecuteAction performs it, so there is no approved-but-destination-rejected state. Ratchet rounds separate approval and effect by 72h by design, never by a fallible send.
6. Authorization Changes to Existing Contracts
6.1 Spork contract — at GovernanceForkHeight
CreateSpork/ActivateSpork become callable only by GovernanceContract; the legacy spork-signer and CommunitySporkAddress paths are removed.
Future implemented sporks (normative). Activation through governance takes two Type-1 actions with a mandatory binary release between them: (1) CreateSpork — the send-block hash is the real SporkId; (2) a point release replaces the shipped placeholder with that ID, operators upgrade; (3) ActivateSpork; enforcement after SporkMinHeightDelay. Skipping step 2 is fatal: an active spork absent from ImplementedSporksMap terminates the node.
6.2 Governance storage
variable networkAdministrator(address administrator)
This variable holds the single admin role referred to as networkAdmin throughout this ZIP and its companion — one role, one storage location; the longer form is only the code identifier (matching the existing …Administrator naming convention). Unset reads fall back to constants.InitialNetworkAdministrator (§9), mirroring the InitialBridgeAdministrator pattern. SetNetworkAdministrator exists only as the Type-2 payload codec — absent from the dispatch table; the sole write path is vote execution. Deliberately not the Bridge ChangeAdministrator pattern, under which a captured admin could hand authority onward voteless.
GetNetworkAdministrator() types.Address is added to AccountVmContext, reading governance storage via the momentum store pinned for the executing block — deterministic, and already idiomatic for cross-contract reads.
6.3 Bridge, Liquidity, and Plasma — at AdminMigrationForkHeight
Every admin-gated check becomes sendBlock.Address != context.GetNetworkAdministrator() → ErrPermissionDenied. Complete privileged-method disposition (normative — this enumeration is the migration’s work item):
| Contract | Method | Today | At AdminMigrationForkHeight |
|---|---|---|---|
| Bridge | SetNetwork, RemoveNetwork, SetNetworkMetadata, SetTokenPair, RemoveTokenPair, Unhalt, SetOrchestratorInfo, SetBridgeMetadata, RevokeUnwrapRequest |
admin | networkAdmin (SoftDelay challenges retained) |
| Bridge | Halt |
admin or valid TSS signature | networkAdmin or TSS (dual path unchanged) |
| Bridge | ChangeTssECDSAPubKey |
admin + SoftDelay, or TSS path |
networkAdmin + same challenge, or TSS path |
| Bridge | SetAllowKeygen |
admin + guardian predicate | networkAdmin (guardian predicate removed) |
| Bridge | Emergency |
admin + guardians; zeroes admin, clears TSS keys, halts | redefined: networkAdmin-gated; clears TSS keys and halts; no admin zeroing or guardian predicate |
| Liquidity | Fund, BurnZnn |
*types.SporkAddress — the unreachable legacy signer; stranded today |
networkAdmin |
| Liquidity | SetTokenTuple |
admin + guardians + SoftDelay |
networkAdmin + SoftDelay |
| Liquidity | SetIsHalted, UnlockLiquidityStakeEntries, SetAdditionalReward |
admin (+ SoftDelay where present) |
networkAdmin, challenges retained |
| Liquidity | Emergency |
admin + guardians; zeroes admin, halts | removed — post-migration it would equal SetIsHalted(true) |
| both | ChangeAdministrator, NominateGuardians, ProposeAdministrator |
admin / guardians | removed |
Fund/BurnZnnare a rescue: gated on the lost spork signer, they are unreachable today and forever without re-gating.- Guardian predicate:
CheckSecurityInitialized’s guardian-count requirement is removed post-height; surviving callers proceed on the delay fields alone — otherwise guardian removal would brick them withErrSecurityNotInitialized. - Delays:
SoftDelaysurvives;AdministratorDelayis deprecated (all consumers removed). Removed constants:InitialBridgeAdministrator,MinGuardians. - Storage schema (consensus-critical): the removed fields live inside persisted composite ABI variables, so the persisted codecs are unchanged — “removal” applies to authorization, dispatch, and RPC, never the encoding. Deprecated fields MUST be ignored post-height and SHOULD be zeroed on first write; conformance asserts no authorization path reads them, not key absence.
Plasma. SetVariables moves from the GovernanceAddress gate to the same networkAdmin check — in ReceiveBlock, since send-side validation has no state access (the Bridge does likewise). An unauthorized send is accepted and rejected at receive, matching Bridge semantics; the in-code parameter bounds are unchanged. GovernanceAddress survives only for pre-height replay — retiring today’s placeholder-key backdoor over live consensus parameters.
The boundary. Governance sets networkAdmin and nothing else. It cannot set plasma variables directly (its only send destination is SporkContract) or indirectly (plasma authorizes the sender, a role governance never holds). Parameters belong to the admin; governance’s sole lever is deciding who the admin is.
RPC compatibility. Bridge/Liquidity RPC responses keep their administrator field, populated from GetNetworkAdministrator() — no shape break for wallets, explorers, or the orchestrator.
6.4 Multisig contract — no changes
The companion Multisig contract is unmodified and has no governance-caller path — none could be added without redesign: ChangePolicy operates only on its own sender, the verifier rejects blocks without valid threshold signatures (a contract-send has none), and Locked is monotonic. Governance never reaches into the multisig; it only points at it. Minimums: (1) no networkAdmin method holds direct custody of embedded-contract funds; (2) fund-equivalent methods (ChangeTssECDSAPubKey) retain their timelocks; (3) initial-signer criteria MUST be objective, published, free of delegation-status exclusions; the initial admin address is published and verified per §11.5.
7. Plasma and Fees
ProposeAction: EmbeddedWDoubleWithdraw; ExecuteAction: EmbeddedSimple; votes inherit pillar-voting pricing. The deposit is a constant, not a fee: refunded on Approved/NoDecision, donated to AZ on Rejected.
8. RPC
Namespace embedded.governance: GetActionById, GetAllActions, GetPillarVotes, and GetNetworkAdministrator() -> { administrator, multisig } — the current admin with the address’s MultisigRecordInfo (threshold, signers, locked, pending, pendingHeight) inlined, or null if not a multisig.
Action adds computed fields (Expired, Round, Status, CurrentVoteId, thresholds, VotingPeriod, ExecutableAt, Votes) and — Type-2 only, a security requirement — ProposedAdministrator inlining the proposed address’s MultisigRecordInfo: what voters are delegating to sits in the action view itself, defending the bait-and-switch and locked-target traps.
IsGovernanceForkEnforced(), IsAdminMigrationForkEnforced(), and GetNetworkAdministrator() are added to AccountVmContext.
9. Constants Introduced
Type1Action / Type2Action / Type1EAction = uint8(1) / uint8(2) / uint8(3)
ActionStatusVoting/Approved/Rejected/NoDecision = uint8(0..3)
Type1ActionActivePillarThresholds = []uint32{66, 55, 45, 40}
Type1ActionDirectionalThresholds = []uint32{50, 55, 60, 66}
Type1ActionVotingPeriods = []int64{45, 21, 21, 21} // * PhaseTimeUnit
Type2ActionActivePillarThresholds = []uint32{50, 40, 33}
Type2ActionDirectionalThresholds = []uint32{50, 60, 66}
Type2ActionVotingPeriods = []int64{30, 14, 14} // * PhaseTimeUnit
Type1EPillarYesThreshold = uint32(66) // absolute, vs all active Pillars
Type1EVotingPeriod = int64(7 * PhaseTimeUnit)
Type2ExecutionDelay = int64(72 * 60 * 60) // ratchet rounds only
MaxOpenActionsPerPillar = uint8(2)
GovernanceForkHeight / AdminMigrationForkHeight = uint64(TBD)
InitialNetworkAdministrator = "z1...TBD" // community Multisig, per §11.5
ProposalDeposit = 100 * g.Zexp; GovernanceActionDataMaxLength = MaxDataLength
New errors: ErrUnkownActionType, ErrInvalidActionRound, ErrForbiddenDestination, ErrForbiddenMethod, ErrNotPillarOwner, ErrInvalidEmergencyFlag, ErrTooManyOpenActions, ErrInvalidNetworkAdministrator. MultisigForkHeight is defined by the companion ZIP; the heights MAY coincide (§2).
10. Fork Classification
A Hard Fork at each height: non-upgraded nodes stop following the canonical (upgraded) chain. No adoption threshold exists at either height.
11. Activation
1. Both ZIPs finalize independently; heights are scheduled via the process below, in either order or as one shared height (preferred, §2).
2. Implementations merge; a release ships with readiness signaling enabled but no height set.
3. Readiness criterion. When ≥66% of active Pillars have signaled over a sustained window (suggested: 7 consecutive days), a point release sets the height at least 60 days of momentums ahead.
3a. How a Pillar signals (normative). The upgraded node signals automatically: once per epoch while producing for Pillar P, it broadcasts a zero-amount block from P’s registered producer address whose Data carries a protocol marker plus the feature id (governance-fork / multisig-fork; one block MAY carry both) — an ordinary transaction valid under pre-fork rules. (The momentum Version field cannot serve: the verifier pins it exactly pre-fork.) Signals are attributable via the Pillar registry, automatic, and measurable by anyone; a dashboard SHOULD track the trailing share.
3b. If the threshold is not reached. The criterion is scheduling guidance — not an adoption veto, which would recreate paralysis-by-absence. If signaling stalls after a sustained campaign (suggested: 90 days), the height MAY be scheduled anyway with longer lead (≥90 days of momentums) and unambiguous notice. The fork proceeds regardless (item 4).
3c. The chain never evaluates the threshold (normative). Signal blocks are measurement, not consensus input: no rule reads them; no on-chain condition triggers a height. The chain is: signals → human judgment → point release with a compiled height constant → nodes enforce it. A hard fork cannot be chain-triggered (old binaries lack the new rules); BIP9-style self-activation is rejected as an adoption veto encoded in consensus.
4. Each fork proceeds at its height regardless of adoption. Legacy nodes halt and re-sync on the new znnd.
5. Community Multisig publication gate — AdminMigrationForkHeight only. InitialNetworkAdministrator compiles into that release, so the community Multisig MUST first exist on-chain and be publicly verified: the address; the (creatorPubKey, nonce) pair for offline recomputation; threshold and signer list mapped to nominated identities; locked == false, pending == null at a stated height via getPolicy.
Rationale
Why sporks plus a single admin pointer? Sporks warrant deliberate votes; operations need hour-level response Pillars won’t reliably provide. Governance keeps one operational lever — who is admin — the sole operational question that is a legitimacy question.
Why does set-admin live in governance, not the Multisig contract? Two independent recovery paths: compromised-but-operable signers rotate themselves via ChangePolicy (no vote, hours); a captured, Locked, or abandoned multisig is escaped by one Type-2 vote. A rotation-based design has only the first path, is unimplementable (a contract-send cannot carry threshold signatures; Locked is permanent), and leaves a locked admin recoverable only by hard fork. Repointing ignores the incumbent’s state, is more verifiable, and keeps the graph acyclic.
Why is a multisig a drop-in admin? Its address derives from the creation event, not the policy — rotation never changes it; the pointer is set once.
Why admin-set plasma parameters? Allowlisting PlasmaContract would add a second operational surface inside governance, and tuning needs operational tempo, not 30-day votes. The admin turns the dials within in-code bounds; Pillars control who holds the dials — bounds-limited, recoverable by repoint-then-restore, strictly better than today’s placeholder keyholder or a frozen parameter set.
Why reject only the zero address for Type-2? An IsMultisigAddress check is false assurance — one person with two keypairs mints a passing 2-of-2 — and it forecloses a future embedded-timelock admin. The vote is the filter, informed by §8 inlining.
Why no callable setter? A ChangeAdministrator-style method is invoked by the current admin — a captured admin could hand authority onward without a vote.
Why Pillar-only proposing? The owner address binds proposals to registered stake; anyone else lobbies a Pillar. Deposit plus cap make spam cost capital.
Why hard fork, no adoption threshold, full legacy removal? The inability to activate sporks is the problem; an adoption gate hands a veto to inaction; a retained legacy path is an unrotatable weakest key.
Why an emergency track? The sole spork path must not be only slow. Type-1E’s absolute >66% means silence blocks it, and being strictly harder than Type-1, the flag enables no threshold-shopping.
Why a fixed 100 ZNN deposit, refunded on NoDecision? Skin in the game, not a fee: a convincing proposal costs nothing; rejected deposits fund AZ. No setter — spam is structurally bounded and a lever is a censorship vector; changing the amount takes a Type-1 upgrade. NoDecision refunds because a proposer cannot compel turnout.
Why these thresholds? Sporks start at 66% with a deliberation window; repointing at 50% with immediate round-0 execution, because replacement may be an emergency. Final-round floors: asymptotically >21.8% assent for Type-2 (>33% × >66%), >26.4% for Type-1 (>40% × >66%); ratchet repoints hold 72h so quiet capture is contestable.
Other choices. Rejected: a combined contract; an operational action class; security councils; proposer-specified types; unbounded decay; vote carryover; per-contract admin variables; seeding admin from the live Bridge administrator; failure-case fallback branches.
Backward Compatibility
Before each height, behaviour is byte-identical to today; from it, non-upgraded nodes halt and must upgrade and re-sync. Enforcement comes solely from the release binary; signaling informs scheduling only. Chain-split risk is accepted and mitigated per §11.
Unchanged: address state, token issuance, block formats, and the AZ, Pillar, Sentinel, Stake, HTLC, and Token contracts. The Spork contract changes per §6.1; Bridge/Liquidity/Plasma change per §6.3 (removed methods become unresolvable; storage codecs unchanged, deprecated fields ignored). The Multisig contract is unchanged.
Orchestrator (off-chain). It gates “administrator mode” on the admin equalling its own producer address — impossible for a multisig, so the mode goes permanently inactive post-migration; admin-initiated halt becomes a manual M-of-N action while the TSS halt path stays automatic. Document for operators; retire the code path.
Reference Implementation
Original: go-zenon PR #47 by sumoshi21. Branch: codex/governance-ratchet (81c2474). Required pre-merge updates (each with tests): The 15-item pre-merge update checklist (fork-height activation, Type-2 direct-write semantics, migration disposition tests, readiness signaling, and RPC inlining, each with tests) is maintained in the companion post: Governance ZIP — Changelog & Implementation Notes.
Security Considerations
- Narrow attack surface. Governance touches no Bridge/Liquidity/Plasma/Token/Multisig state. A captured vote at worst creates a spork (still needing matching binaries) or repoints
networkAdmin— visible from propose time. - Sole spork authority. A contract defect could stall upgrades; mitigated by battle-tested voting machinery, tests, and hard fork as last resort.
- Emergency-track abuse. The absolute threshold cannot pass quietly; the 7-day window and early-reject give the No side a veto.
- Malicious admin repointing. A >50% round-0 coalition could install a hostile admin: it holds no funds and no un-timelocked fund-equivalents; the repoint is visible; the same path repoints back; the floor and 72h delay bound low-turnout capture.
- Bait-and-switch / locked target. A clean
Activepolicy can hide aPendingrotation maturing post-vote; aLockedmultisig can never rotate again — why §8 inlining ofpending/lockedis mandatory. A locked admin stays escapable by repoint. - Admin control of plasma parameters. Bounds-limited, recoverable by repoint-then-restore, strictly narrower than today’s placeholder-keyholder exposure.
- Emergency admin replacement. One of the intended new signers submits
CreateMultisig(the creator must be among the initial signers; creation is immediate), publishes(creatorPubKey, nonce), and a Type-2 proposal repoints — round-0 executes instantly; ratchet rounds wait 72h. During the window: plasma is bounds-clamped; a maliciousHaltis reversed post-repoint;ChangeTssECDSAPubKeysits behind its time challenge — a race, not a guarantee (it completes no earlier thanSoftDelay, min. ~24h, after its visible start; the protocol guarantees no vote latency). Monitoring MUST surface challenge starts — a hostile challenge triggers the emergency vote. If epoch-level Pillar responsiveness cannot be assumed, raise the TSS-change delay floor first. - Hard-fork coordination risk. No adoption threshold means chain-split risk — deliberate; heights are scheduled only per §11 with long lead and public tracking.
- Proposer gating. Owner-only proposing concentrates agenda-setting in accountable identities; in-flight actions survive registry churn; the cap bounds spam.
- Deposit as censorship lever — eliminated. A constant with no setter; changing it takes a Pillar-approved upgrade.
- Registry churn / late-round capture. Round-start snapshots freeze thresholds; floors, rising bars, fresh vote ids, the 72h delay, and terminal
NoDecisionbound capture. - Replay / idle execution / storage.
Id = sendBlock.Hashbinds actions to the chain; stalled execution cannot block governance; expired actions are not pruned (a follow-up ZIP MAY). - Non-atomic target execution — Type-1/1E only.
Approvedis set before the destination processes the send; a rejection leaves the action terminal. Type-2 is exempt: its write is internal and atomic with whicheverExecuteActionperforms it. - Migration completeness. A missed admin-gated method is an invisible authority hole — hence §6.3’s enumeration and item-14 tests.
Changelog
Maintained in the companion post — Governance ZIP — Changelog & Implementation Notes (v2.2 current).
Copyright
This ZIP is licensed under the GNU General Public License v3.0.