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 |
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 |
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 |
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.
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 |
| 63 order limit | Per side per market | Expand capacity |
| 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). 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