The first prediction market where every position is encrypted until settlement. Nobody can see your bet — not even us. Powered by Arcium MPC + ZK proofs on Solana.
3
Market types
$1–$100
Accuracy tiers
100%
Pre-settlement private
ZK
Verified payouts
// market types
Three ways to play
Each market type has different stake rules and payout math. Same privacy guarantee across all — your prediction is encrypted the moment you submit it. All bets go into a single unified pool per market — the pool address reveals nothing.
Payout: winning pool splits all losing pools proportionally
Unified pool — outcome hidden
BINARY + MULTI — VARIABLE STAKES
Bet $5, $50, or $500. Bigger stake on winning side = bigger share of loser pool. 2% fee on total: 1.5% creator + 0.5% protocol.
ACCURACY — FIXED TIERS ONLY
Everyone in the same tier pays the exact same fee. Stake size has zero effect — only prediction accuracy determines payout. 20% platform fee on loser pool.
// accuracy tiers
Accuracy market. Three isolated lobbies.
Accuracy markets only. Same question, separate pools. $1 bettors compete against $1 bettors. Skill wins — not wallet size.
$1
Micro lobby
Low stakes, high volume
Learn the platform
Isolated from $10/$100
1_000_000 USDC (6 decimals)
$10
Standard lobby
Core accuracy product
Deepest participation
Most active pools
10_000_000 USDC (6 decimals)
$100
Whale lobby
High conviction
Bigger prize pool
Isolated from lower tiers
100_000_000 USDC (6 decimals)
// data flow
From bet to payout
Every step for all three market types. What the user sends, what goes on-chain, what the backend stores, what the contract executes.
YesNo + MultiOutcome: 1 unified pool · Accuracy: 3 pools (one per tier $1/$10/$100) · Pool address reveals nothing about prediction
👤 creator — admin setup (once)
// run once at deploy
await program.methods.initialize(50, 150, 2000).rpc()
// 50 = 0.5% protocol fee (YesNo/Multi on total pool)
// 150 = 1.5% LP fee (YesNo/Multi on total pool)
// 2000 = 20% accuracy fee (accuracy on loser pool only)
await program.methods.initYesnoCompDef().rpc()
await program.methods.initMultioutcomeCompDef().rpc()
await program.methods.initAccuracyCompDef().rpc()
// YesNo market
👤 creator — YesNo
await program.methods.createMarketGroup(MarketType.YesNo, MarketCategory.Crypto,
"Will BTC close above $100k on Friday?",
OracleType.Pyth, lock_timestamp, resolve_deadline, []
).rpc() // locks $10 bond
await program.methods.createFlatMarket().rpc() // bet_size=0, variable stakes
await program.methods.createPool(0, PoolType.Unified).rpc() // ONE pool — all bettors
// MultiOutcome market
👤 creator — MultiOutcome
await program.methods.createMarketGroup(MarketType.MultiOutcome, ...,
outcome_labels: ["Real Madrid","Arsenal","Bayern","PSG"]).rpc()
await program.methods.createFlatMarket().rpc() // same as YesNo
await program.methods.createPool(0, PoolType.Unified).rpc() // ONE pool — all outcomes
// Accuracy market
👤 creator — Accuracy
await program.methods.createMarketGroup(MarketType.Accuracy, ...,
"SOL price at Friday close?").rpc()
// 3 tier markets — each has fixed bet_size, called 3 times
await program.methods.createTierMarket(Tier.Micro).rpc() // $1 bet_size=1_000_000
await program.methods.createTierMarket(Tier.Standard).rpc() // $10
await program.methods.createTierMarket(Tier.Whale).rpc() // $100
// each tier gets its own pool — user picks tier, NOT prediction
await program.methods.createPool(0, PoolType.Accuracy).rpc() // $1 pool
await program.methods.createPool(0, PoolType.Accuracy).rpc() // $10 pool
await program.methods.createPool(0, PoolType.Accuracy).rpc() // $100 pool
⛓ on-chain after creation
MarketGroup PDA status: Open bond: $10 locked
Pool PDA seeds: ["pool", market, 0]
pool_type: Unified // same for all bettors — side hidden
vault: UNIFIED_VAULT // all USDC escrowed here
total_staked: 0 participant_count: 0 status: Open
🤖 backend DB
INSERT INTO markets (pubkey, question, type, status, lock_timestamp, creator)
VALUES ('GROUP_PK', 'Will BTC close above $100k?', 'yesno', 'open', 1748890000, 'CREATOR')
📱 frontend GET /markets
{ question: 'Will BTC close above $100k?', status: 'open', total_volume: '$0' }
// UI: "Betting open · locks in 2h 14m · $0 in pool"
// no YES/NO split — sides are private until settlement
// protocol spec
Every moving part
All 25 on-chain instructions, the complete backend surface, and every account the protocol creates.
frontendbackendarciumadminanyone
admin — run once at deploy (4)
#
instruction
caller
what it does
1
initialize
admin
Creates global CyperMarket PDA. Sets fee bps, treasury, authority.
2
init_yesno_comp_def
admin
Registers YesNo equality-check circuit with Arcium.
Emits errors (not winner flags). Updates registry. No fees — sent via accuracy_send_fees.
payout + cleanup (5)
#
instruction
caller
what it does
21
accuracy_send_fees
backend
Accuracy only. Sends 20% platform fee of loser pool to treasury after backend computes loser count.
22
write_position_payout
backend
Writes computed payout to one Position PDA. Called once per position. Idempotent — safe to retry.
23
claim_payout
frontend
User pulls USDC from pool vault to wallet. Only works if position.status == Settled.
24
return_bond
frontend
Creator reclaims $10 bond after group.status == Settled.
25
slash_bond
anyone
Permissionless. Sends bond to treasury if creator missed resolve_deadline.
// architecture
What lives where
Four layers. Solana handles money and state. Arcium decrypts only what needs to be secret. Backend handles coordination and math. Your device handles encryption.
// hybrid architecture — Arcium equality checks only
user device + oracle
User wallet
Encrypts prediction with MXE pubkey. Never sent as plaintext.
Every prediction is encrypted with the Arcium MXE public key client-side in your browser before it's submitted. The encrypted blob is stored on-chain. Nobody — not other users, not validators, not even Cypher — can decrypt it without the MXE's private key shards, which are split across multiple MPC nodes and only combined inside the secure computation at settlement.
What stops a creator from posting a wrong resolution?+
Three things: a $10 USDC bond (slashed if they misbehave), a 1-hour dispute window after any resolution, and Pyth on-chain price feeds for crypto markets which require no human input at all. For custom markets, the bond + dispute window is the protection layer.
How many outcomes can a multi-outcome market have?+
Between 2 and 4 outcomes in v1. All bettors go into one unified pool — the pool address reveals nothing about which outcome you picked. Only Arcium decrypts the outcome at settlement.
Can I bet any amount on binary and multi-outcome markets?+
Yes — binary and multi-outcome markets have variable stakes. You choose any amount above a small minimum. The more you stake on the winning side, the larger your proportional share of the loser pool. Accuracy markets are different — they use fixed entry fees per tier ($1/$10/$100) so skill, not wallet size, determines your payout share.
What token is used?+
USDC only, across all market types. Stable value means your $10 bet is worth $10 at settlement. If you only have SOL, swap on Jupiter first — one click, 5 seconds.
How does settlement scale to many users?+
Settlement uses parallel sharding. Positions are grouped into shards of 8. Each shard runs as a separate Arcium job simultaneously. A SettlementRegistry on-chain accumulates results as jobs complete. For 10,000 users that's 1,250 parallel jobs — wall-clock settlement time stays roughly constant.
What happens if nobody bets on the winning side?+
Edge case handled — if winner_count is 0, the entire net pool goes to protocol treasury to prevent permanent fund lock. For accuracy markets this cannot happen — the top ~50% always win by definition of the median cutoff.
Is the contract upgradeable?+
Yes, with a multisig upgrade authority. No single key can upgrade the program. All accounts have reserved padding bytes so upgrades don't require migrating existing market data.
How do I run the project locally?+
Install Bun from bun.sh, then: bun install && bun run dev. The math simulator runs at localhost:3000 and the site at localhost:3000/site. No environment variables needed for the simulator.