Skip to content

OhShii Locker Integration

This document explains how OhShii Locker relates to the launcher, where locks live (SONS governance locks vs the OhShii Locker product), what the launcher can and cannot do, and how token listing and lock workflows work.

Key distinction up front. A campaign’s SONS locks live on that campaign’s sons_governance canister — this covers BOTH the automatic vesting locks created at LGE finalization AND the manual “additional” locks users create for that DAO’s token (create_additional_lock). Manual SONS locks can be created from either frontend — the OhShii launcher frontend or the OhShii Locker frontend — but in both cases the lock is created on, and lives in, the sons_governance canister. This is the opposite of OhShii Locker product locks (OHSHII and other listed tokens), which live on lock_storage + the locker backend/strongbox. The frontend you use to create a lock does not determine where it lives: a DAO-token lock always lands on sons_governance, a listed-token lock always lands on the locker backend.


ContextWhere locks liveHow they are createdWho manages themLauncher backend can modify?
SONS governance locks — a DAO’s own token: (a) LGE vesting locks, (b) manual additional locksEach campaign’s sons_governance canister (per-lock custody subaccount)(a) launcher backend at LGE finalization (batch_create_vesting_locks); (b) any user, from either the launcher OR the OhShii Locker frontend (create_additional_lock, ICRC-2)The sons_governance canister + the user (activate, create manual locks, reclaim cancelled) + that DAO’s own SONS proposalsNo. The launcher backend never touches SONS locks; only the user (governance methods) and the governance canister (its own proposals) can.
OhShii Locker (product) — OHSHII + other listed tokenslock_storage + locker backend/strongboxUsers via the locker frontend; launcher backend “on behalf of” for delayed-unlock claimsLocker backend; users via locker frontend; launcher backend for some flows; ONS proposals for token list and lock opsToken list: yes (via backend or ONS proposals). Locks: yes for certain operations via ONS proposals (status, delete, transfer).
  • SONS governance locks are, from the launcher’s perspective, entirely user- and governance-driven: users create manual locks and activate vesting from the frontend, but the authoritative state is in the sons_governance canister. The launcher backend cannot modify them (it only creates the vesting batch at finalization). Both frontends (launcher and locker) offer the manual-lock and reclaim UIs for DAO tokens; both call the same sons_governance methods.
  • OhShii Locker is a separate app (own codebase, canisters, frontend). The launcher integrates with it by (1) calling the locker backend to list tokens and create locks on behalf of users (e.g. delayed-unlock claim), and (2) using ONS proposals to manage the token list and some lock operations on the locker.

OhShii Locker canisters (separate project)

Section titled “OhShii Locker canisters (separate project)”
CanisterRole
ohshii_locker_backendLock creation, unlock processing, token list (supported tokens). Privileged methods are callable by the authorized canister ohshii_governance (ONS) via approved proposals.
lock_storageLock records and subaccounts. Used for quadratic voting power (OHSHII) and lock points (third-party tokens).
proxyToken transfer authorization
strongboxTransfer logging; holds tokens for locks created “on behalf of” (e.g. by launcher).
ohshii_locker_frontendLocker web UI (separate app). Users create and manage locks here for listed tokens.

Launcher and Locker are two separate codebases and deploy pipelines. They share Internet Identity (and on mainnet, alternative origins for the same principal). See LOCAL_DEPLOY_AND_ARCHITECTURE.md.


These are all locks on a campaign’s own DAO token, and they all live in that campaign’s sons_governance canister. There are two creation paths:

  • Create — automatic vesting (LGE): The launcher backend creates the vesting locks during LGE finalization by calling sons_governance batch_create_vesting_locks (when delayed unlock is enabled). No OhShii Locker canister is involved. These start INACTIVE and the user activates them (below).
  • Create — manual “additional” locks: Any user can lock their own DAO tokens by calling sons_governance create_additional_lock (ICRC-2: approve the governance canister, which pulls the tokens into the new lock’s custody subaccount). This is exposed from both frontends — the OhShii launcher frontend (DAO details / voting-power page) and the OhShii Locker frontend (lock form, DAO-token path) — and in both cases the lock is created on, and managed by, the sons_governance canister (never lock_storage). Manual locks are created Active immediately (no activation step). The lock’s creator is the caller.
  • Custody: Every SONS lock (vesting or manual) holds its tokens in its own custody subaccount of the governance canister — mirroring how the locker holds each product lock in its own strongbox subaccount. Vesting locks are funded from the governance main account async (SONS timer) after finalization; manual locks are funded directly by the user’s ICRC-2 pull at creation. Unlocks are paid out of each lock’s subaccount, and the governance main account is treasury-only. See GOVERNANCE.md → “Per-lock custody isolation”.
  • Activate / claim (vesting only): The launcher frontend lets the user call governance activate_vesting and then dao_storage.confirm_vesting_activation. Unlocks and transfers are handled by the sons_governance canister. Manual locks skip this — they are already Active.
  • Modify: The launcher backend cannot modify any of these locks. Only the governance canister (and the user via governance methods) can. ONS proposals do not apply here; SONS governance can have its own proposals for lock operations (ModifyLock, DeleteLock, TransferLockBeneficiary/Creator, etc.) on that governance’s locks. Consistent with the locker product, a lock a SONS proposal moves to Cancelled leaves its remaining balance in the lock’s custody subaccount, reclaimable by the lock creator via governance claim_cancelled_lock (both the launcher and locker frontends surface a Reclaim button for cancelled SONS locks); a forced Completed or DeleteLock instead sweeps the residual back to the DAO treasury.

OhShii Locker token list (supported tokens)

Section titled “OhShii Locker token list (supported tokens)”

The launcher can manage which tokens are listed on the locker:

  1. Via ONS proposals (production path): ExecuteAdminMethod targeting ohshii_locker_backend:
    • admin_list_token — add a token (ledger metadata is re-fetched by the locker backend at execution).
    • admin_update_token — update min_lock_amount, logo, etc. (name/symbol/decimals/fee always come from the ledger).
    • remove_supported_token — remove token from the list (existing locks become Cancelled; users can reclaim). OHSHII (7rrmx-tyaaa-aaaal-qsraq-cai) can never be removed — it is a permanent supported token (removing it would cancel every active OHSHII lock). The OHSHII ledger is rejected at the frontend, at ONS proposal creation, and authoritatively in the locker backend.
  2. Via launcher backend (e.g. when a user first claims with delayed unlock and the token is not yet listed): the backend calls the locker’s admin_list_token (exposed as list_token_on_locker in launcher code). This is a convenience path; the main governance path is via proposals.

OhShii Locker locks (locks on listed tokens)

Section titled “OhShii Locker locks (locks on listed tokens)”
  • Create:
    • Launcher backend can create a lock on the locker when a user claims LGE tokens with delayed unlock: it calls locker prepare_lock_on_behalf_of, transfers tokens to the locker strongbox, then finalize_lock_on_behalf_of (see create_lock_on_locker in launcher backend).
    • Users create locks via the OhShii Locker frontend (separate app) for any listed token.
  • Modify / delete / transfer: The launcher does not do these from the backend. They are done via ONS proposals (ExecuteAdminMethod on ohshii_locker_backend): admin_update_lock_status, admin_delete_lock, admin_transfer_lock_recipient.

  • Via ONS proposal: Create an ExecuteAdminMethod proposal targeting ohshii_locker_backend, method admin_list_token, with token_id, standard, min_lock_amount, and optional logo. The locker backend re-fetches name, symbol, decimals, and fee from the ledger at execution. See GOVERNANCE.md and Create Proposal form “List Token on Locker”.
  • Via launcher backend: When a user claims with delayed unlock and the token is not yet listed, the backend calls list_token_on_locker (which calls the locker’s admin_list_token). Used for convenience; governance path is via proposals.
  • Update: ONS proposal, method admin_update_token (min_lock_amount, logo, etc.). Name/symbol/decimals/fee are always re-fetched from the ledger by the locker.
  • Remove: ONS proposal, method remove_supported_token. Active and Frozen locks are set to Cancelled; users reclaim via the locker. OHSHII can never be removed (rejected at the frontend, at ONS proposal creation, and authoritatively in the locker backend); any other token is removable.

Where min_lock_amount lives (source of truth). The minimum lock amount (token quantity) is stored only in the locker backend, per token, in its supported_tokens entry, and is enforced there at lock creation. ohshii_governance has no min_lock_amount parameter — admin_update_token merely writes the value into the locker’s state; the locker is the sole reader/enforcer. (Contrast the minimum lock duration: for OHSHII that is a votable ONS parameter, min_lock_duration_days, which the locker pulls and syncs — see GOVERNANCE.md.)

3. Create a lock on OhShii Locker (launcher-initiated)

Section titled “3. Create a lock on OhShii Locker (launcher-initiated)”

When a user claims LGE tokens with delayed unlock:

  1. Launcher backend checks if the campaign token is listed on the locker; if not, it lists it (list_token_on_locker).
  2. Backend calls locker prepare_lock_on_behalf_of(recipient, token_canister_id) and gets lock_id and subaccount.
  3. Backend transfers tokens from pool_manager to the locker strongbox subaccount.
  4. Backend calls locker finalize_lock_on_behalf_of with schedule (e.g. linear vesting). The lock then appears in the locker and is managed there (unlocks, etc.).

All of this is launcher backend → locker backend/strongbox. The lock is stored in lock_storage and managed by the locker; the launcher does not modify it afterwards except via ONS proposals (update status, delete, transfer recipient).

4. Create a lock on OhShii Locker (user-initiated)

Section titled “4. Create a lock on OhShii Locker (user-initiated)”

The user uses the OhShii Locker frontend (separate app): choose a listed token, amount, schedule, and create the lock. The locker backend and lock_storage handle creation and lifecycle. The launcher is not involved.

5. SONS governance locks (sons_governance) — vesting and manual, no OhShii Locker

Section titled “5. SONS governance locks (sons_governance) — vesting and manual, no OhShii Locker”

Every lock on a campaign’s own DAO token lives in that campaign’s sons_governance canister — never on lock_storage. Two creation paths, one home:

  • Automatic vesting (LGE): During LGE finalization, the launcher backend calls governance batch_create_vesting_locks. Locks are stored in the governance canister, each with its own custody subaccount (funded from the governance main account by the SONS timer after finalization); unlocks are paid from those subaccounts, keeping the main account treasury-only. Created INACTIVE — the user activates (below).
  • Manual “additional” locks (user-initiated, either frontend): A user locks their own DAO tokens by calling governance create_additional_lock (ICRC-2: approve the governance canister → it pulls the tokens into the new lock’s custody subaccount). This is available from both the OhShii launcher frontend and the OhShii Locker frontend; both call the same sons_governance method, so the lock lands on the governance canister regardless of which app was used. Created Active immediately. This is the parallel to a Locker-product lock, but for a DAO’s own token it stays in SONS governance — it does not go through the locker backend / lock_storage.
  • Activate (vesting only): User uses the launcher frontend to call governance activate_vesting and then storage confirm_vesting_activation. Unlocks are processed by the governance timer.
  • Cancel / reclaim: A SONS ModifyLock → Cancelled proposal leaves the residual in the lock’s subaccount for the creator to reclaim via governance claim_cancelled_lock (Reclaim button on both frontends) — the same cancel-then-reclaim shape as the OhShii Locker product. Completed/DeleteLock instead sweep the residual to the DAO treasury.
  • The launcher backend cannot modify any of these locks. They are not “on OhShii Locker”; they are in the governance canister. Lock points and the locker token list do not apply to them.

Locker

SONS

ONS

Launcher

funds + pays unlocks

list token, create lock on behalf

batch_create_vesting_locks

proposals: list/update/remove token, lock ops

create_additional_lock, activate_vesting, claim, claim_cancelled_lock

proposals UI

user locks: listed tokens

create_additional_lock, reclaim: DAO tokens

Launcher backend

Launcher frontend

ohshii_governance

sons_governance

per-lock custody subaccounts

ohshii_locker_backend

lock_storage

strongbox

OhShii Locker frontend

Note the two arrows into sons_governance: both the launcher frontend and the locker frontend let a user create/manage manual locks on a DAO token directly on that campaign’s governance canister. The locker frontend routes listed-token locks to the locker backend, but DAO-token locks to sons_governance — the destination follows the token, not the app.

  • Token list on locker: Launcher backend (list when needed) or ONS proposals (list / update / remove).
  • Locker product locks (listed tokens): Launcher backend (create for delayed-unlock claim) or locker frontend (user locks); stored in lock_storage; lock operations via ONS proposals.
  • SONS governance locks (DAO tokens): In sons_governance only — both LGE vesting locks and user-created manual create_additional_lock locks (creatable from either the launcher or the locker frontend). Each is held in its own per-lock custody subaccount (governance main account stays treasury-only); users activate vesting, create manual locks, and reclaim cancelled locks from the frontend; the launcher backend cannot modify them, and ONS proposals do not touch them (only that DAO’s own SONS proposals do).

  • 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 governance locks (vesting + manual, on sons_governance) vs Locker-product locks (listed tokens, on lock_storage).
  • GOVERNANCE.md — ONS vs SONS, proposal categories, snapshot/restore.
  • 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.