Specification
Security Model
The points where attacks land, and what stops them.
1. Threat Surface
| Surface | Attack | Mitigation |
|---|---|---|
| Wallet adapter RPC | Frontend leaks Helius key in bundle | HELIUS_RPC_URL is server-side only; client uses NEXT_PUBLIC_SOLANA_RPC (public RPC). CI greps .next/ for the key signature, failing the build if it leaks. |
| Vault drain | Trader withdraws another holder's collateral | Vault is owned by the market PDA; only the program can call transferChecked. Each operation re-validates outcome balances. |
| Mint inflation | Anchor program mints outcome shares outside CTF | mint_authority = market_pda. The program only mints from split; merge and redeem only burn. |
| LMSR over-fill | Trader buys at stale prices to drain vault | The cost function is recomputed on chain at execution time using shares_q from the same account; an attacker cannot substitute a stale snapshot. |
| Optimistic griefing | Spam proposals to lock collateral | Bond is non-refundable on failed challenge -- griefing pays the protocol. |
| DVM bribery | Whale dominates a single dispute | Effective stake = stake x reputation. New whales have score 1.0; persistent honest voters have score up to 4.0. A first-time vote cannot out-weigh established history at parity stake. |
| Race on close | Trader splits at the deadline boundary | market.close(now) requires now >= resolution_deadline; the splits / merges check state == Open so the window cannot be straddled. |
| Token-2022 transfer hook abuse | Hostile transfer hook freezes the vault | Collateral must be a known mint without active transfer hooks. The CreateMarket instruction validates the mint's extension list. |
2. Audit-Reply Self-Tests
Pre-deploy gate (scripts/verify-audit-blocks.mjs):
- README dependency parity -- if README mentions
UMA,Pyth,Gnosis CTF,LMSR, orToken-2022, the correspondingCargo.tomlandpackage.jsonmust declare a matching dependency. - Placeholder grep -- no
// Stub,unimplemented!(),println!("would ..."),// TODO,todo!(), empty function bodies inpub fn. - Live-claim parity -- README's
live marketsclaim must match the metadata service's/markets?state=Openrow count at the time of the build. - No auto-generated comments -- no
// rev-xxx,// patch-N,// generated bymarkers.
The gate runs in CI on every push and locally before any GitHub push.
3. Bond Math
text
proposer_bond = market.resolution_source.bond
challenger_bond = matching
total_at_risk = 2 * bond
winner_payout = bond + (bond / 2) # full bond back + half loser's
loser_payout = 0
protocol_take = bond / 2 # the other half of loser's bondThe protocol-take half funds the DVM voter rewards in the same round, so honest voters are paid from griefers' bonds rather than from inflation.
4. Upgrade Authority
The Anchor program ships with a multisig upgrade authority. The signer set is published at docs/governance.md (TBD) and rotates via a 14-day timelock. The metadata service holds no signing authority over the program; it is a read-only mirror.
5. Replay & Re-org Resistance
- All state transitions key off
market_id(a u64) -- there is no nonce surface to replay. - Solana's finalisation guarantees mean that once a
split/mergeisconfirmed, the program treats it as final for accounting; the metadata service waits forfinalizedbefore mirroring trade fills into Postgres. - A re-org that rewrites a finalised block would break Solana's invariants -- the program's correctness reduces to the chain's correctness.
6. Disclosure
Security disclosures: open a private security advisory on the public GitHub repository (security/advisories/new). Bug bounties scale with severity per the matrix at docs/bounty.md (TBD).