Architecture
This document describes the canister layout and the distinction between OHSHII Governance (ONS) and LGE Governance (SONS).
Canister map
Section titled “Canister map”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)”| Canister | Mainnet canister ID | Role |
|---|---|---|
ohshii_launcher_backend | vil43-piaaa-aaaal-qsibq-cai | Core 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_storage | uqcjy-biaaa-aaaal-qsifq-cai | Persistent 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_manager | hymny-gyaaa-aaaal-qsm7a-cai | Creates 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_governance | xnsdw-yaaaa-aaaal-qsqua-cai | ONS 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_frontend | v5mnw-oaaaa-aaaal-qsica-cai | Asset 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)”| Canister | Mainnet canister ID | Role |
|---|---|---|
ohshii_locker_backend | idxmu-dqaaa-aaaah-aq7da-cai | Lock creation and validation, timer-driven unlock processing, and custody orchestration via proxy. |
lock_storage | gq7kz-gyaaa-aaaah-ard5q-cai | Canonical lock records and indices in stable memory, including each lock’s custody subaccount. |
proxy | op74x-uyaaa-aaaah-aq7uq-cai | Token-transfer execution and authorization (ICRC-1 transfers, circuit breaker). |
strongbox | oi62d-zaaaa-aaaah-aq7ua-cai | Transfer logging / custody support; authorizes only the backend and proxy as callers. |
ohshii_locker_frontend | iewka-oiaaa-aaaah-aq7dq-cai | Asset 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.
OHSHII token suite
Section titled “OHSHII token suite”The OHSHII governance token has its own ICRC token suite — one ledger plus its index:
| Canister | Mainnet canister ID | Role |
|---|---|---|
| OHSHII Ledger | 7rrmx-tyaaa-aaaal-qsraq-cai | ICRC-1 ledger for the OHSHII token (proposal-fee currency, Voting-Power / lock source, treasury asset). |
| OHSHII Index | 7yshl-fqaaa-aaaal-qsrba-cai | Transaction 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 responsibilities
Section titled “pool_manager responsibilities”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
createPoolvia 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
transferPositionthat moves LP-position ownership frompool_managerto the campaign’ssons_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 buybacks —
pool_manageris the on-chain owner of the OHSHII/ICP ICPSwap liquidity position (the full-range position on theyvg67…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: onlyohshii_governancemay invokeproposal_transfer_pool_positionto move that position, and ONS is an admin ofpool_manager. (Separately,ohshii_governancecan also mint and hold new custom ICPSwap pools directly via its ownproposal_create_custom_pool/proposal_transfer_custom_pool_positionself-methods — but the live OHSHII position is held bypool_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 callsupdate_campaignandadmin_update_campaign_statuson storage). So campaign state is changed in two ways:- Backend (self-flow): methods such as
admin_update_campaign_status/admin_update_ico_infoare called by the backend as part of its own flows; the backend then calls dao_storage. In production these operations run throughohshii_governancevia 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).
- Backend (self-flow): methods such as
-
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 callsrequest_refund(per-user, within the 7-day window) and the bulkrefund_campaignpath 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 lockeris_admin()which includesOHSHII_GOVERNANCE_ID) and the launcher backend. The launcher backend also calls the locker (e.g.list_token_on_locker,create_lock_on_lockerfor 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).
- OHSHII Governance (via proposals): Executes ONS proposals that target the locker (e.g.
LGE fund flow / custody
Section titled “LGE fund flow / custody”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.
Governance scope
Section titled “Governance scope”Two different governance systems exist; they must not be confused.
| Scope | Canister(s) | What it governs | Token used for voting | Deploy 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 token | Dynamic: created by the backend during create_ico_campaign (see Backend: governance creation). Not in dfx.json. |
Diagram: governance scope
Section titled “Diagram: governance scope”Backend: governance creation
Section titled “Backend: governance creation”Each LGE campaign gets its own governance canister. The backend:
- Creates an empty canister via Cycles Ledger (
create_empty_governance_canister). - Creates ledger and index canisters with that governance as controller.
- Installs the governance WASM (
GOVERNANCE_WASM=sons_governance.wasm.gz) into the empty canister.
Relevant code: src/backend/src/lib.rs — create_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).
Canister map diagram
Section titled “Canister map diagram”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.
On-chain data & storage
Section titled “On-chain data & storage”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):
| Canister | Persists in stable memory |
|---|---|
ohshii_launcher_backend | Launched-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_storage | Campaigns, 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_manager | Liquidity-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-optfield fails Candid decode on upgrade. - A
MemoryIdis never reused once its structure is removed (theMemoryManagernever 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_bytesis 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.
See also
Section titled “See also”- 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-checktype-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.