Sponsor System
Overview
Section titled “Overview”OhShii Launcher features an optional sponsor system. Three structural properties define it:
- Capped pool, not an open-ended fee. The referral payout is bounded to the 5% referral band of each contribution — at most 5% of the curve (≈
25 × kICP; ≈25 ICP at the 500-ICP default raise, scaling with the creator-chosen500 × ktarget) across all sponsors of a campaign. Sponsor activity cannot raise that ceiling. - Success-contingent (deferred). The full 5% band is held per campaign and a sponsor’s earned share is paid only if the LGE completes successfully. On failure the held band is refunded to contributors; sponsors are paid nothing.
- Claimed from the campaign’s own DAO, not from OhShii. On success the earned Σtier is transferred to the campaign’s autonomous
sons_governancecanister — into a dedicated referral subaccount, kept separate from that DAO’s main treasury account — and registered there (register_sponsor_claims); the sponsor claims it from that DAO. OhShii is not the payer. The unearned remainder settles to the OHSHII treasury.
Sponsors are rewarded based on their Voting Power (VP) from locked OHSHII tokens. Sponsor codes are entirely optional — users can participate in LGE campaigns and token purchases without one. When no sponsor code is provided, the referral band is not earned and ultimately settles to the OhShii treasury.
Every contribution has a 10% total fee split into two halves:
- 5% OhShii platform fee — always goes to the treasury, non-negotiable
- 5% referral/sponsor band — on all current campaigns the full 5% is held per-campaign at purchase time and settled only when the LGE outcome is known (see Deferred referral below). The sponsor’s snapshotted tier cut (0–5% by VP) becomes a claim on success; the unearned remainder settles to the OhShii treasury; on failure the entire held 5% is refunded to buyers.
The campaign always receives a clean 90% of the contribution (the per-leg ICP ledger fees are absorbed by the 5% platform band, not deducted from the campaign net — see Clean-net model). The sponsor’s VP tier is snapshotted at the time of each individual transaction (not once per campaign):
- No sponsor code or VP < 2,000: sponsor earns 0%, treasury retains 10%
- VP ≥ 2,000: sponsor earns 2%, treasury retains 8%
- VP ≥ 3,000: sponsor earns 3%, treasury retains 7%
- VP ≥ 5,000: sponsor earns 5%, treasury retains 5%
Active-voter requirement (Voter Benefits Protocol). The VP tier above only applies if the sponsor is an active ONS voter — i.e. they voted on at least 2 of the last 3 countable OHSHII governance proposals (the same active-voter rule that gates LGE purchase limits). A sponsor who has the VP for a tier but is not an active voter forfeits the reward share entirely (0%, regardless of VP) until they resume voting; the unearned band settles to the OhShii treasury exactly as a sub-threshold tier does. This is evaluated live at each transaction (LGE creation and token purchase alike), reusing the governance get_active_voter_status query — no separate opt-in.
In short, a sponsor’s reward share depends on locked OHSHII (which gives VP) and on remaining an active voter. VP is the OhShii Locker’s quadratic voting power:
VP = sqrt( Σ token_amount × lock_months² )Weights are summed across a principal’s eligible locks and the square root is applied once (for a single lock this is sqrt(token_amount) × lock_months). See Voting.
Architecture
Section titled “Architecture”Two Code Paths for Fee Processing
Section titled “Two Code Paths for Fee Processing”The sponsor system is integrated into two separate fund allocation flows:
1. LGE Creation (allocate_ico_funds)
Section titled “1. LGE Creation (allocate_ico_funds)”When a user creates an LGE campaign and pays the creation fee (5 ICP base + variable token cost), the backend:
- Extracts the sponsor code from
ICOInit.sponsor_code— this is the LGE creator’s referrer (the person who referred the creator) - Looks up the referrer’s sponsor info in
dao_storagecanister - Calls
get_sponsor_fee_percent_by_vp()to fetch the referrer’s current VP and compute their reward share percentage - Splits the 10% token-cost fee between the referrer (sponsor) and backend treasury
- Transfers the sponsor’s cut (if viable) to the sponsor’s account via ICP ledger
Key characteristics:
- The sponsor here is the LGE creator’s referrer, not a campaign-wide sponsor
- This path runs once, when the LGE is created — the fee is extracted from the one-time LGE creation payment, not from subsequent token purchases
- The referrer’s VP is checked at creation time
Key function: allocate_ico_funds() in src/backend/src/lib.rs
2. Token Purchase / Reserved Purchase (escrow forward — resolve_escrow_split / forward_escrow_legs / settle_referral_leg)
Section titled “2. Token Purchase / Reserved Purchase (escrow forward — resolve_escrow_split / forward_escrow_legs / settle_referral_leg)”When a user participates in an LGE with a reserved payment (ICRC-2 approval-based flow), the backend:
- Extracts the sponsor code from the purchase request parameter, or falls back to the buyer’s stored sponsor via
get_user_sponsor() - Resolves the sponsor info upfront (single call to
get_sponsor_info) - Fetches the buyer’s individual referrer’s VP via
get_sponsor_fee_percent_by_vp()(single call to lock_storage) - Snapshots the sponsor’s VP tier and resolves the fee split (10% total: 5% platform + held 5% referral band, with the sponsor’s tier cut recorded inside it) before any funds move (
resolve_escrow_split/escrow_split_math), so the split is fixed for that purchase - Forwards from the per-contribution escrow to three destinations as discrete, single-responsibility legs: the campaign subaccount (clean net), the OhShii treasury (platform fee, which also absorbs the per-leg ledger fees), and the per-campaign referral subaccount on
pool_manager(the full 5% referral band, HELD until the LGE outcome is known)
Key characteristics:
- The sponsor here is each buyer’s individual referrer — different buyers in the same campaign can have different sponsors
- VP is re-checked at every purchase (not cached, not set once per campaign); the resulting tier cut is snapshotted into the contribution so the eventual settlement uses the tier as of purchase time
- If a sponsor’s VP changes between purchases (e.g., they lock more tokens or unlock), future purchases snapshot the new tier
- No sponsor transfer happens at purchase. The third leg routes the full 5% into the per-campaign referral subaccount, where it is held. The referral leg is an isolated step in the escrow forward (
settle_referral_leg), so it can be redirected without re-architecting the campaign and platform legs.
Fee custody (current, shipped): the fee split executes inside the per-contribution escrow forward — ICP moves Buyer → a per-contribution backend escrow → the three legs above. The escrow is an internal custody mechanism; from the user’s perspective the campaign nets a clean 90% and the referral band is held pending the outcome. See WORKFLOWS.md (LGE participation / purchase flow).
Deferred referral is the shipped default. On all current campaigns (
referral_deferred = Some(true), set at creation, and ondao-0000000011) the full 5% referral band is held in the per-campaign referral subaccount until the LGE outcome is known. The sponsor’s snapshotted tier cut is registered as a claim on the campaign’ssons_governancecanister on success and the sponsor claims it there (within 7 days); the unearned remainder of the 5% settles to the OhShii treasury; on failure the entire held 5% is refunded to buyers. The legacy immediate-pay path (referral_deferred = None/false, sponsor paid at purchase) is dead — no live campaign uses it — and is documented only where examples are explicitly labelled “legacy”.
A purchase never falls back to paying the referral band out. If the campaign’s referral setting cannot be read when a purchase is made, the purchase is refused before anything is charged and can simply be retried.
Token-math basis: the bonding curve prices on the gross ICP a buyer sends, on every live campaign — the pre-escrow one (curve_input_net = None) and every campaign created since (Some(false)) alike. The escrow still forwards the net ~90% to the campaign subaccount; the curve input is the gross. The net input basis (curve_input_net = Some(true)) exists in code but is retired — it broke the listing ratio — and no campaign carries it. None of this changes the 10% fee split or the tier table below.
Key functions (live, deferred path): resolve_escrow_split / escrow_split_math (regime-aware split), forward_escrow_legs (the three legs), settle_referral_leg (the isolated held-band leg), and on success settle_deferred_referral_on_success / drain_campaign_referral — all in src/backend/src/lib.rs and src/pool_manager/src/lib.rs. process_fees_for_reserved_purchase() is the legacy immediate-pay arithmetic and has no live call sites.
Sponsor Code Lookup
Section titled “Sponsor Code Lookup”Source: dao_storage canister
- Method:
get_sponsor_info(sponsor_code: String) → Option<SponsorInfo> - Returns: Sponsor’s principal, total earnings, and referral history
Flow:
VP Retrieval
Section titled “VP Retrieval”Source: lock_storage canister (OhShii Locker)
- Method:
calculate_quadratic_voting_power(principal: Principal, token_id: Principal) → QuadraticVotingPowerResult - Calculation:
VP = sqrt( Σ token_amount × lock_months² )over the principal’s eligible locks
Notes:
- VP is specific to the OHSHII token (the locker sums locked OHSHII across all locks for a user)
- VP is a floating-point value rounded to an integer for tier comparison
- If the call fails, the backend safely defaults to 0% sponsor fee
Fee Calculation
Section titled “Fee Calculation”The total transaction fee is always 10% of a contribution, split into the platform band and the referral band:
Total fee = contribution_amount × 10% = platform_fee + referral_band
Platform fee = contribution_amount × 5% (always goes to treasury; also absorbs the per-leg ledger fees)Referral band = contribution_amount × 5% (HELD per-campaign on the deferred path; see below) └─ sponsor tier cut = contribution_amount × (sponsor_fee_percent / 100) (0–5% by VP, SNAPSHOTTED) └─ remainder = contribution_amount × ((5% - sponsor_fee_percent) / 100)Campaign = contribution_amount × 90% (clean — see Clean-net funding model)Deferred path (live, regime-aware split). escrow_split_math(gross, sponsor_fee_percent, referral_deferred = true) keeps the platform 5% headed to the treasury and routes the full 5% referral band (tier cut + remainder) into the per-campaign referral subaccount. The sponsor_fee_e8s value is the snapshotted tier cut carried into the contribution for the per-sponsor settlement after success; it is not transferred at purchase. The settlement uses the held band:
- Success: the sponsor’s snapshotted tier cut becomes a
claim_referralclaim on the campaign’ssons_governance; the remainder of the 5% settles to the OhShii treasury. - Failure: the entire held 5% is refunded to buyers (so each contributor recovers 95% — see Failure path).
All percentages are stored internally as per-mille (÷1000) to avoid floating-point precision issues:
let sponsor_fee_percent_permille: u64 = match vp { vp if vp >= 5000 => 50, // 5% = 50 per-mille vp if vp >= 3000 => 30, // 3% = 30 per-mille vp if vp >= 2000 => 20, // 2% = 20 per-mille _ => 0 // 0% = 0 per-mille};
platform_fee_e8s = (token_cost_e8s * 50) / 1000; // always 5%, to treasuryreferral_band_e8s = (token_cost_e8s * 50) / 1000; // full 5%, HELD per-campaignsponsor_fee_e8s = (token_cost_e8s * sponsor_fee_percent_permille) / 1000; // 0–5%, SNAPSHOTTED tier cut inside the bandOn the live deferred path the campaign subaccount is funded with a clean 90% directly (next section), and the full 5% referral band is held — not netted away leg-by-leg.
Clean-net funding model
Section titled “Clean-net funding model”Each forward leg incurs one ICP ledger fee (0.0001 ICP / 10,000 e8s). On the live deferred path those per-leg fees are absorbed by the 5% platform band (treasury side), not deducted from the campaign net. The campaign subaccount therefore receives a clean 90% of gross, so the pool draws exactly its target (450 × k ICP for a creator-chosen 500 × k raise — e.g. 450 ICP for the 500-ICP default) regardless of how many individual contributions made it up. The buyer additionally pays the inbound transfer_from ledger fee on top of their contribution (the escrow receives the full gross).
VP-Gated Reward Tiers (Reference Table)
Section titled “VP-Gated Reward Tiers (Reference Table)”The percentages below are the on-success settlement shares. On the live deferred path the full 5% referral band is held at purchase; on success the sponsor claims their tier cut from the campaign’s own sons_governance canister and the treasury retains the rest, as shown. On failure the held 5% is refunded to buyers (sponsor earns 0, treasury retains only the platform 5%).
| Sponsor VP Range | Reward share % | Treasury share (on success) | Campaign Gets | Notes |
|---|---|---|---|---|
| No code provided | — | 10% | 90% | No sponsor to pay; on success the full 5% band settles to treasury |
| < 2,000 VP | 0% | 10% | 90% | Sponsor not yet qualified; on success the full 5% band settles to treasury |
| ≥ 2,000 VP | 2% | 8% | 90% | Minimum tier; sponsor claims 2% of the held 5% band on success |
| ≥ 3,000 VP | 3% | 7% | 90% | Mid tier; sponsor claims 3% of the held 5% band on success |
| ≥ 5,000 VP | 5% | 5% | 90% | Maximum tier; sponsor claims the full 5% band on success |
Important: The campaign always receives a clean 90% of the contribution regardless of the sponsor fee tier. The 5% OhShii platform fee always goes to the treasury. The sponsor’s tier cut is taken from the 5% referral band only, never from the campaign’s 90% or the platform fee — and on the deferred path it is settled at the LGE outcome, not at purchase.
Backend Implementation
Section titled “Backend Implementation”Primary Function: get_sponsor_fee_percent_by_vp()
Section titled “Primary Function: get_sponsor_fee_percent_by_vp()”Located in src/backend/src/lib.rs. For a sponsor principal it:
- Reads the sponsor’s OHSHII voting power with one bounded-wait call to
lock_storage::calculate_quadratic_voting_power(VP is never cached). - Maps the rounded VP to a tier, in per-mille:
≥ 5,000 → 50(5%),≥ 3,000 → 30(3%),≥ 2,000 → 20(2%), otherwise0. - For a non-zero tier, asks
ohshii_governance.get_active_voter_statuswhether the sponsor is an active voter; a sponsor who is not gets0.
Failure behaviour: if either call fails or cannot be decoded, the result is 0 — the reward share is withheld, never widened, the referral band stays with the treasury, and the buyer’s purchase or LGE creation is not blocked. Each such fallback is recorded in the LGE logs.
Frontend UI
Section titled “Frontend UI”Sponsor Code Input
Section titled “Sponsor Code Input”Sponsor codes are presented as optional fields in all participation flows:
- LGE creation form: optional “Sponsor Code” field
- LGE participation (purchase) flow: optional sponsor code, or the buyer’s stored sponsor
When no sponsor code is used, the referral band settles to the OhShii treasury.
VP Tier Display
Section titled “VP Tier Display”Two locations display sponsor reward share tiers to users:
1. OnsVotingPage “Other Benefits” Section
Section titled “1. OnsVotingPage “Other Benefits” Section”The user’s VP is displayed alongside reward share tiers they can achieve:
Your Voting Power: 2,345 VP
Reward Tiers: • 0% reward share (no sponsor code) • 2% reward share (2,000+ VP) ← Your current tier • 3% reward share (3,000+ VP) • 5% reward share (5,000+ VP)Users see which tier they qualify for based on their current VP.
2. SponsorSystem Component (TokenManagement/SponsorSystem.jsx)
Section titled “2. SponsorSystem Component (TokenManagement/SponsorSystem.jsx)”Displays a comprehensive sponsor dashboard:
- Current sponsor status (registered, not registered, VP)
- Reward tier based on VP
- Earnings summary
- Referral history
The component fetches the user’s sponsor code (via get_sponsor_code_by_principal) and VP (via calculate_quadratic_voting_power) to compute the reward share percentage.
Fee Flow Diagram
Section titled “Fee Flow Diagram”This flow runs independently for each transaction (LGE creation or token purchase). Different buyers in the same campaign may trigger different sponsor lookups and VP tiers.
Examples
Section titled “Examples”All examples below are on the live deferred path (referral_deferred = Some(true)): at purchase the full 5% referral band is held per-campaign, and the snapshotted sponsor tier cut is settled only at the LGE outcome.
Example 1: No Sponsor Code
Section titled “Example 1: No Sponsor Code”User A contributes 100 ICP to campaign X, no sponsor code.
Contribution: 100.0 ICPTotal fee (10%): 10.0 ICP ├─ Platform fee (5%): 5.0 ICP → treasury (also absorbs per-leg ledger fees) └─ Referral band (5%): 5.0 ICP → HELD in per-campaign referral subaccount (snapshotted sponsor cut = 0; no code provided)Campaign receives: clean 90.0 ICPAt outcome: • SUCCESS → snapshotted cut 0 → nothing claimable; the full 5% held band settles to OHSHII treasury • FAILURE → the full 5% held band is refunded to buyers (User A recovers 95 ICP)Example 2: Sponsor with 2,500 VP (2% tier)
Section titled “Example 2: Sponsor with 2,500 VP (2% tier)”User B contributes 100 ICP with sponsor code “vp2500”. Sponsor has 2,500 VP → snapshots the 2% tier.
Contribution: 100.0 ICPTotal fee (10%): 10.0 ICP ├─ Platform fee (5%): 5.0 ICP → treasury (also absorbs per-leg ledger fees) └─ Referral band (5%): 5.0 ICP → HELD in per-campaign referral subaccount (snapshotted sponsor cut = 2.0 ICP; remainder 3.0 ICP)Campaign receives: clean 90.0 ICPAt outcome: • SUCCESS → 2.0 ICP claimable by the sponsor on the campaign's sons_governance (within 7 days); remainder 3.0 ICP → OHSHII treasury • FAILURE → the full 5.0 ICP held band is refunded to buyers (User B recovers 95 ICP, sponsor earns 0)Example 3: Sponsor with 6,000 VP (5% tier, maximum)
Section titled “Example 3: Sponsor with 6,000 VP (5% tier, maximum)”User C contributes 100 ICP with sponsor code “whale_sponsor”. Sponsor has 6,000 VP → snapshots the maximum 5% tier.
Contribution: 100.0 ICPTotal fee (10%): 10.0 ICP ├─ Platform fee (5%): 5.0 ICP → treasury (also absorbs per-leg ledger fees) └─ Referral band (5%): 5.0 ICP → HELD in per-campaign referral subaccount (snapshotted sponsor cut = 5.0 ICP; remainder 0)Campaign receives: clean 90.0 ICPAt outcome: • SUCCESS → 5.0 ICP claimable by the sponsor on the campaign's sons_governance (within 7 days); no remainder • FAILURE → the full 5.0 ICP held band is refunded to buyers (User C recovers 95 ICP, sponsor earns 0)Example 4: Sponsor with VP < 2,000 (no reward share)
Section titled “Example 4: Sponsor with VP < 2,000 (no reward share)”User D contributes 50 ICP with sponsor code “newbie_sponsor”. Sponsor has 1,500 VP → does not qualify for any tier.
Contribution: 50.0 ICPTotal fee (10%): 5.0 ICP ├─ Platform fee (5%): 2.5 ICP → treasury (also absorbs per-leg ledger fees) └─ Referral band (5%): 2.5 ICP → HELD in per-campaign referral subaccount (snapshotted sponsor cut = 0; below the 2,000 VP threshold)Campaign receives: clean 45.0 ICPAt outcome: • SUCCESS → nothing claimable; the full 2.5 ICP held band settles to OHSHII treasury • FAILURE → the full 2.5 ICP held band is refunded to buyers (User D recovers 47.5 ICP)Deferred referral (shipped, default)
Section titled “Deferred referral (shipped, default)”On every current campaign (Campaign.referral_deferred = Some(true), set at creation, and on dao-0000000011) the full 5% referral band is held per-campaign instead of paying the sponsor at purchase time. The band lives in a per-campaign referral subaccount on pool_manager, derived from the campaign id, and is settled only once the LGE outcome is known.
Aggregate cap. Because the band is 5% of each contribution and the curve raises the creator-chosen 500 × k ICP (default ~500; k = target / 500, k in 1..=10), the entire referral payout of a campaign is bounded to ≈25 × k ICP (≈25 at the default — 5% of the curve), split across all of its sponsors by tier. Sponsor activity cannot raise that ceiling; any unearned portion settles to the OHSHII treasury (on success) or is refunded to buyers (on failure). This is the sense in which the referral program is a fixed, bounded pool rather than an open-ended per-referral fee.
- At purchase: the third escrow leg routes the full 5% (snapshotted sponsor tier cut + remainder) into the per-campaign referral subaccount on
pool_manager. The sponsor’s tier cut is snapshotted into the contribution at purchase-time VP, but no sponsor transfer happens. - On success (
settle_deferred_referral_on_success/drain_campaign_referral): the sum of snapshotted tier cuts moves out of thatpool_managersubaccount into a dedicated referral subaccount on the campaign’ssons_governance, and is registered there asclaim_referralclaims; sponsors claim their cut from that subaccount within 7 days; the unearned remainder of the 5% drains to the OHSHII treasury. The sponsors’ pot is therefore isolated from the DAO’s own treasury account — aTreasuryWithdrawproposal cannot reach it, and a sponsor’s claim cannot draw on DAO funds. A sponsor’s snapshotted referral band below the dust threshold folds into the platform leg at purchase (→ treasury), and on the SONS settlement the last claimant absorbs any ≤N×fee shortfall so no claimant dead-ends. - After the 7-day claim window: entitlements still unclaimed are swept out of the referral subaccount to the OhShii treasury by
sweep_expired_referrals, a permissionless call anyone may make once the deadline has passed (there is no privileged operator step and no off-chain reconciler). - On failure: the entire held 5% is refunded to buyers — see the Failure path below.
Failure path (deferred referral)
Section titled “Failure path (deferred referral)”When a campaign Fails, contributors request a refund via the backend (request_refund) within the 7-day window. On the deferred path the contributor recovers 95% of their gross contribution — the net 90% that funded the LGE plus the held 5% referral band — and this is tier-independent (the sponsor earns nothing on a failed campaign, so the whole 5% goes back to buyers regardless of the snapshotted tier). For comparison, the campaign creator keeps roughly 70% of their own contribution on the standard split. Each refund leg (campaign and referral) is transferred from the HELD subaccounts net of its own ICP ledger fee (0.0001 ICP / 10,000 e8s), so the participant bears the per-leg fee; the treasury does not cover or top up any refund fees. For a pre-escrow/legacy campaign the referral subaccount is empty (its 5% was retained in the campaign subaccount over-retention), so the whole 95% is paid from the campaign subaccount — the empty referral subaccount is the protection, never a treasury draw.
If the contributor paid the Guest-tier OHSHII fee at contribution time (30,000 OHSHII, snapshotted then), that fee is also refunded on a failed campaign — the refund is idempotent and keyed per (user, campaign), so sibling contributions cannot double-charge or double-refund it.
For the end-to-end refund mechanics (subaccount draw, atomic mark, no-over-draw and no-double-pay invariants), see WORKFLOWS.md → Campaign failure and refunds.
Referral registration & verification gating (anti-Sybil)
Section titled “Referral registration & verification gating (anti-Sybil)”To resist Sybil attribution — fake or throwaway identities used to farm referral storage and reward shares — the referral system is gated on the invited user’s identity verification:
-
Connection persistence. A sponsor↔user referral connection is only persisted on-canister (the
dao_storageUSER_SPONSORSmap, the sponsor’sreferralslist, and theSPONSOR_USERS_INDEX) once the invited user is verified in governance (any accepted method, Google included, viaohshii_governance.is_verified). Until then the referrer code is held pending client-side (localStorage) and commits no canister storage, so a flood of unverified identities cannot bloat sponsor state. -
Reward routing. While the invited buyer holds no verification at all, the sponsor earns nothing on that buyer’s purchases — the corresponding referral share stays with the OhShii treasury. The check is made at purchase time, from the eligibility record
get_lge_eligibilityalready returns; it is not retroactive to that buyer’s earlier unverified purchases. -
Already-verified invitee. If the invited user is already verified, attribution is confirmed immediately; the verification flows that accept an optional
sponsor_codealso confirm a pending connection right after a successful verification. -
Strength is not part of this gate. All three gates ask only “is this wallet verified at all?”, so a Google-verified invitee counts exactly as a strongly verified one. Referral attribution is not electorate integrity.
For integrators reading the same answer, note the name collision between two fields:
Source Field / call Meaning LgeEligibilityrecord (fromget_lge_eligibility)verification_strengthpresent for any verification method; absent only for a wallet with no verification at all LgeEligibilityrecordis_verifiedthe tier ladder’s question: does the wallet hold a Strong method (Human tier or above)? falsefor a Google-only walletohshii_governanceis_verifiedquerythe union over all four providers, i.e. “any method”
The rule is enforced on-canister at every entry point that can create an
attribution or route a reward — the purchase-time split, the purchase-path
attribution, and the standalone set_user_sponsor — so it does not depend on the
frontend. The frontend additionally keeps an unverified user’s code as pending
rather than calling set_user_sponsor.
Configuration & Governance
Section titled “Configuration & Governance”Current Configuration (Hardcoded)
Section titled “Current Configuration (Hardcoded)”VP thresholds and reward share percentages are hardcoded in src/backend/src/lib.rs:
if vp >= 5000 { 50 } // 5% (50 per-mille)else if vp >= 3000 { 30 } // 3% (30 per-mille)else if vp >= 2000 { 20 } // 2% (20 per-mille)else { 0 } // 0%Because they are hardcoded, changing them requires a canister upgrade, which on the launcher backend is itself an ONS proposal.
Minimum Transfer Amounts
Section titled “Minimum Transfer Amounts”ICP Ledger transfer fee: 0.0001 ICP (10,000 e8s)
On the live deferred path there is no purchase-time sponsor transfer, so the dust threshold does not gate a sponsor payout at purchase. Instead:
- Campaign subaccount: 30,000 e8s (0.0003 ICP). If the net campaign leg is below this, it is consolidated rather than transferred as dust.
- Sub-dust referral band: if a contribution’s snapshotted sponsor referral band is below the dust threshold (30,000 e8s / 0.0003 ICP), it is folded into the platform leg (→ OHSHII treasury) at purchase rather than held as dust in the referral subaccount.
- Sponsor payout (deferred): the sponsor’s actual payout is a balance-driven
claim_referralon the campaign’ssons_governanceafter a successful LGE, payingmin(registered_claim, subaccount_balance − fee)— wheresubaccount_balanceis the balance of that canister’s dedicated referral subaccount, not its main treasury account, so the payout can never draw on DAO funds. The held band can be a few ledger fees short of the sum of registered claims, so the last claimant absorbs the shortfall — no claimant dead-ends, and no dust transfer is attempted at purchase.
These thresholds are hardcoded and not currently governance-configurable. They prevent dust transfers that would incur more in fees than the actual amount transferred.
Edge Cases & Safe Defaults
Section titled “Edge Cases & Safe Defaults”1. VP Fetch Failure
Section titled “1. VP Fetch Failure”Scenario: calculate_quadratic_voting_power call to lock_storage fails or times out.
Behavior: Backend returns 0 immediately (safe default).
Result: Sponsor fee is 0%; full 10% stays in backend treasury.
Logged: Warning message recorded in LGE logs.
2. Self-Sponsorship
Section titled “2. Self-Sponsorship”Scenario: User tries to use their own sponsor code.
Behavior: Before processing fees, backend calls get_sponsor_info(code). If the returned sponsor_principal equals the caller_principal, sponsorship is rejected.
Result: Sponsor fee is 0%; full 10% stays in backend treasury.
Logged: Warning message: “Self-sponsorship detected, sponsor fee = 0%“
3. Invalid or Deleted Sponsor Code
Section titled “3. Invalid or Deleted Sponsor Code”Scenario: Sponsor code not found in storage or sponsor has been deactivated.
Behavior: get_sponsor_info(code) returns None or an error.
Result: Sponsor fee is 0%; full 10% stays in backend treasury.
Logged: Warning message: “Sponsor code not found. 0% sponsor fee.”
4. Sponsor Referral Band Below the Dust Threshold
Section titled “4. Sponsor Referral Band Below the Dust Threshold”Scenario: A sponsor snapshots a reward share (e.g., 3% of a tiny contribution), but that contribution’s referral band is below the dust threshold (30,000 e8s / 0.0003 ICP).
Behavior (deferred path — live): there is no purchase-time sponsor transfer to attempt. The sub-dust band is folded into the platform leg (→ OHSHII treasury) at purchase rather than held as dust. For above-threshold contributions, the band is held and the eventual sponsor payout is a balance-driven claim_referral on the campaign’s sons_governance after success — min(registered_claim, subaccount_balance − fee), drawn from that canister’s dedicated referral subaccount rather than its DAO treasury — where the last claimant absorbs any ≤N×fee shortfall.
Result: No dust transfer is made at purchase; the sponsor’s earnings are settled (or absorbed) only at the LGE outcome.
Logged: Info message recorded in LGE logs when a sub-dust band is folded into the platform leg.
5. User Has No Locked OHSHII (VP = 0)
Section titled “5. User Has No Locked OHSHII (VP = 0)”Scenario: User is registered as a sponsor but has not locked any OHSHII tokens.
Behavior: calculate_quadratic_voting_power returns 0 VP.
Result: Sponsor fee is 0%; full 10% stays in backend treasury.
Logged: Info message (if sponsor code is provided): “Sponsor fee is 0% based on VP tier. Full 10% fee remains in backend treasury.”
Integration Points
Section titled “Integration Points”Backend <→ Storage Canister
Section titled “Backend <→ Storage Canister”| Method | Called by | Purpose |
|---|---|---|
get_sponsor_info(code) | LGE creation (allocate_ico_funds) and the purchase split | Resolve sponsor principal and validate sponsor code |
set_user_sponsor(principal, code) | Backend (during LGE creation via call::call to storage) and Frontend (via user action) | Associate a user with a sponsor code for future referrals |
Backend <→ Lock Storage Canister (OhShii Locker)
Section titled “Backend <→ Lock Storage Canister (OhShii Locker)”| Method | Called by | Purpose |
|---|---|---|
calculate_quadratic_voting_power(principal, token_id) | get_sponsor_fee_percent_by_vp() | Fetch sponsor’s OHSHII voting power |
Frontend <→ Backend
Section titled “Frontend <→ Backend”| Method | Called by | Purpose |
|---|---|---|
set_user_sponsor(caller, code) | User (via form) | Register a user with a sponsor code |
register_sponsor_with_icrc2_payment(args, pow) | SponsorSystem.jsx | Pay the 3 ICP registration fee (ICRC-2 approval) and register the sponsor code in one call |
Registering a sponsor code (one call, paid once)
Section titled “Registering a sponsor code (one call, paid once)”- No preparation step. The page approves 3 ICP to the backend and calls
register_sponsor_with_icrc2_payment; a separate preparation call is not needed (prepare_sponsor_registrationremains callable for older clients). A call without a sufficient allowance is refused before anything is recorded or charged. - One call per principal at a time, and the per-caller rate limit and the Shield checks run first.
- The fee is taken at most once per principal. Before it asks the ICP ledger for the
fee, the backend durably records the payment it is about to request (its memo and a fixed
created_at_time, stored per payer). A retry re-sends exactly the same request, which the ledger deduplicates, or, when the fee has already arrived, registers without asking for it again. - A landed fee is a credit for this principal. If the code cannot be registered after the fee has landed, the answer says so and the next call — with another code if needed — registers it without a new charge.
- An interrupted payment older than a day is settled from the ICP ledger. The ledger deduplicates a repeated request only for about 24 hours. After that, the payer’s next call reads the ICP ledger’s own history for the recorded request: if it landed, it counts as paid and the code is registered without a new charge; if it provably never landed, the old attempt is discarded and the call pays once. Until the ledger’s window has closed, or while the read is still in progress, the call answers “call again later” and charges nothing.
- When the registration band is busy. Registrations share a rate-limited band. When it is spent, the refusal is the Shield proof-of-work demand; the page solves the proof automatically (a few seconds) and registers through a separate, rate-limited lane. When the band is certain to be in its high-load state, the proof is demanded before consensus, at no cost.
- The pay-first path is retired.
register_sponsor_with_payment(send ICP first, verify afterwards) refuses every call with a message pointing toregister_sponsor_with_icrc2_payment, and charges nothing. Do not send ICP directly to the backend for a sponsor code.
Frontend <→ Storage Canister
Section titled “Frontend <→ Storage Canister”| Method | Called by | Purpose |
|---|---|---|
get_sponsor_info(code) | SponsorSystem.jsx | Display sponsor details (earnings, tiers) |
get_sponsor_code_by_principal(principal) | SponsorSystem.jsx | Check if user has a sponsor code |
Behaviour on Mainnet
Section titled “Behaviour on Mainnet”- Sponsor VP is live (calculated from real locked OHSHII)
- A sponsor’s tier changes only when they lock or unlock tokens, a lock’s duration changes their VP, or their active-voter status changes
- VP is not cached; each transaction recalculates current VP
Q: Can I use a sponsor code I created myself?
A: No. The backend checks if the sponsor principal matches the caller principal and rejects self-sponsorship. Your sponsor fee will be 0%.
Q: What happens if my sponsor locks more tokens mid-campaign?
A: VP is checked fresh at each individual purchase, not once per campaign. So if your sponsor moves from 2,000 VP to 3,000 VP between two of your purchases, the first purchase uses the 2% tier and the second uses the 3% tier. There is no caching or per-campaign VP snapshot.
Q: Is the campaign fee increased if I use a sponsor code?
A: No. The campaign always receives 90% regardless of sponsor tier. The sponsor fee is deducted from the 5% referral/sponsor pool only, not from the campaign’s 90% or the 5% platform fee.
Q: What if my sponsor’s VP drops below 2,000?
A: If they drop below 2,000 VP (e.g., they unlock tokens), on your next contribution the sponsor’s tier cut is 0% and the whole 10% fee settles to the treasury (on success).
Q: Can I change my sponsor code after participating?
A: The system records one sponsor per user, and the first recorded attribution is kept: registering a sponsor for a user who already has one does not replace it.
Q: Can different buyers in the same campaign have different sponsors?
A: Yes. Each buyer has their own sponsor code (either passed at purchase time or pre-registered via get_user_sponsor()). Different buyers earn reward shares for different sponsors, and each sponsor’s VP tier is checked independently per purchase.
Q: Is there a minimum sponsor code purchase?
A: Yes, sponsor codes cost 3 ICP one-time (non-refundable).
Related Documentation
Section titled “Related Documentation”- GOVERNANCE.md — VP and quadratic voting mechanics
- OHSSHII_LOCKER_INTEGRATION.md — VP calculation and OhShii Locker integration
- WORKFLOWS.md — LGE creation and token purchase workflows
- ARCHITECTURE.md — Canister interactions and fund flows
- LOGGING_SYSTEM.md — Three-tier logging architecture, stable memory log details, frontend monitoring
- GOOGLE_VERIFICATION.md — Google verification (Standard): the Internet-Identity attribute-bundle mechanism, one Google account per wallet, the address-normalisation rules, privacy model, governance controls and escape hatches.
- TELEGRAM_VERIFICATION.md — Telegram verification (Strong): the flow, the privacy model, and the veto-override attestation it now carries.
- WORLD_ID_VERIFICATION.md — World ID voter verification (Strong, legacy): flow, privacy model, configuration states including the
accepts_new_proofsretirement flag, threshold-ECDSA RP signatures, rate limits and governance controls. - DECIDEID_VERIFICATION.md — DecideID voter verification (Strong, legacy): configuration states including the
accepts_new_proofsretirement flag, the VC and OIDC paths, privacy model, rate limits and pause levers. - FRONTEND.md — Frontend architecture: React + JSX + JSDoc type-checking, the canister-types.js / utils/canister.js bridges, and the TypeScript version policy