Skip to content

Architecture

This document describes the canister layout and the distinction between OHSHII Governance (ONS) and LGE Governance (SONS).

OhShii spans two separate codebases — the Launcher (this repo) and the Locker — plus the OHSHII token suite (the governance token’s own ledger and index). Each set is listed below with its mainnet canister ID and on-chain role.

OhShii Launcher (dev-ohshii-launcher, this project)

Section titled “OhShii Launcher (dev-ohshii-launcher, this project)”
CanisterMainnet canister IDRole
ohshii_launcher_backendvil43-piaaa-aaaal-qsibq-caiCore orchestrator: LGE/token creation, per-campaign deployment of ledger/index/sons_governance, and the housekeeping timer. Holds per-contribution escrow custody, and its MAIN account is the platform / DAO ICP treasury (receives the 5% platform fee and post-window residual sweeps).
dao_storageuqcjy-biaaa-aaaal-qsifq-caiPersistent storage for campaign records, contributions, sponsor/referral data, the per-campaign governance_canister_id mapping, and the DAO-transparency event log. Only the backend writes to it.
pool_managerhymny-gyaaa-aaaal-qsm7a-caiCreates each campaign’s ICPSwap pool and seeds its initial liquidity; at finalization hands the LP position to the campaign’s sons_governance before that DAO becomes autonomous. Also holds the OHSHII ecosystem LP position (under ONS governance), collects trading fees (only via governance proposals), runs ICP→OHSHII treasury buybacks, and refunds held ICP from the campaign and referral subaccounts on failure. See pool_manager responsibilities.
ohshii_governancexnsdw-yaaaa-aaaal-qsqua-caiONS governance — the OhShii ecosystem’s single platform-wide DAO. Members lock OHSHII for Voting Power and vote (quadratic) on proposals, with liquid-democracy delegation and an identity-verification gate (World ID / DecideID). Through executed proposals ONS upgrades and administers the launcher and locker canisters and the OHSHII token suite — canister / asset / governance upgrades (incl. ledger-suite and dapp batches), ExecuteAdminMethod (call_raw to launcher/locker/token methods), config changes, guardian management, snapshot and controller operations, and voting-parameter changes — and manages the OHSHII treasury and its liquidity (the LP position pool_manager holds; it can also mint/hold its own custom ICPSwap pools). It also serves the cached cycle-balance / canister-status reads used by System Status. Full proposal inventory: see Governance scope and GOVERNANCE.md.
ohshii_launcher_frontendv5mnw-oaaaa-aaaal-qsica-caiAsset canister serving the launcher web UI.

Note: sons_governance is not in dfx.json. One sons_governance canister is created per LGE campaign at runtime by the backend (Cycles-Ledger create_canister + install of the bundled sons_governance.wasm.gz); each instance governs a single campaign. See Governance scope.

OhShii Locker (dev-ohshii-locker, separate project)

Section titled “OhShii Locker (dev-ohshii-locker, separate project)”
CanisterMainnet canister IDRole
ohshii_locker_backendidxmu-dqaaa-aaaah-aq7da-caiLock creation and validation, timer-driven unlock processing, and custody orchestration via proxy.
lock_storagegq7kz-gyaaa-aaaah-ard5q-caiCanonical lock records and indices in stable memory, including each lock’s custody subaccount.
proxyop74x-uyaaa-aaaah-aq7uq-caiToken-transfer execution and authorization (ICRC-1 transfers, circuit breaker).
strongboxoi62d-zaaaa-aaaah-aq7ua-caiTransfer logging / custody support; authorizes only the backend and proxy as callers.
ohshii_locker_frontendiewka-oiaaa-aaaah-aq7dq-caiAsset canister serving the locker web UI.

Launcher and Locker are two separate codebases and deploy pipelines. They share Internet Identity (and, on mainnet, alternative origins for the same principal). The launcher backend and ONS governance both call the locker (vesting locks, token-list management via proposals); for SONS vesting vs Locker locks and the integration flows, see OhShii Locker integration.

The OHSHII governance token has its own ICRC token suite — one ledger plus its index:

CanisterMainnet canister IDRole
OHSHII Ledger7rrmx-tyaaa-aaaal-qsraq-caiICRC-1 ledger for the OHSHII token (proposal-fee currency, Voting-Power / lock source, treasury asset).
OHSHII Index7yshl-fqaaa-aaaal-qsrba-caiTransaction index for the OHSHII ledger (history and holder lookups).

The OHSHII ICPSwap pool (yvg67-gyaaa-aaaar-qbseq-cai) is the ICP/OHSHII DEX pool — infrastructure around the token (used for treasury buybacks and the price/swap UI), not part of the token suite itself.

The launcher frontend’s System Status page (SystemStatusPage.jsx) monitors the launcher canisters and this OHSHII token infrastructure only. OhShii Locker has its own canister set and its own System Status page in the locker project.

pool_manager is the launcher’s ICPSwap-liquidity and campaign-custody canister. Its role is broader than the “pool creation and fee collection” summary suggests:

  • Pool creation + initial liquidity — for each campaign it creates the ICPSwap V3 pool (factory createPool via an ICPSwap passcode) and mints the initial LP position. Liquidity is two-phase: the pool is created at LGE start, and the ICP + token liquidity is minted at finalization. Finalize retries are idempotent, so a Frozen→Finalizing retry never orphans a position.
  • LP-position handoff to the SONS DAO — at finalization it executes the one-way ICPSwap transferPosition that moves LP-position ownership from pool_manager to the campaign’s sons_governance. The backend orchestrates this at finalization STEP 2, before the step that seals SONS into autonomy (which removes the backend from the SONS admin set) — so the position belongs to the DAO before the DAO becomes self-governing.
  • Fee collection (governance-gated) — it claims ICPSwap trading fees and keeps per-campaign fee bookkeeping. Direct/creator fee collection is disabled; collection runs only through executed ONS/SONS governance proposals (collect-to-treasury and collect-and-buyback).
  • Holds the OHSHII ecosystem LP position + runs treasury buybackspool_manager is the on-chain owner of the OHSHII/ICP ICPSwap liquidity position (the full-range position on the yvg67… pool), and it also swaps treasury ICP into OHSHII against that same pool, forwarding the bought OHSHII to the treasury. It acts under ONS command: only ohshii_governance may invoke proposal_transfer_pool_position to move that position, and ONS is an admin of pool_manager. (Separately, ohshii_governance can also mint and hold new custom ICPSwap pools directly via its own proposal_create_custom_pool / proposal_transfer_custom_pool_position self-methods — but the live OHSHII position is held by pool_manager, not governance.)
  • Refund custody — on a failed campaign it returns held ICP to contributors from the campaign subaccount and the per-campaign referral subaccount. Refunds draw only from these held subaccounts — never the treasury.

All of the above is driven by the backend (during finalization and refunds) or by executed ONS/SONS governance proposals; pool_manager treats ohshii_governance as an admin so proposal execution can reach its governance-only methods.

Who can modify campaign state and OhShii Locker state

Section titled “Who can modify campaign state and OhShii Locker state”
  • Campaigns (including non-completed)
    Stored in dao_storage. Only the backend can write (it calls update_campaign and admin_update_campaign_status on storage). So campaign state is changed in two ways:

    • Backend (self-flow): methods such as admin_update_campaign_status / admin_update_ico_info are called by the backend as part of its own flows; the backend then calls dao_storage. In production these operations run through ohshii_governance via an approved (ONS) proposal where implemented, or remain unavailable if no proposal path exists.
    • OHSHII Governance (via proposals): When an ONS proposal is approved and executed, ohshii_governance calls the backend via call_raw (e.g. admin_update_campaign_status, admin_update_ico_info); the backend performs the update and calls dao_storage.
      So campaign state is modified by the backend (its own flows) and by OHSHII governance (through executed ONS proposals).
  • Campaign states and refunds
    Campaign state can be Active, Finalizing, Completed, Failed, or Frozen. Finalizing is the provisional phase after the target is reached while pool/liquidity, vesting locks, LP position transfer, governance sync, SONS finalization, and controller cleanup are still running. Completed is terminal and is written only after those critical finalization steps succeed. A campaign becomes Failed when it expires without selling out (housekeeping) or when finalization is run on a non–sold-out campaign. For Failed campaigns, contributors can request a refund within 7 days of expiry. For escrow-funded campaigns the refund is 95% of the contribution, tier-independent: the net 90% held in the campaign subaccount plus the held 5% referral held in the per-campaign referral subaccount (creator still nets ~70% of their original purchase); legacy pure pre-escrow campaigns refund the historical ~90% of gross. Refunds run two ways: a contributor calls request_refund (per-user, within the 7-day window) and the bulk refund_campaign path handles emergency batch processing, invoked by the authorized caller. In both cases the backend marks the contributions as refunded in dao_storage and the pool_manager transfers ICP from the campaign subaccount and the referral subaccount (held funds only — never the treasury) to the user. Each refund leg is net of its own ledger fee, which the user bears. After the 7-day refund window closes, a housekeeping task sweeps any un-refunded residual ICP (campaign subaccount + referral subaccount) to the DAO treasury on-chain — balance-driven and at-most-once, covering both Failed and Completed campaigns. See WORKFLOWS.md (Campaign failure and refunds) for the full per-leg math.

  • OhShii Locker (token list and locks)
    The locker backend (ohshii_locker_backend) accepts calls from its authorized callers — principally ohshii_governance (see locker is_admin() which includes OHSHII_GOVERNANCE_ID) and the launcher backend. The launcher backend also calls the locker (e.g. list_token_on_locker, create_lock_on_locker for vesting flows). So:

    • OHSHII Governance (via proposals): Executes ONS proposals that target the locker (e.g. admin_list_token, admin_update_token, remove_supported_token, admin_update_lock_status, admin_delete_lock, admin_transfer_lock_recipient).
    • Backend: Can add tokens to the locker and create locks on behalf of users (e.g. LGE vesting).
      So both the backend and the OHSHII governance (via proposals) can modify locker state (token list and locks).

LGE contribution custody is per-contribution and fully on-chain — there is no off-chain reconciler. Each purchase routes the buyer’s ICP through a backend escrow subaccount derived per contribution (a single-purchase compartment), then forwards three clean legs out of that escrow:

  • Net 90% → the campaign’s pool_manager subaccount — the LGE proceeds that fund liquidity at finalization.
  • 5% platform → the DAO treasury — sent to the backend canister’s MAIN account (vil43-piaaa-aaaal-qsibq-cai).
  • Held 5% referral → the per-campaign referral subaccount — retained until the LGE outcome (paid out on success, or returned to contributors on failure as part of the 95% refund above).

The backend canister’s MAIN account (vil43-piaaa-aaaal-qsibq-cai) IS the platform / DAO ICP treasury: it receives the 5% platform fee on every purchase and the 7-day residual sweeps after refund windows close. On campaign failure, refunds are paid ONLY from held funds (campaign subaccount + referral subaccount); the treasury is never used as a refund source. Finalization reconciles any un-forwarded escrow stragglers before draining the campaign subaccount, so no contribution is left in limbo without an off-chain process. See WORKFLOWS.md for the authoritative per-leg fee/refund math — it is the single source of truth for the numbers; this section only summarises where the funds sit.


Two different governance systems exist; they must not be confused.

ScopeCanister(s)What it governsToken used for votingDeploy model
OHSHII Governance (ONS)Single canister: ohshii_governance (e.g. xnsdw-yaaaa-aaaal-qsqua-cai)OhShii Launcher canisters (backend, storage, pool_manager), OhShii Locker (token list, etc.), and the OHSHII token suite (ledger, index, archives). Also the OHSHII token’s DEX liquidity positions (held by pool_manager, moved only by ONS proposal) and the OhShii treasury.OHSHII token (quadratic voting on locked tokens)In dfx.json; deployed with the launcher.
LGE Governance (SONS)One per LGE/campaign: sons_governance (dynamic ID per campaign)Only that LGE: treasury of the campaign token, governance WASM, asset canister, pool/params for that campaign.The LGE campaign tokenDynamic: created by the backend during create_ico_campaign (see Backend: governance creation). Not in dfx.json.

LGE Governance SONS

OHSHII Governance ONS

ohshii_governance

Launcher canisters

OhShii Locker

OHSHII token suite ledger/index/archive

OHSHII DEX liquidity positions

sons_governance A

sons_governance B

Treasury + WASM + asset

Treasury + WASM + asset

Vote with OHSHII

Vote with LGE token

Each LGE campaign gets its own governance canister. The backend:

  1. Creates an empty canister via Cycles Ledger (create_empty_governance_canister).
  2. Creates ledger and index canisters with that governance as controller.
  3. Installs the governance WASM (GOVERNANCE_WASM = sons_governance.wasm.gz) into the empty canister.

Relevant code: src/backend/src/lib.rscreate_empty_governance_canister, create_governance_canister_internal, GOVERNANCE_WASM. The same WASM binary is used for every SONS governance canister; each instance has its own state (proposals, treasury, config).


OhShii Locker

OHSHII token

OhShii Launcher

writes campaign state

token list and locks

proposals call backend

proposals call directly

proposals call directly

upgrade/govern

upgrade/govern

upgrade/govern

creates per LGE

governs own

ohshii_launcher_backend

dao_storage

pool_manager

ohshii_governance

ohshii_launcher_frontend

ohshii ledger

ohshii index

ohshii pool

ohshii_locker_backend

lock_storage

proxy

strongbox

ohshii_locker_frontend

sons_governance

Treasury + WASM + asset

Campaign state and locker state are modified by both the backend (direct admin or vesting flows) and the OHSHII governance (via executed ONS proposals), as described in Who can modify campaign state and OhShii Locker state.


All five launcher canisters persist their state directly in stable memory with the ic-stable-structures crate — there is no manual pre_upgrade/post_upgrade serialization step. Each canister has exactly one MemoryManager, which partitions stable memory into VirtualMemory regions (one per MemoryId); each region backs a StableBTreeMap (collections / indices) or a StableCell (single values, config, counters). State therefore survives canister upgrades automatically.

What each canister persists (representative structures):

CanisterPersists in stable memory
ohshii_launcher_backendLaunched-token records + counters, feature-toggle status cells (LGE / token / index creation, the Bitcoin & Solana gateways), critical audit logs, relaunch replay-protection, the Shield used-PoW-nonce ledger, and OHSHII guest-fee custody markers
dao_storageCampaigns, contributions, created tokens, sponsor/referral data, secondary indices, and the DAO-transparency event log
ohshii_governance (ONS)Proposals, executed proposals, votes & voter history, voting-parameter config, identity-verification state (World ID + DecideID), liquid-democracy delegation maps, and an event log
sons_governance (SONS)One instance per campaign — that campaign’s proposals, votes, config, vesting-lock records, delegation maps, and verification state
pool_managerLiquidity-pool registry and per-campaign pool/fee bookkeeping (pool / position / ledger ids, per-campaign sub-accounts, fee totals & distributions) and a pool event log

Upgrade-safe schema evolution (data-integrity model)

Section titled “Upgrade-safe schema evolution (data-integrity model)”

Stable storage is governed by a strict discipline so upgrades never corrupt or silently lose data:

  • New persisted fields are Option<T>, appended last — a missing non-opt field fails Candid decode on upgrade.
  • A MemoryId is never reused once its structure is removed (the MemoryManager never reclaims a bucket; re-binding stale bytes would trap or mis-decode).
  • Value/key types are never tightened or shrunk on a live id.
  • Storable::from_bytes is decode-hardened — a decode failure logs and falls back to a safe default instead of trapping.

The authoritative allocation table for every MemoryId across all OhShii canisters is the MemoryId Inventory.

Note: OhShii Atlas and OhShii Explorer (analytics tools, not DAO-governed) are powered by a separate off-chain analytics service maintained by a contributor; its internals are out of scope for this on-chain architecture document.


  • ARCHITECTURE.md — Canister map and governance scope table.
  • WORKFLOWS.md — Create LGE, token, vote, create/execute proposal, backend vs frontend upgrade, self-snapshot flows.
  • OHSSHII_LOCKER_INTEGRATION.md — OhShii Locker token list and lock management via ONS proposals, SONS vesting vs Locker.
  • GOVERNANCE.md — ONS vs SONS, proposal categories, snapshot/restore.
  • LIQUID_DEMOCRACY.md — Vote delegation on ONS: follow / unfollow flows, accept-followers toggle, dismiss-follower, snapshot cascade model, four-layer rate limits, cross-canister batched VP fetch contract, event log reference, FAQ.
  • LOGGING_SYSTEM.md — Three-tier logging architecture, stable memory log details, frontend monitoring.
  • WORLD_ID_VERIFICATION.md — World ID voter verification: flow, privacy model, three-state config (not_configured / optional / required), threshold-ECDSA RP signatures, rate limits, governance controls and operator checklist.
  • FRONTEND.md — Frontend architecture: React + JSX + JSDoc @ts-check type-checking, the canister-types.js + utils/canister.js bridges, Candid wire conventions, auth providers, and the TypeScript version policy.
  • Deploy/VOTER_VERIFICATION_GUIDE.md — Verifying WASM hashes for DAO proposals.