An open, permissionless prediction market layer on Solana — implementing the pm-AMM design from Paradigm, with a Commitment Vault flow so markets can be bootstrapped by the crowd without a designated market maker.
Live on devnet → pm-amm.vercel.app
Program ID: EvWE8LGzzyZRDASKLnLBy9qZRuL8iaJYiPf2mRZh75yV
Standard AMMs (Uniswap/CPMM) are a poor fit for prediction markets. Outcome tokens pin to either 0 or 1 at resolution, so their volatility scales with both current probability and time-to-expiry. LPs face unbounded loss-versus-rebalancing (LVR) as expiry approaches — in plain english, they're guaranteed to lose.
The pm-AMM solves this with a Gaussian invariant:
(y − x)·Φ((y − x)/L) + L·ϕ((y − x)/L) − y = 0
where Φ is the standard normal CDF, ϕ is the PDF, and L is a liquidity parameter. The key property: LVR stays proportional to the pool value regardless of the current price — no more guaranteed losses near expiry.
Two variants are supported:
- Static — constant
L, predictable pricing - Dynamic —
L_t = L₀·√((T−t)/(T−t₀)), liquidity decays towards expiry so expected LVR is constant over the full horizon
Bootstrapping a prediction market is historically hard — you need an initial probability, liquidity, and trading activity from day one. Our Commitment Vault solves this in a permissionless way:
- Anyone opens a vault with a question ("Will BTC hit $150k by year-end?") and a commit phase (1 min → 7 days).
- Committers stake USDG on YES or NO during the phase. Minimum commit 1 USDG, minimum total 10 USDG.
- When the commit phase ends, anyone can call
launch_vault_market. The crowd's stake ratio sets the initial probability (e.g. 3 USDG YES / 7 USDG NO → P = 30%). A pm-AMM pool is initialized at those odds. - Committers receive fair-odds outcome tokens (
my_commit / P_my_side) plus proportional LP tokens from the pool. - If the commit threshold isn't met, committers refund their USDG 1:1.
No designated market maker, no centralized oracle for the initial price — the market price discovers itself.
programs/pm_amm/src/
├── math/
│ ├── gaussian.rs # On-chain Φ(x), ϕ(x), Φ⁻¹(x) — Abramowitz & Stegun
│ ├── invariant.rs # pm-AMM invariant, reserves, Newton-Raphson swap
│ └── fixed_point.rs # 12-decimal u128 fixed-point arithmetic
├── instructions/
│ ├── initialize_registry.rs
│ ├── create_market.rs
│ ├── initialize_pool.rs
│ ├── initialize_vault.rs # Open a Commitment Vault
│ ├── commit.rs # Stake YES/NO during commit phase
│ ├── launch_vault_market.rs # Permissionless launch at fair odds
│ ├── claim_committer.rs # Claim outcome + LP tokens post-launch
│ ├── refund_commit.rs # Refund if threshold not met
│ ├── buy_outcome_tokens.rs # 1 USDG → 1 YES + 1 NO (complete set mint)
│ ├── sell_outcome_tokens.rs # 1 YES + 1 NO → 1 USDG (merge)
│ ├── swap.rs # YES ↔ NO via Gaussian invariant
│ ├── add_liquidity.rs
│ ├── remove_liquidity.rs # Atomic pair-burn + solvency check
│ ├── resolve_market.rs
│ └── redeem.rs # Pro-rata winning payout
└── state/
├── registry.rs # Global auto-incrementing market/vault IDs
├── vault.rs # Commitment Vault + committer position
├── market.rs # Market (YES/NO mints, resolution time)
└── pool.rs # pm-AMM pool (reserves, L, fees)
All Gaussian functions are computed on-chain in fixed-point (u128 scaled by 1e12):
- PDF
ϕ(x)— Taylor series with range reduction forexp(−x²/2) - CDF
Φ(x)— Abramowitz & Stegun approximation (error < 7.5×10⁻⁸) - Inverse CDF
Φ⁻¹(p)— Beasley-Springer-Moro rational approximation - Swap resolution — Newton-Raphson on the invariant (tolerance proportional to
L, converges in 5–10 iterations)
pm-AMM's pool reserves are "virtual inventory" — they're minted by the program without a corresponding USDG deposit. To keep the system safe under adversarial swap sequences, every state-changing instruction preserves:
collateral_reserve >= |yes_circulating − no_circulating|
At redeem time, if the winning side's circulating supply exceeds the available collateral (edge case), payouts are pro-rata:
payout = winning_tokens × min(collateral, winning_circulating) / winning_circulatingSo the system is always liveness-safe — no swap can brick the pool, and resolution always terminates.
Markets use USDG (Token-2022) on devnet: 4F6PM96JJxngmHnZLBh9n58RH4aTVNWvDs2nuwrT5BP7
The program handles Token-2022 extensions (TransferFeeConfig, ImmutableOwner, CpiGuard) via the token_interface crate and computes actual-received amounts (read balance before/after) to stay solvent when transfer fees apply.
React 19 + Vite + TypeScript + shadcn/ui + Tailwind v3. Solana Wallet Adapter (Phantom, Solflare).
Pages:
/— Vaults list (browse, filter by state)/vault/create— Open a vault, choose commit/market durations (presets or custom minute input), optionally commit YES or NO from the same flow/vault/:id— Vault detail with live countdown, commit, launch, claim, refund/market/:id— Market detail with Trade panel (Buy/Sell YES or NO routed via compound tx: mint pair + swap), position sidebar, resolve, redeem
Editorial design system: Instrument Serif (display) + JetBrains Mono (data) + Inter Tight (UI). Warm cream/near-black palette with orange accents.
cd app
npm install
npm run devOpen http://localhost:5173 and connect a wallet on devnet.
- Rust + Cargo
- Solana CLI (v3.0+)
- Anchor CLI (v0.31+)
- Node.js (v18+)
anchor buildcargo test # Unit tests (math, invariant, gaussian)
anchor test # Integration tests (localnet)
node sim.mjs # pm-AMM simulator (off-chain verification)solana config set --url devnet
anchor deploy --provider.cluster devnet
cp target/idl/pm_amm.json app/src/idl/pm_amm.json- pm-AMM: A Uniform AMM for Prediction Markets — Moallemi & Robinson, Paradigm Research (Nov 2024)
MIT