Skip to content

Voting

How a proposal is voted and resolved on the two OhShii governance families:

  • ONS (OhShii Network System) — ohshii_governance, the single OhShii ecosystem DAO. It governs the entire OhShii ecosystem — the launcher, the locker, and the OHSHII token itself (ledger and index) — plus any external dapp that adds it as a controller, which it can then upgrade (backend code and frontend assets) by proposal.
  • SONSsons_governance, one DAO per LGE campaign. It governs that campaign’s treasury, token ledger suite, asset canister, and pool — and, like ONS, any external dapp added as one of its controllers (same code + asset upgrade powers).

ONS does not govern SONS. While an LGE is in progress the launcher backend and ONS are temporary controllers of the new campaign’s canisters (so OhShii can monitor and finalize it). At completion (finalization) those controllers are removed and the campaign DAO becomes fully autonomous — from then on only its own SONS DAO can act on it; ONS has no power over a completed campaign. See Creating a Liquidity Generation Event for the controller lifecycle.

This page is the voting mechanics reference. For the full proposal catalog (every category and admin method) see Governance: ONS vs SONS; for vote delegation see Liquid Democracy; for the identity layer see World ID Verification and DecideID Verification; for how these mechanics add up to capture resistance (threat model, honest limits, and the SNS comparison) see Governance & Capture Resistance.

ONS and SONS share the same two-axis voting engine and (by default) the same threshold constants; they differ mainly in where Voting Power comes from and how identity verification is gated. Those differences are summarised at the end.

  • A vote is a single boolean: decision = trueAdopt (yes), falseReject (no). There is no Abstain — abstaining means not voting, which counts against quorum.
  • Voting is free. It costs no tokens; you only need eligible lock-based Voting Power. (Only creating a proposal costs a fee — see Proposing.)
  • The anonymous principal is always rejected (guard = "reject_anonymous"), and each call passes through the OhShii Shield (PoW / rate-limit / Defcon) with the PoW solution as the trailing optional argument.
  • Rate limit: at most 3 vote attempts per hour per (caller, proposal). The veto-override round uses a separate counter, so spending your round-1 attempts never locks you out of an override vote.
  • One recorded vote per principal per round; a second attempt is rejected (Already voted on this proposal).

Wire signatures:

ONS : vote(proposal_id: nat64, decision: bool, voting_token: principal, pow_solution: opt blob) -> (variant { Ok; Err: text })
SONS : vote(proposal_id: nat64, approve: bool, pow_solution: opt blob) -> (variant { Ok; Err: GovernanceError })

ONS takes a voting_token (which token’s locks supply your VP — OHSHII for ecosystem proposals, or a completed campaign’s token). SONS always uses its own campaign token.

Voting Power is quadratic and time-weighted:

VP = min( sqrt(token_amount) × lock_months , 36,000 )
  • Computed per lock, then summed across a principal’s eligible locks, then capped at max_voting_power_per_user (default 36,000). The cap applies to the sum (36,000 + 4,000 still votes as 36,000).
  • A lock is eligible only if its duration ≥ min_lock_duration_days (default 45 days = 1.5 months) and its status is Active. A freshly-created Inactive vesting lock grants zero VP until the beneficiary activates it.
  • VP is read live at vote time (recomputed from your current locks on every vote). What is snapshotted at proposal creation is the set of decision thresholds (ProposalVotingSnapshot), so a proposal is judged by the rules in force when it was created (grandfathering) — not your VP balance.
ONSSONS
VP tokenOHSHIIthe campaign’s own token
How VP is readinter-canister call to lock_storage (15s bounded wait; never silently defaults to 0 on failure)computed canister-locally from the DAO’s own locks (get_locks_by_creator, zero ICC)
Quadratic detailfloat sqrt of normalized amountinteger isqrt of amount / 1e8, plus a 10-minute duration grace

The quadratic formula is hardcoded (changes only by a canister upgrade); the cap value, the 45-day minimum, and days_in_month are governance-votable.

Every proposal is either Normal (standard) or Critical, which sets its voting window, quorum, and approval rule.

A proposal is Critical when its category is one of: UpgradeCanister, UpgradeGovernanceCanister, UpgradeAssetCanister, CriticalGovernanceOperation, UpgradeCanisterBatch, UpgradeDappBatch. Adding/replacing a guardian also clears Critical thresholds. In addition, a subset of ExecuteAdminMethod proposals run the Critical tier even though the category is Normal — the high-blast-radius admin calls: on ONS (admin_method_call_is_critical) treasury / balance withdrawals, liquidity removal, ICPSwap position transfers, the treasury-funded liquidity operations (create / add / retry / remove-to-treasury / forward-retry), OhShii Locker lock mutations (update-status / delete / transfer-recipient) and campaign deletion, plus token-metadata edits of the OHSHII ledger and LGE-info edits of the root campaign dao-0000000001; on SONS (is_critical_admin_method) the equivalent AdminMethods — TreasuryWithdraw, RemoveLiquidity, TransferLiquidityPosition, CreatePoolAndAddLiquidity, AddLiquidityToPool, ModifyLock, DeleteLock, TransferLockBeneficiary, TransferLockCreator, BatchSetFollow, UpgradeIndexCanister. Everything else (Motion, config/fee changes, most admin methods) is Normal. Only Critical proposals can be guardian-vetoed and can close early.

ParameterDefaultFloor / boundVotable?
Normal voting window3 daysguardian_min ≤ normal ≤ criticalyes
Critical voting window7 days> 0yes
Guardian-created Normal min window1 day> 0yes
Guardian-removal window≥ 7 dayshardcoded floor (never early-close; vetoable-but-overridable)no
Standard quorum (VP)250,000≠ 0yes
Standard min voters15≠ 0yes
Standard approvalsimple VP majority — adopt VP > reject VP (a tie rejects)hardcoded rule
Critical quorum (VP)350,000≠ 0yes
Critical min voters20≠ 0yes
Critical approval≥ 65%1–99yes
Critical immediate-close VP450,000> 0yes
Critical immediate-close voters30≠ 0yes
Critical immediate-close approval≥ 75%1–99yes
Veto-override approval≥ 80%1–99yes
Veto-override quorum (VP)700,000≠ 0yes
Veto-override min voters50≠ 0yes
Veto-override window24 h≥ 1 day hard flooryes
VP cap per user36,000> 0yes
Min lock duration45 daysyes
Min VP to propose10,000≥ 1yes
Proposal creation fee30,000 tokens±50% per change; ≥ rejection_cost + ~3× ledger_feeyes
Rejection cost25,000 tokens±50% per change; ≤ proposal feeyes
Vote rate limit3 / hour / proposalhardcoded

The “normal immediate-approval” constants (90% / 20 voters / 500,000 VP) are vestigial — early close is disabled for Normal proposals in the two-axis model. They are retained only for stable-storage / snapshot compatibility.

  • Normal, at the deadline: quorum met iff voters ≥ min_quorum_votes (15) and total_VP ≥ standard_quorum_vp (250,000). If met → Adopt iff adopt_VP > reject_VP (strict; tie → Rejected). If quorum not met → Expired. Normal proposals never close early.
  • Critical, at the deadline: quorum met iff total_VP ≥ critical_quorum_vp (350,000) and voters ≥ critical_min_quorum_votes (20). If met and any votes cast → Adopt iff adopt% ≥ critical_approval_pct (65%), else Rejected. Quorum met but zero votes, or quorum not met → Expired.
  • Critical early close (inside vote(), before the deadline): voters ≥ 30 and total_VP ≥ 450,000 and adopt% ≥ 75%Approved immediately. The symmetric early reject fires at adopt% ≤ 25%. Guardian gate: if the proposal is vetoable and a guardian is set, an early approval additionally requires the guardian to have voted yes (this preserves a real veto window; the early-reject side has no such gate). A guardian-removal proposal can never close early.

code / asset proposal (awaiting chunk upload)

all other proposals

all WASM/asset chunks uploaded

upload session expires (fee forfeited)

passes (at deadline, or early for Critical)

quorum met but vote fails

quorum not met

guardian veto (Critical/vetoable only)

override round succeeds (>=80% / 700k VP / 50 voters)

veto upheld

execution begins

success

execution error

PendingUpload

Open

Expired

Approved

Rejected

Vetoed

Executing

Executed

ExecutionFailed

The stored status enum is PendingUpload, Open, Approved, Executing, Executed, Rejected, Expired, ExecutionFailed, Vetoed, VetoOverrideExpired. Vetoed is non-terminal (the override round is open); VetoOverrideExpired is a display-only status — once an override window has lapsed the UI shows it, but the stored status stays Vetoed until the timer finalises it to Approved/Rejected. Resolution runs on a periodic timer (ONS ≈ every 5 minutes): expire/close → execute approved → process refunds.

The guardian is a single trusted principal (set via SetGuardian) who can cast a blocking but overridable veto on any Critical/vetoable Open proposal. guardian_veto is deliberately the least-gated update — its only gate is the is_guardian check (no Shield, no rate limit, no cycle floor, no verification) so an emergency veto can always land. It moves Open → Vetoed and opens a separate override round with its own tally and its own vote map (a round-1 voter may vote again; the override round is direct-only — no delegation cascade — and has no early close).

At the override deadline the timer finalises: the override succeeds (Vetoed → Approved) iff override_voters ≥ 50 and override_VP ≥ 700,000 and adopt% ≥ 80%; otherwise the veto is upheld (Vetoed → Rejected). A guardian-removal proposal is itself vetoable-but-overridable: the guardian may veto its own removal, but the community can still remove it by clearing that override supermajority (with a fresh personhood re-attestation per voter) — so removing a guardian that fights its removal takes the 80% / 700,000 VP / 50-voter override, not a bare majority. The guardian can never vote on its own removal in either round. (The 700,000 VP override quorum is intentionally kept reachable — an unreachable bar would turn every veto into a permanent kill.)

Creating a proposal (unlike voting) costs tokens and needs stake:

  • Min VP to propose: live VP ≥ min_vp_to_propose (default 10,000), checked before the fee is charged. SONS additionally requires a raw token balance ≥ 100 tokens (hardcoded floor). Guardians are exempt from the VP/fee checks.
  • Creation fee: default 30,000 tokens (OHSHII for ONS, the campaign token for SONS), collected via ICRC-2 and frozen on the proposal. The deposit is held by the governance canister itself.
  • Refund (single source of truth refund_for(status)):
OutcomeRefund
Approved / Executed / ExecutionFailedFull (fee − ledger fee)
Rejected / Expired (no quorum)Partial (fee − rejection_cost − ledger fee); the withheld rejection_cost (default 25,000) goes to the platform treasury (ONS) / stays on-canister (SONS)
Vetoed / still Open / ExecutingNone yet
Abandoned paid PendingUploadForfeited

OhShii supports two independent proof-of-personhood methods; a principal is verified if either has verified them (OR semantics), and one verification works on every OhShii DAO (verification state lives on ohshii_governance).

  • World ID — scan a World ID document (@worldcoin/idkit); the canister signs the Relying-Party request with IC threshold ECDSA (no HTTPS outcall; the key never materializes). Anti-replay via spent nullifier.
  • DecideID — an Internet-Identity-issued JWT Verifiable Presentation validated by pure on-canister crypto (no inter-canister calls, no HTTPS outcalls). Anti-replay via a presentation digest.

A verification, once granted, persists even if the DAO later disables that method (the check reads the verified-user sets, not the enabled flags). There is no “set verified” backdoor — only the real proof flow adds; the verification state can only be cleared (never forged) by the authorized caller (e.g. ohshii_governance via an approved proposal).

Is verification required to vote? It depends on the DAO family:

Governance actionONS (ecosystem)SONS (per-campaign)
Cast a voteConditional — required only if World ID or DecideID is enabled on ONS. Both default OFF, so by default no verification is required.Conditional on requires_verification, which DEFAULTS TO TRUE — so a fresh campaign DAO requires verification to vote unless it votes the flag off.
Create a proposalSame conditional gate (guardian exempt)Same gate (guardian exempt; plus an emergency exemption — see below)
Delegate / followSame conditional gate (caller + delegate)follow primitives carry the same gate; vote delegation is an ONS feature (see Liquid Democracy)
Guardian vetoNever gatedNever gated

SONS holds no verification store of its own — it calls ohshii_governance.is_verified (10s bounded wait, behind a circuit breaker), then caches a success in a local “Forever Verified” set so the DAO keeps working even during an ONS outage (eviction is restricted to the authorized caller). To prevent a DAO soft-bricking itself (no verified holder left to flip the gate off), an emergency exemption lets any staked holder submit the one narrow rescue proposal — a CriticalGovernanceOperation whose only effect is turning requires_verification off — without being verified.

When the gate is off, the system is not ungated: direct voting/proposing still require VP > 0 (and, on SONS, stake + fee), and delegation substitutes an “active-lock” anti-Sybil check.

Separate, do not conflate: verification also gates LGE participation economics (purchase tier above Guest, the OHSHII guest fee), and sponsor rewards require active-voter status — but those are LGE/economic gates, not governance-voting gates. “Active voter” (recent participation) is a different concept from “verified” (proof-of-personhood). See Participating in an LGE.

AspectONS (ohshii_governance)SONS (sons_governance)
Instancesone (ecosystem)one per LGE campaign
Scope / can controllauncher, locker, OHSHII ecosystem + any dapp that adds ONS as a controllerits campaign’s canisters + any dapp that adds that SONS as a controller; ONS can act on the campaign only before completion, autonomous after
VP tokenOHSHIIthe campaign token
VP sourceICC to lock_storagecanister-local
Verification gateconditional on a method being enabled (default off)per-DAO requires_verification (default on)
Verification storesource of truthcalls ONS + “Forever Verified” cache
Vote delegationyes (Liquid Democracy)follow primitives exist; delegation product is ONS
Param routingall voting params via one CriticalGovernanceOperation (set_voting_parameters)split: fees via ConfigChange (Normal); all thresholds/durations/VP-cap/min-lock/requires_verification via CriticalGovernanceOperation
Threshold constantsidentical defaults to ONS

Both families snapshot per-proposal thresholds at creation (grandfathering); both reject zero quorum; both forbid changing the formula/critical-category classification without a canister upgrade.