Threat Model#
Detailed analysis of attack surfaces and mitigations.
Adversary Model#
Capabilities#
| Capability | Description | Risk Level |
|---|---|---|
| Arbitrary Transactions | Can submit any valid Solana tx | High |
| Sybil Accounts | Can create unlimited wallets | Medium |
| Flash Loans | Large capital for single tx | Medium |
| MEV Extraction | Frontrun/sandwich attacks | Medium |
| Market Manipulation | Trade to move prices | Medium |
Limitations#
| Limitation | Assumption | Confidence |
|---|---|---|
| Forge Signatures | Ed25519 secure | Very High |
| Break Pyth | Oracle honest | High |
| Control Solana | Network honest | High |
| Infinite Capital | Finite per tx | High |
Trusted and Semi-Trusted Roles#
| Role | Trust Level | Powers | Explicit Non-Powers |
|---|---|---|---|
| Config authority | Semi-trusted | Bounded governance updates, fee/treasury configuration, pauser rotation, emergency ops | Cannot seize user collateral; token destinations remain validated by instruction |
| Pauser guardian | Semi-trusted | Global Pause; may impose or raise per-market emergency severity | Cannot Unpause, cannot call SetPauser, cannot clear or lower emergency severity |
| Market creator | Limited | Market-scoped cap updates and creator-scoped PostOnly toggles | Cannot impose admin Paused/ForceCancelOnly; cannot redirect refunds |
| Crank operators | Permissionless | Lifecycle transactions and closer-reward collection | Cannot change outcomes or user destinations |
Attack Surfaces#
1. Instruction-Level Attacks#
| Instruction | Attack Vector | Mitigation |
|---|---|---|
| create_market | Spam creation | Rent cost limits |
| place_order | Orderbook manipulation | Solvency constraints |
| place_order | Self-trade wash | Self-trade prevention |
| cancel_order | Unauthorized cancel | Owner signature |
| snapshot_* | Oracle manipulation | Pyth security |
| resolve_market | Wrong outcome | Deterministic logic |
| redeem | Double claim | Settled flag |
| close_market | Premature close | All-settled check |
2. Economic Attacks#
| Attack | Description | Mitigation |
|---|---|---|
| Naked Short | Sell without owning | Balance validation |
| Undercollateralized Buy | Buy without funds | Collateral locking |
| Oracle Front-running | Trade on future prices | Pyth latency |
| Market Corner | Accumulate to manipulate | No position limits (v1) |
3. Protocol-Level Attacks#
| Attack | Description | Mitigation |
|---|---|---|
| Reentrancy | Callback during execution | Solana locks, no callbacks |
| Integer Overflow | Arithmetic overflow | Checked math |
| PDA Collision | Same PDA, different purpose | Unique seed prefixes |
| Account Confusion | Wrong account type | Discriminator checks |
| Rent Drain | Force account closure | Rent-exempt accounts |
| Issuer Freeze | Settlement token issuer freezes a market vault or user ATA | Accepted settlement-asset tail risk; monitor and rotate defaults for new markets |
4. Operational Attacks#
| Attack | Description | Mitigation |
|---|---|---|
| Crank DoS | Prevent lifecycle | Multiple operators |
| Treasury Drain | Exhaust crank rewards | Capped rewards |
| State Bloat | Create many accounts | Rent costs |
| Pauser Key Abuse | Escalate halt state unnecessarily | Pauser cannot unpause, clear, or lower emergency state; authority rotation runbook |
Detailed Mitigations#
Reentrancy Protection#
Solana's runtime provides inherent protection:
- Account Locking: All accounts locked for transaction
- No Recursive CPI: Cannot borrow mutably twice
- No Token Callbacks: Unlike ERC-777, SPL Token has no hooks
- Idempotency: Settlement checks
settledflag first
Oracle Security#
Price validation applies the following checks to every oracle reading before it is accepted:
- Positive price: the price must be greater than zero, otherwise the reading is rejected (
InvalidPrice). - Published after the boundary: the reading's
publish_timemust be at or after the relevant snapshot boundary, otherwise it is rejected as stale (StaleOracle). The reading'sprev_publish_timeis also used to prove it is the first price at or after the boundary (Sampling Rule A). - Optional confidence gate: when a confidence limit is configured, the ratio of the reading's confidence interval to its price must fall within that limit, otherwise the reading is rejected.
The protocol reads the Pyth PriceUpdateV2 account directly at fixed byte offsets (it does not depend on a Pyth client SDK), verifies the account's discriminator and verification level, then extracts the price, confidence, exponent, and timestamps before applying the checks above.
Solvency Enforcement#
Invariant:
vault.balance >= max(total_yes_shares, total_no_shares) + accumulated_creator_fees
Known Considerations and Mitigations#
This section calls out subtle risk areas integrators sometimes ask about, and how the protocol handles each.
Oracle Price Staleness#
Consideration: Stale Pyth prices could affect how a market resolves.
How it is handled: Sampling Rule A requires the first price at or after each boundary:
- Start snapshot:
publish_time >= t_start - End snapshot:
publish_time >= t_end
A reading published before the boundary is rejected, and the candidate's predecessor timestamp is used to confirm it is the first qualifying price.
Settlement Double-Claim#
Consideration: A user might try to settle the same position more than once.
How it is handled: Each position carries a settled flag that is checked first; once settled, further settlement calls are no-ops with no additional payout. See the idempotency code in Architecture Security → Reentrancy Protection.
Crank Liveness#
Consideration: A market could stall if no one performs its lifecycle operations (snapshotting, resolution, settlement).
How it is handled: All lifecycle operations are permissionless and reward-incentivized, so anyone can perform them, and multiple independent operators are expected. A force-close fallback exists for positions in markets that are not resolved within the expiration window.
Settlement-Token Issuer Freeze#
Consideration: The current Solana beta uses a single settlement mint per market. If that mint has an active freeze authority, the issuer can freeze a market vault PDA or a user's associated token account. A frozen treasury recipient can be bypassed by routing protocol fees to another configured recipient shard, but a frozen market vault or payout destination blocks the affected SPL Token transfer until the issuer unfreezes the account.
How it is handled: This is an accepted settlement-asset tail risk, not an on-chain bug. The program cannot override an issuer freeze. Operators must:
- monitor live market vault addresses and known payout/treasury addresses against the issuer's freeze or blacklist surface;
- keep a tested stablecoin-default rotation path for new markets via
UpdateMarketDefaults (0x32); - communicate that affected redemptions or fee claims are blocked by the settlement token program until unfreeze, while unrelated markets continue normally;
- treat per-asset settlement allowlists and multi-mint risk controls as a v-next structural improvement.
Epoch Boundary Race#
Consideration: Clock drift near epoch boundaries could create timing gaps.
How it is handled: Boundaries use inclusive comparisons (>=), so there is no gap between consecutive epochs.
Price Conversion Precision#
Consideration: Converting NO-side quotes to the canonical YES book could lose precision.
How it is handled: Conversions use exact integer arithmetic with protocol-favorable rounding, backed by extensive test and property-test coverage.
Known Limitations (v1)#
| Limitation | Description | Future |
|---|---|---|
| No position limits | Unlimited accumulation | Add optional limits |
| Single oracle | Only Pyth | Multi-oracle support |
| Deep orderbook tiers | 64-4096 orders per side per market | Add larger tiers after measured demand |
| Full collateral | No leverage | Add margin |
What to Expect If an Issue Occurs#
Because every protocol rule is enforced on-chain, a transaction that would violate an invariant simply fails rather than committing bad state. For broader issues, the protocol exposes safety controls and a disclosure process you can rely on:
- Trading can be halted. The protocol can be paused globally (
Pause) or restricted per market (SetMarketEmergencyStatus, including a post-only mode that lets makers cancel but blocks new aggressive flow). The separate pauser guardian is escalation-only: it can halt or make a market more restrictive, but it cannot unpause, clear emergency state, or rotate itself. Pausing stops new trading while a fix is prepared; it does not seize user funds. - Funds remain fully collateralized. Every share is backed by collateral held in the market vault, and solvency is enforced at runtime, so a pause or delay does not put deposited collateral at risk.
- Markets have a force-close fallback. Positions in a market that is not resolved within its expiration window can be force-closed permissionlessly, so funds are not stranded if normal lifecycle operations stall.
- Vulnerabilities are handled under responsible disclosure. If you find a security issue, report it privately (see Reporting Vulnerabilities) and allow time for a fix before any public disclosure.
Next Steps#
- Review Invariants for formal guarantees
- See Architecture Security for implementation