# DRAFT Governance ZIP for Comment

**URL:** https://forum.hypercore.one/t/draft-governance-zip-for-comment/932
**Category:** ZIPs
**Created:** [June 15, 2026, 1:38am UTC](https://forum.hypercore.one/t/draft-governance-zip-for-comment/932 "2026-06-15T01:38:37Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![0x3639](https://forum.hypercore.one/user_avatar/forum.hypercore.one/0x3639/32/33_2.png) [@0x3639](https://forum.hypercore.one/u/0x3639)
#### Post date: [June 15, 2026, 1:38am UTC](https://forum.hypercore.one/t/draft-governance-zip-for-comment/932/1 "2026-06-15T01:38:37Z")

</div>

| Field | Description |
| --- | --- |
| zip | ZIP:-XXXX _(to be assigned by sponsoring Pillar)_ |
| title | Pillar-Governed Embedded Governance Contract |
| author | 0x3639 |
| status | Draft |
| type | Soft Fork (Spork-gated) |
| acceptance | **Complete** — Governance spork created on-chain on 2025-05-01 at momentum 10,231,257. |
| activation | Path A: legacy spork-signer activates the spork. Path B fallback: \>2/3 of active Pillars upgrade to a release that enforces activation at a fixed height (TBD). |
| created | 2026-05-31 |
| license | GNU General Public License v3.0 |
| link | TBD — upstream PR to `zenon-network/go-zenon` |
| branch | [GitHub - 0x3639/go-zenon at codex/governance-ratchet · GitHub](https://github.com/0x3639/go-zenon/tree/codex/governance-ratchet) (`81c2474`) |
| original | sumoshi21, [governance v1 by sumoshi21 · Pull Request #47 · zenon-network/go-zenon · GitHub](https://github.com/zenon-network/go-zenon/pull/47) |

* * *

## Abstract

This ZIP adds `GovernanceContract`, an embedded contract that lets active Pillars propose, vote on, and execute actions that create/activate Sporks or call administrative methods on Spork, Bridge, and Liquidity. Activation is gated by `GovernanceSpork`, created on-chain on 2025-05-01 at momentum 10,231,257. The contract becomes a parallel authorized caller beside the current legacy administrators, which remain active during transition. This ZIP is authored by 0x3639 and improves on sumoshi21’s [go-zenon PR #47](https://github.com/zenon-network/go-zenon/pull/47) with a low-turnout ratchet, Type-1 deliberation window, clarified execution semantics, and additional tests. Reference branch: [0x3639/go-zenon@codex/governance-ratchet](https://github.com/0x3639/go-zenon/tree/codex/governance-ratchet), commit `81c2474`.

## Motivation

Several embedded contracts still rely on privileged hardcoded administrator paths:

- The Spork contract currently restricts `CreateSpork` and `ActivateSpork` to the legacy spork-signer address, with a separate time-bounded `CommunitySporkAddress` path already present in code.
- The Bridge contract restricts ~14 sensitive methods (`SetNetwork`, `Halt`, `ChangeTssECDSAPubKey`, `ChangeAdministrator`, `NominateGuardians`, …) to a single administrator.
- The Liquidity contract restricts `Fund`, `BurnZnn`, `SetTokenTuple`, `SetIsHalted`, and similar methods to either the spork address or a single administrator.

This model conflicts with progressive decentralization and can block community-driven protocol work. This ZIP introduces a Pillar-governed contract authorized to call these privileged methods. Any address may propose an action, Pillars vote, and any address may execute if the vote passes. Existing administrators remain as parallel authorities during transition.

## Specification

### 1. New Embedded Contract

A new embedded contract is added at address:

```auto
z1qxemdeddedxg0vernancexxxxxxxxxxxklyh23 // GovernanceContract

```

The address is added to `common/types.EmbeddedContracts` and is callable only after the activation of `GovernanceSpork`.

### 2. Activation Spork

A new spork has been created on the Network of Momentum:

```auto
Spork name: Governance Contract
Spork ID: 3dce423d7bc10d2409e598e33811c9c9e79eff178f94adc571aeef30e8bc9b1d
Create tx hash: 3dce423d7bc10d2409e598e33811c9c9e79eff178f94adc571aeef30e8bc9b1d
Created by: z1qqvwzz2xq7q5gwk6uhcddgrpxlfcyzc8rsu82s (authorized spork-signer)
Sent to: z1qxemdeddedxsp0rkxxxxxxxxxxxxxxxx956u48 (Spork contract)
Momentum height: 10,231,257
Timestamp: 2025-05-01 13:12:50 UTC
Status: Created — pending activation

```

This is the canonical `GovernanceSpork` referenced throughout this ZIP. PR #47 used a placeholder ID (`ddd43466…`, marked `// todo change it` in source); the ratchet branch already replaces it with `3dce423d7bc10d2409e598e33811c9c9e79eff178f94adc571aeef30e8bc9b1d` in `common/types/spork.go`.

Prior to `GovernanceSpork` enforcement, `GovernanceContract` does not appear in the embedded-contracts map and any call to it is rejected. After enforcement, `GetEmbeddedMethod` resolves to the governance-aware map, which includes all post-HTLC embedded contracts plus `GovernanceContract`.

### 3. Contract ABI

```auto
function ProposeAction(
    string name,
    string description,
    string url,
    address destination,
    string data
)

function ExecuteAction(hash id)

function VoteByName(hash id, string name, uint8 vote)
function VoteByProdAddress(hash id, uint8 vote)

variable action(
    address owner,
    string name,
    string description,
    string url,
    address destination,
    string data,
    int64 creationTimestamp,
    uint8 type,
    uint8 round,
    hash currentVoteId,
    int64 roundStartTimestamp,
    uint8 status,
    bool executed
)

```

`vote = 0` indicates Yes, `vote = 1` indicates No (consistent with the existing `definition.VoteYes` / `definition.VoteNo` constants used by the Accelerator-Z and Pillar contracts).

### 4. Action Types, Rounds, and Thresholds

Two action types are defined, distinguished automatically by the proposal’s `destination`:

| Type | Destination | Initial active-Pillar decision threshold | Initial directional-majority threshold | Initial voting period |
| --- | --- | --- | --- | --- |
| 1 | `SporkContract` | \>66% of active Pillars | \>50% Yes or No among Yes+No votes | `45 * PhaseTimeUnit` |
| 2 | Any other contract | \>50% of active Pillars | \>50% Yes or No among Yes+No votes | `30 * PhaseTimeUnit` |

If the initial round ends without enough active-Pillar votes to approve or reject the action, the action enters a bounded low-turnout ratchet. Each ratchet round lowers the number of active Pillars required to make a decision, but raises the percentage of directional votes (`Yes + No`, excluding abstentions) required for either side to win. This preserves the high initial hurdle while allowing governance to progress when turnout is low but the participating Pillars are strongly aligned.

| Type | Round | Active-Pillar threshold | Directional threshold | Voting 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% | \>55% | 14 days |
| 2 | 2 | \>33% | \>60% | 14 days |
| 2 | 3 | \>25% floor | \>66% | 14 days |

A round approves when:

```auto
(yes + no) * 100 > activePillars * activePillarThreshold
yes * 100 > (yes + no) * directionalThreshold

```

A round rejects when:

```auto
(yes + no) * 100 > activePillars * activePillarThreshold
no * 100 > (yes + no) * directionalThreshold

```

Abstentions count toward `VoteBreakdown.Total` for transparency, but they do not count toward the active-Pillar threshold, do not count as directional votes, and do not help either side cross the directional threshold. For decision purposes, abstaining is therefore equivalent to not voting; its value is audit visibility. If a round ends without approval or rejection, votes for that round are closed and a new round starts with a fresh vote id. Old votes remain queryable for audit history, but they do not carry into the next round.

After the final round, if neither side satisfies both thresholds, the action expires as `NoDecision` and cannot be executed. Proposers cannot specify the type directly; it is derived from `destination` at propose time. `destination == TokenContract` is explicitly forbidden.

### 5. Proposal Lifecycle

**Propose.** Any address may call `ProposeAction` on `GovernanceContract`, sending `ProjectCreationAmount` of `ZnnTokenStandard` (the same anti-spam fee used by Accelerator-Z projects). The contract:

1. Validates `Name` length is within `[1, ProjectNameLengthMax]`, `Description` within `[1, ProjectDescriptionLengthMax]`, `Url` matches the existing project-URL regex, `Data` is valid base64, `Destination != TokenContract`, and the decoded action targets an allowed governance method.
2. Assigns `Id = sendBlock.Hash`, sets `Owner = sendBlock.Address`, records `CreationTimestamp` from the frontier momentum, sets `Type` per §4, initializes `Round = 0`, `CurrentVoteId = Id`, `RoundStartTimestamp = CreationTimestamp`, `Status = Voting`, and writes an `ActionVariable` to contract storage under key `0x00 || id`.
3. Writes a `VotableHash{Id: CurrentVoteId}` so the existing pillar-voting machinery (`VoteByName`, `VoteByProdAddress`) can be reused for the current round.

**Vote.** Each active Pillar MAY cast one vote per action round via `VoteByName` (pillar name + producing-address signature) or `VoteByProdAddress`. The `id` argument to the vote method MUST be the action’s `CurrentVoteId`; after round 0, this is no longer the same value as the action’s `Id`. Votes accumulate against `CurrentVoteId` in the shared `VoteBreakdown` storage. Re-votes within the same round follow the existing pillar-voting semantics. When a new round starts, `CurrentVoteId` changes and prior-round votes stop counting toward the active decision.

**Finalize / Execute.** Any address MAY call `ExecuteAction(id)`. The contract:

1. Returns `ErrDataNonExistent` if the action does not exist. If the action is already executed or has a terminal status (`Approved`, `Rejected`, or `NoDecision`), it returns silently (`nil, nil`).
2. Loads the current round schedule for the action type, the current `VoteBreakdown` for `CurrentVoteId`, and the current count of active Pillars from `MomentumStore.GetActivePillars()`.
3. Computes `directionalVotes = breakdown.Yes + breakdown.No`. Abstentions are recorded in `breakdown.Total` for transparency but are excluded from `directionalVotes` and from the active-Pillar threshold calculation.
4. For Type-1 actions, approval or rejection is not finalized until the current round voting period has elapsed. This creates a minimum deliberation window for spork-targeted actions: a threshold-crossing vote can still be changed before the round closes. Type-2 actions may finalize as soon as the thresholds are crossed.
5. If the action is finalizable, `directionalVotes * 100` is greater than `activePillars * activePillarThreshold`, and `breakdown.Yes * 100` is greater than `directionalVotes * directionalThreshold`, the action is approved: the contract sets `Status = Approved`, sets `Executed = true`, base64-decodes `Data`, and emits a contract-send block from `GovernanceContract` to `Destination` carrying the decoded payload, `Amount = 0`, `TokenStandard = ZNN`.
6. If the action is finalizable, `directionalVotes * 100` is greater than `activePillars * activePillarThreshold`, and `breakdown.No * 100` is greater than `directionalVotes * directionalThreshold`, the action is rejected: the contract sets `Status = Rejected`, closes the current `VotableHash`, and emits no contract-send block.
7. If the current round is still inside its voting period and no finalizable decision exists, the call returns without effect.
8. If the current round has elapsed without approval or rejection and another ratchet round exists, the contract closes the current `VotableHash`, increments `Round`, derives a fresh `CurrentVoteId` from `(action id, round)`, resets `RoundStartTimestamp` to the current frontier momentum timestamp, writes `VotableHash{Id: CurrentVoteId}`, and returns without executing the action.
9. If the final ratchet round has elapsed without approval or rejection, the contract sets `Status = NoDecision`, closes the current `VotableHash`, and emits no contract-send block.

### 6. Authorization Changes to Existing Contracts

The reference implementation extends, but does not replace, the existing administrator checks. In every case below, `sendBlock.Address == X.Administrator` is changed to `(sendBlock.Address == X.Administrator) || (sendBlock.Address == GovernanceContract)`.

- **Spork contract:** `CreateSpork`, `ActivateSpork`.
- **Bridge contract:** `SetNetwork`, `RemoveNetwork`, `SetNetworkMetadata`, `SetTokenPair`, `RemoveTokenPair`, `Halt`, `Unhalt`, `Emergency`, `ChangeTssECDSAPubKey`, `ChangeAdministrator`, `SetAllowKeygen`, `SetOrchestratorInfo`, `SetBridgeMetadata`, `RevokeUnwrapRequest`, `NominateGuardians`.
- **Liquidity contract:** `Fund`, `BurnZnn`, `SetTokenTuple`, `SetIsHalted`, `UnlockLiquidityStakeEntries`, `SetAdditionalReward`, `ChangeAdministratorLiquidity`, `NominateGuardiansLiquidity`, `EmergencyLiquidity`.

`Destination == TokenContract` is rejected at propose time, so the Token contract administrator remains unaffected by this ZIP.

### 7. Plasma and Fees

- `ProposeAction` is priced at `EmbeddedWDoubleWithdraw` plasma.
- `ExecuteAction` is priced at `EmbeddedSimple` plasma.
- Vote calls inherit pricing from the existing Pillar-voting infrastructure.
- The `ProjectCreationAmount` ZNN fee on `ProposeAction` is held by the contract (consistent with Accelerator-Z behaviour).

### 8. RPC

A new public namespace `embedded.governance` is registered with two methods:

- `GetActionById(id hash) -> Action`
- `GetAllActions(pageIndex uint32, pageSize uint32) -> ActionList`

Where `ActionList` is:

```auto
Count int
List []Action

```

And `Action` wraps `ActionVariable` with computed round, threshold, and vote fields:

```auto
Expired bool // Current round has elapsed
Round uint8 // Current ratchet round
Status uint8 // Voting, Approved, Rejected, NoDecision
CurrentVoteId hash // Vote id used by the active round
ActivePillarThreshold uint32 // Current active-Pillar threshold
DirectionalThreshold uint32 // Current Yes-or-No threshold among directional votes
VotingPeriod int64 // Current round voting period
Votes *definition.VoteBreakdown // {currentVoteId, total, yes, no}

```

A new method `IsGovernanceSporkEnforced() bool` is added to the `AccountVmContext` interface.

### 9. Constants Introduced

```auto
Type1Action = uint8(1)
Type2Action = uint8(2)
ActionStatusVoting = uint8(0)
ActionStatusApproved = uint8(1)
ActionStatusRejected = uint8(2)
ActionStatusNoDecision = uint8(3)
Type1ActionActivePillarThresholds = []uint32{66, 55, 45, 40}
Type1ActionDirectionalThresholds = []uint32{50, 55, 60, 66}
Type1ActionVotingPeriods = []int64{45 * PhaseTimeUnit, 21 * PhaseTimeUnit, 21 * PhaseTimeUnit, 21 * PhaseTimeUnit}
Type2ActionActivePillarThresholds = []uint32{50, 40, 33, 25}
Type2ActionDirectionalThresholds = []uint32{50, 55, 60, 66}
Type2ActionVotingPeriods = []int64{30 * PhaseTimeUnit, 14 * PhaseTimeUnit, 14 * PhaseTimeUnit, 14 * PhaseTimeUnit}
GovernanceActionDataMaxLength = MaxDataLength
ErrUnkownActionType = errors.New("unknown action type")
ErrInvalidActionRound = errors.New("invalid action round")

```

### 10. Fork Classification

This ZIP is a **Spork-gated soft fork** in the operational sense used for prior NoM embedded-contract additions. On the ratchet branch, the canonical `GovernanceSpork` ID is in `ImplementedSporksMap`. Before enforcement, `GovernanceContract` is absent from the embedded-contract map and calls to it are rejected. After enforcement, non-upgraded Pillars cannot validate governance transactions and will stop following the canonical chain, as with prior spork-gated upgrades. If the community classifies this differently, Sponsors may redraft as a Hard Fork with higher acceptance/activation thresholds.

### 11. Activation Paths

#### Path A — Standard Spork Activation (preferred)

1. **Spork creation — COMPLETE.** The authorized spork-signer created `GovernanceSpork` (`3dce423d…9b1d`) at momentum 10,231,257 on 2025-05-01.
2. The ratchet implementation, or an equivalent upstream PR, is merged and released.
3. Pillars upgrade.
4. Once a supermajority is upgraded, the authorized spork-signer submits `ActivateSpork(3dce423d…9b1d)`.
5. From the enforcement height, `GovernanceContract` is callable and the §6 administrator checks take effect.

#### Path B — Pillar-Coordinated Hard Fork (fallback)

If the spork-signer does not activate within a community-agreed timeout, Sponsors may publish a follow-up ZIP that hard-codes enforcement of `GovernanceSpork` at a specified momentum height. Path B should proceed only if at least 2/3 of active Pillars are running the new release before that height; otherwise the height should be delayed by another release. Path B is explicitly a fallback after good-faith attempts at Path A.

## Rationale

**Why an embedded contract?** It reuses NoM’s existing pillar-voting machinery and remains auditable on-chain. A multisig would reintroduce off-chain coordination and a small trusted set.

**Why 66% / 50% initial thresholds?** Spork actions alter protocol rules and start at 66%. Bridge/Liquidity operations start at 50% to remain operationally responsive.

**Why a Type-1 deliberation window?** Type-1 actions can create or activate sporks, so crossing the threshold early should not immediately execute. Type-2 actions may execute immediately because many are operational responses.

**Why are Bridge/Liquidity admin rotations Type-2?** Type is destination-based: Spork is Type-1; Bridge/Liquidity are Type-2. This keeps emergency and operations flows responsive. A follow-up ZIP may introduce method-level Type-1 classification for specific admin/guardian rotations.

**Why the ratchet?** Low turnout should not permanently block governance, but later rounds must require stronger agreement. Therefore active-Pillar thresholds fall while directional thresholds rise.

**Other design choices.** `ExecuteAction` is permissionless so execution cannot be censored; existing administrators remain during transition; `TokenContract` is forbidden because token issuance needs a separate higher-bar ZIP; the 1 ZNN proposal fee mirrors Accelerator-Z; abstentions are visible but do not count toward decision thresholds. Rejected alternatives include security councils, proposer-must-be-Pillar rules, proposer-specified types, unbounded threshold decay, vote carryover across rounds, and deleting executed/expired action history.

## Backward Compatibility

Under **Path A** (Standard Spork Activation): identical to every prior spork-gated upgrade on NoM. Before `GovernanceSpork` enforcement, governance transactions are universally rejected. After enforcement, upgraded Pillars validate them and non-upgraded Pillars stop following the canonical chain — the same property that has held for the Accelerator-Z, Bridge, Liquidity, and HTLC sporks. The high Pillar upgrade rate targeted before signer activation is the mitigation.

Under **Path B** (Pillar-Coordinated Hard Fork fallback): a modified `go-zenon` release hard-codes enforcement of the existing `GovernanceSpork` (ID `3dce423d…9b1d`) at a specified momentum height. The on-chain spork object is unchanged — what changes is that enforcement no longer requires the legacy signer’s `ActivateSpork` transaction. Pillars still running the legacy release at the activation height would be forked out, hence the \>2/3 Pillar binary-upgrade prerequisite before the height is reached.

In both paths: address state, plasma rules, token issuance, momentum/account-block formats, and the Accelerator-Z, Pillar, Sentinel, Stake, HTLC, and Token contracts are unchanged. The Spork, Bridge, and Liquidity contracts gain a _parallel_ authorized caller; their existing administrator continues to work.

## Reference Implementation

Original implementation: [zenon-network/go-zenon#47 — _governance v1_](https://github.com/zenon-network/go-zenon/pull/47) by sumoshi21.

This ZIP’s proposed implementation: [0x3639/go-zenon@codex/governance-ratchet](https://github.com/0x3639/go-zenon/tree/codex/governance-ratchet) at commit `81c2474`, improving on PR #47 with the governance ratchet, Type-1 deliberation window, clarified execution semantics, and additional tests.

Notable files:

- `vm/embedded/definition/governance.go` — ABI, `ActionVariable`, storage helpers.
- `vm/embedded/implementation/governance.go` — `ProposeAction`, `ExecuteAction`, `checkActionVotes`.
- `rpc/api/embedded/governance.go` — RPC namespace.
- `vm/embedded/tests/governance_test.go` — end-to-end propose → vote → execute, ratchet rollover, and Bridge time-challenge lifecycle tests.
- `common/types/{address,spork}.go` — contract address and spork registration.
- `vm/vm_context/{interfaces,spork}.go` — `IsGovernanceSporkEnforced()`.
- `vm/embedded/embedded.go` — governance-aware contract map.
- `vm/constants/{embedded,errors}.go` — thresholds, periods, and error.

### Required pre-merge changes

1. The canonical `GovernanceSpork` ID is already applied on the ratchet branch: **`3dce423d7bc10d2409e598e33811c9c9e79eff178f94adc571aeef30e8bc9b1d`** (created 2025-05-01, momentum 10,231,257). Reviewers SHOULD verify it remains unchanged before merge.
2. Open the ratchet branch as a new PR against upstream and confirm it remains mergeable after upstream review.
3. Independent review of the augmented administrator checks on every Bridge and Liquidity method to confirm no method was missed.

## Security Considerations

- **Spork-ID grinding.** Because `Type` is determined by destination at propose time, an adversary cannot bypass the Type-1 threshold schedule by routing through an indirect destination — there is no proxy contract able to forward to the Spork contract under the current authorization set.
- **Late-round minority capture.** Lower active-Pillar thresholds improve liveness but can concentrate decision power. This ZIP mitigates that risk with explicit threshold floors, rising directional thresholds, fresh vote ids per round, and a terminal `NoDecision` state instead of unbounded threshold decay.
- **Replay across forks.** `Id = sendBlock.Hash` binds the action to a specific momentum chain; cross-fork replay is not possible without identical send-block content.
- **Idle execution.** `ExecuteAction` is permissionless, so a stalled execution cannot block subsequent governance; any pillar or community member may trigger it.
- **Storage growth.** Action records are not garbage-collected. At 1 ZNN per proposal and current expected throughput this is not a concern, but a follow-up ZIP MAY introduce pruning of expired-and-unexecuted actions.
- **Augmented administrator check.** Until the legacy administrator addresses are revoked by a follow-up governance action, the security model is the _weaker_ of {legacy admin key, governance contract}. This is intentional during transition and SHOULD be tightened in a follow-up ZIP once governance is operating reliably.
- **Non-atomic target execution.** Governance approval and target-contract execution are not atomic. `ExecuteAction` marks the governance action `Approved` and `Executed` before the emitted contract-send is processed by the destination contract. If the destination later rejects because its state changed, a precondition is missing, or the method only starts a delayed workflow, the governance action remains terminal and cannot be retried. Operators SHOULD treat approval as authorization to send the target call, not proof that the target-side effect completed.
- **Time-challenged Bridge/Liquidity actions.** Some Bridge and Liquidity administrator methods use existing `TimeChallenge` delays. For those methods, governance requires a two-action lifecycle: the first approved action starts the time challenge, and a second approved action with identical calldata after the delay completes the target change. During the transition period, the legacy administrator and `GovernanceContract` share the same method-name-keyed challenge slot, so either authority can reset or interfere with the other’s pending challenge by submitting different calldata for the same challenged method.

## Copyright

This ZIP is licensed under the GNU General Public License v3.0.
