Skip to content

Sponsor System

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 × k ICP; ≈25 ICP at the 500-ICP default raise, scaling with the creator-chosen 500 × k target) 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_governance canister 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%, backend keeps 10%
  • VP ≥ 2,000: sponsor earns 2%, backend keeps 8%
  • VP ≥ 3,000: sponsor earns 3%, backend keeps 7%
  • VP ≥ 5,000: sponsor earns 5%, backend keeps 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.

This mechanism aligns sponsor incentives with governance participation: sponsors must lock OHSHII tokens (to gain VP) and remain active voters to earn — and keep — higher reward shares. The VP formula is:

VP = sqrt(token_amount) × lock_duration_months

(Derived from OhShii Locker’s quadratic voting power calculation.)


The sponsor system is integrated into two separate fund allocation flows:

When a user creates an LGE campaign and pays the creation fee (5 ICP base + variable token cost), the backend:

  1. Extracts the sponsor code from ICOInit.sponsor_code — this is the LGE creator’s referrer (the person who referred the creator)
  2. Looks up the referrer’s sponsor info in dao_storage canister
  3. Calls get_sponsor_fee_percent_by_vp() to fetch the referrer’s current VP and compute their reward share percentage
  4. Splits the 10% token-cost fee between the referrer (sponsor) and backend treasury
  5. 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:

  1. Extracts the sponsor code from the purchase request parameter, or falls back to the buyer’s stored sponsor via get_user_sponsor()
  2. Resolves the sponsor info upfront (single call to get_sponsor_info)
  3. Fetches the buyer’s individual referrer’s VP via get_sponsor_fee_percent_by_vp() (single call to lock_storage)
  4. 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
  5. 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 on dao-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’s sons_governance canister 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”.

Token-math basis (new campaigns): for campaigns created after the escrow custody change, the bonding-curve input is the net that funds the LGE (gross minus fees and ledger overhead), keeping tokens_sold ↔ pooled ICP consistent. Pre-existing campaigns keep the original gross basis unchanged. This is internal to token-amount accounting and does not change 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.

Source: dao_storage canister

  • Method: get_sponsor_info(sponsor_code: String) → Option<SponsorInfo>
  • Returns: Sponsor’s principal, total earnings, and referral history

Flow:

Yes

User provides sponsor_code

Backend calls dao_storage::get_sponsor_info(sponsor_code)

Found and valid (not self-sponsored)?

Extract sponsor_principal

Call lock_storage::calculate_quadratic_voting_power(sponsor_principal, OHSHII_token)

Map VP to fee percentage via get_sponsor_fee_percent_by_vp()

Source: lock_storage canister (OhShii Locker)

  • Method: calculate_quadratic_voting_power(principal: Principal, token_id: Principal) → QuadraticVotingPowerResult
  • Calculation: VP = sqrt(token_amount) × lock_duration_months

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

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_referral claim on the campaign’s sons_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 treasury
referral_band_e8s = (token_cost_e8s * 50) / 1000; // full 5%, HELD per-campaign
sponsor_fee_e8s = (token_cost_e8s * sponsor_fee_percent_permille) / 1000; // 0–5%, SNAPSHOTTED tier cut inside the band

The campaign_e8s = token_cost - platform - sponsor - admin arithmetic that paid the campaign the residual after an immediately-transferred sponsor cut belongs to the dead immediate-pay branch (referral_deferred = None). On 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.

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).


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 RangeReward share %Treasury share (on success)Campaign GetsNotes
No code provided10%90%No sponsor to pay; on success the full 5% band settles to treasury
< 2,000 VP0%10%90%Sponsor not yet qualified; on success the full 5% band settles to treasury
≥ 2,000 VP2%8%90%Minimum tier; sponsor claims 2% of the held 5% band on success
≥ 3,000 VP3%7%90%Mid tier; sponsor claims 3% of the held 5% band on success
≥ 5,000 VP5%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.


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 (around line 16329).

async fn get_sponsor_fee_percent_by_vp(sponsor_principal: Principal) -> u64 {
let lock_storage = match Principal::from_text(LOCK_STORAGE_ID) {
Ok(p) => p,
Err(_) => return 0, // Safe fallback: if lock_storage ID invalid, sponsor gets 0%
};
let ohshii_token = match Principal::from_text(OHSHII_CANISTER_ID) {
Ok(p) => p,
Err(_) => return 0, // Safe fallback
};
// Fetch VP from lock_storage (single inter-canister call)
let vp_result: Result<(QuadraticVotingPowerResult,), _> =
ic_cdk::call(lock_storage, "calculate_quadratic_voting_power",
(sponsor_principal, ohshii_token)).await;
let vp = match vp_result {
Ok((result,)) => result.quadratic_voting_power.round() as u64,
Err(e) => {
// Log failure and return safe default
store_ico_log(None, Some(sponsor_principal),
format!("⚠️ Failed to fetch VP for sponsor {}: {:?}. Defaulting to 0% sponsor fee.",
sponsor_principal, e),
"warning");
return 0; // Safe default: if VP fetch fails, no reward share
}
};
// Map VP to fee tier (per-mille, divide by 10 for display %)
if vp >= 5000 { 50 } // 5%
else if vp >= 3000 { 30 } // 3%
else if vp >= 2000 { 20 } // 2%
else { 0 } // 0%
}

Key characteristics:

  1. Single inter-canister call: Directly calls lock_storage::calculate_quadratic_voting_power(). No multi-hop queries; no caching of VP (always fresh).
  2. Safe fallback: If lock_storage is unreachable or principal cannot be parsed, returns 0 (sponsor earns nothing).
  3. Per-mille encoding: Fee percentages stored as 0, 20, 30, 50 (representing 0%, 2%, 3%, 5%). Divide by 10 for display.
  4. Logged failures: All VP fetch failures are recorded in LGE logs for debugging.

Sponsor codes are presented as optional fields in all participation flows:

  • LGE creation form (CreateICOForm): Optional “Sponsor Code” field
  • Token purchase form (TokenPurchaseForm): Optional “Sponsor Code” field with explanatory text
  • Reserved purchase form (ReservedPurchaseForm): Optional sponsor field

Info text displayed to users:

“If no sponsor code provided, the full 10% platform fee remains in the OhShii treasury to support ecosystem development.”

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.


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.

if provided

Individual transaction (e.g., User contributes 100 ICP to campaign)

Backend receives payment

Sponsor code lookup (per-transaction: from request param or buyer's stored sponsor)

Get sponsor principal → Fetch sponsor VP from lock_storage (fresh, not cached)

Determine fee tier: {0%, 2%, 3%, 5%}

Resolve fee split (BEFORE any funds move — resolve_escrow_split)

Total fee = 10 ICP (always 10%)

Platform fee: 5 ICP (always goes to treasury· also absorbs the per-leg ledger fees)

Referral band: 5 ICP (FULL band, held per-campaign)

snapshotted sponsor tier cut: 0–5 ICP (by VP, recorded for later settlement)

Campaign: clean 90 ICP

AT PURCHASE — forward the 3 escrow legs (from_subaccount = Some(escrow))

1. Campaign subaccount (clean 90 ICP) → via pool_manager

2. OhShii treasury (5 ICP platform band, minus the per-leg ledger fees)

3. Per-campaign referral subaccount on pool_manager (FULL 5 ICP referral band — HELD)

no sponsor transfer here· the band waits for the LGE outcome

Log fee allocation and transfer block heights

AT OUTCOME — settle the held referral band

SUCCESS → register the snapshotted tier cut as a claim_referral claim on the campaign's sons_governance (sponsor claims within 7 days)· remainder → OHSHII treasury

FAILURE → the entire held 5% is refunded to buyers (each contributor recovers 95%)


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. A purely immediate-pay example is shown last, explicitly labelled legacy.

User A contributes 100 ICP to campaign X, no sponsor code.

Contribution: 100.0 ICP
Total 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 ICP
At 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 ICP
Total 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 ICP
At 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 ICP
Total 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 ICP
At 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 ICP
Total 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 ICP
At 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)

Example 5 (legacy, referral_deferred = None — NOT used by any live campaign)

Section titled “Example 5 (legacy, referral_deferred = None — NOT used by any live campaign)”

The original immediate-pay branch transferred the sponsor’s tier cut to the sponsor’s account at purchase time, paid the campaign the residual, and never held a band. It survives in the code as process_fees_for_reserved_purchase() but has no live call sites; it is shown here only for historical context.

LEGACY immediate-pay — User contributes 100 ICP, sponsor at 5% tier:
├─ Platform fee (5%): 5.0 ICP → treasury
├─ Sponsor (5%): 5.0 ICP → sent to sponsor's account AT PURCHASE
└─ Campaign: 90.0 ICP
No band is held; on failure the campaign's 90% is refunded but the already-paid sponsor cut is not recoverable.

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 referral subaccount. 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 is registered as claim_referral claims on the campaign’s sons_governance; sponsors claim their cut there within 7 days; the unearned remainder of the 5% drains to the OHSHII treasury. 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.
  • On failure: the entire held 5% is refunded to buyers — see the Failure path below.

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_storage USER_SPONSORS map, the sponsor’s referrals list, and the SPONSOR_USERS_INDEX) once the invited user is verified in governance (World ID or DecideID, via ohshii_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 is unverified, 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 (reusing the is_verified flag already returned by get_lge_eligibility); 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 flow (register_world_id_verification / register_decideid_verification, both accepting an optional sponsor_code) also confirms a pending connection right after a successful verification.

The frontend already defers attribution for unverified users (it checks is_verified before calling set_user_sponsor, and otherwise saves the code as pending). The corresponding on-canister enforcement — a purchase-time is_verified gate in resolve_escrow_split, piggyback_set_user_sponsor, and the standalone set_user_sponsor so the rule cannot be bypassed via a direct call — ships together with the deferred-referral canister deployment.


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%

VP thresholds and reward share percentages are planned to be governance-configurable via ONS (OHSHII Governance) proposals. This allows the DAO to:

  • Adjust VP thresholds (e.g., lower to 1,500 VP for 2% tier)
  • Introduce new tiers (e.g., 0.5% at 1,000 VP)
  • Modify maximum reward share (e.g., reduce from 5% to 4%)

Implementation will add a SponsorFeeConfig struct to stable memory, readable and writable only via proposal execution.

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 no longer gates 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_referral on the campaign’s sons_governance after a successful LGE, paying min(registered_claim, subaccount_balance − fee). 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. (The legacy figure of 20,000 e8s / 0.0002 ICP for a purchase-time sponsor transfer applied only to the dead immediate-pay path.)


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.

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%“

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) — 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.

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.”


MethodCalled byPurpose
get_sponsor_info(code)allocate_ico_funds, process_fees_for_reserved_purchaseResolve 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)”
MethodCalled byPurpose
calculate_quadratic_voting_power(principal, token_id)get_sponsor_fee_percent_by_vp()Fetch sponsor’s OHSHII voting power
MethodCalled byPurpose
set_user_sponsor(caller, code)User (via form)Register a user with a sponsor code
MethodCalled byPurpose
get_sponsor_info(code)SponsorSystem.jsxDisplay sponsor details (earnings, tiers)
get_sponsor_code_by_principal(principal)SponsorSystem.jsxCheck if user has a sponsor code

To test sponsor fee tiers locally:

  1. Create a sponsor code (3 ICP fee in local environment)

  2. Lock OHSHII tokens to build VP:

    • Use OhShii Locker (locker app running locally) to lock test tokens
    • VP = sqrt(amount) × months, e.g., sqrt(4000000) × 12 = 2,400 VP (3% tier)
  3. Create an LGE with sponsor code and verify:

    • Fee split in allocation logs matches expected tier
    • Sponsor receives correct payment
    • Storage records sponsor payment
  4. Test edge cases:

    • VP fetch failure: Mock lock_storage to return error; verify 0% fee
    • Self-sponsorship: Use your own sponsor code; verify 0% fee
    • Small sponsor fee: Contribute a small amount; verify minimum threshold check
  • Sponsor VP is live (calculated from real locked OHSHII)
  • Reward changes only when sponsor locks/unlocks tokens or time-gated locks expire
  • VP is not cached; each transaction recalculates current VP (ensures fairness)

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), your next contribution will be split 10% to backend, 0% to sponsor.

Q: Can I change my sponsor code after participating?

A: The current system supports one sponsor per user. To switch sponsors, you would need to contact support or use governance proposals to reset your referrer.

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).


  • 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
  • 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 type-checking, the canister-types.js / utils/canister.js bridges, and the TypeScript version policy