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. - SONS —
sons_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.
The vote
Section titled “The vote”- A vote is a single boolean:
decision = true→ Adopt (yes),false→ Reject (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
Section titled “Voting Power”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.
| ONS | SONS | |
|---|---|---|
| VP token | OHSHII | the campaign’s own token |
| How VP is read | inter-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 detail | float sqrt of normalized amount | integer 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.
The two-axis model: Normal vs Critical
Section titled “The two-axis model: Normal vs Critical”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.
| Parameter | Default | Floor / bound | Votable? |
|---|---|---|---|
| Normal voting window | 3 days | guardian_min ≤ normal ≤ critical | yes |
| Critical voting window | 7 days | > 0 | yes |
| Guardian-created Normal min window | 1 day | > 0 | yes |
| Guardian-removal window | ≥ 7 days | hardcoded floor (never early-close; vetoable-but-overridable) | no |
| Standard quorum (VP) | 250,000 | ≠ 0 | yes |
| Standard min voters | 15 | ≠ 0 | yes |
| Standard approval | simple VP majority — adopt VP > reject VP (a tie rejects) | hardcoded rule | — |
| Critical quorum (VP) | 350,000 | ≠ 0 | yes |
| Critical min voters | 20 | ≠ 0 | yes |
| Critical approval | ≥ 65% | 1–99 | yes |
| Critical immediate-close VP | 450,000 | > 0 | yes |
| Critical immediate-close voters | 30 | ≠ 0 | yes |
| Critical immediate-close approval | ≥ 75% | 1–99 | yes |
| Veto-override approval | ≥ 80% | 1–99 | yes |
| Veto-override quorum (VP) | 700,000 | ≠ 0 | yes |
| Veto-override min voters | 50 | ≠ 0 | yes |
| Veto-override window | 24 h | ≥ 1 day hard floor | yes |
| VP cap per user | 36,000 | > 0 | yes |
| Min lock duration | 45 days | — | yes |
| Min VP to propose | 10,000 | ≥ 1 | yes |
| Proposal creation fee | 30,000 tokens | ±50% per change; ≥ rejection_cost + ~3× ledger_fee | yes |
| Rejection cost | 25,000 tokens | ±50% per change; ≤ proposal fee | yes |
| Vote rate limit | 3 / hour / proposal | hardcoded | — |
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.
Tally rules
Section titled “Tally rules”- Normal, at the deadline: quorum met iff
voters ≥ min_quorum_votes (15)andtotal_VP ≥ standard_quorum_vp (250,000). If met → Adopt iffadopt_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)andvoters ≥ critical_min_quorum_votes (20). If met and any votes cast → Adopt iffadopt% ≥ 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 ≥ 30andtotal_VP ≥ 450,000andadopt% ≥ 75%→ Approved immediately. The symmetric early reject fires atadopt% ≤ 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.
Proposal lifecycle
Section titled “Proposal lifecycle”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.
Guardian veto and the override round
Section titled “Guardian veto and the override round”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.)
Proposing a proposal
Section titled “Proposing a proposal”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)):
| Outcome | Refund |
|---|---|
| Approved / Executed / ExecutionFailed | Full (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 / Executing | None yet |
Abandoned paid PendingUpload | Forfeited |
Identity verification gate
Section titled “Identity verification gate”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 action | ONS (ecosystem) | SONS (per-campaign) |
|---|---|---|
| Cast a vote | Conditional — 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 proposal | Same conditional gate (guardian exempt) | Same gate (guardian exempt; plus an emergency exemption — see below) |
| Delegate / follow | Same conditional gate (caller + delegate) | follow primitives carry the same gate; vote delegation is an ONS feature (see Liquid Democracy) |
| Guardian veto | Never gated | Never 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.
ONS vs SONS — summary of differences
Section titled “ONS vs SONS — summary of differences”| Aspect | ONS (ohshii_governance) | SONS (sons_governance) |
|---|---|---|
| Instances | one (ecosystem) | one per LGE campaign |
| Scope / can control | launcher, locker, OHSHII ecosystem + any dapp that adds ONS as a controller | its campaign’s canisters + any dapp that adds that SONS as a controller; ONS can act on the campaign only before completion, autonomous after |
| VP token | OHSHII | the campaign token |
| VP source | ICC to lock_storage | canister-local |
| Verification gate | conditional on a method being enabled (default off) | per-DAO requires_verification (default on) |
| Verification store | source of truth | calls ONS + “Forever Verified” cache |
| Vote delegation | yes (Liquid Democracy) | follow primitives exist; delegation product is ONS |
| Param routing | all 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 constants | — | identical 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.
See also
Section titled “See also”- Governance: ONS vs SONS — the full proposal/method catalog and the votable-vs-hardcoded parameter reference.
- Liquid Democracy — ONS vote delegation (follow/unfollow, cascade, rate limits).
- World ID Verification and DecideID Verification.
- Core Workflows — proposal creation, execution, and finalization flows end to end.