About spruce.fun

Inspiration

Prediction markets are one of the most honest price discovery mechanisms ever built — they aggregate information from thousands of participants and produce probabilities that consistently outperform expert forecasts. Polymarket proved that people will trade on real-world outcomes at scale. But there was a gap: prediction markets only let you go long. You put in $100, you might get $200. There's no leverage, no shorting with margin, no sophisticated position management.

Meanwhile, perpetuals DEXes on crypto have billions in open interest — but they only let you bet on price. Bitcoin up or down. ETH up or down.

We asked: what if you could combine both? Take the richness of real-world outcomes — sports, politics, macro events — and apply the full derivatives toolkit to them. Leveraged longs, leveraged shorts, dynamic margin, liquidation waterfalls. That's spruce.fun.


What We Built

spruce.fun is a derivatives platform that brings leverage to prediction markets. Users take leveraged long or short positions on real-world outcomes that resolve at $0$ (No) or $1$ (Yes). The entire matching engine is on-chain.

On-Chain CLOB (Solana / Anchor)

Every order, match, and cancellation is an on-chain transaction — no off-chain relayer, no sequencer. The Anchor program implements price-time priority matching. When two orders cross, both sides are filled atomically and receive fungible SPL position tokens: LONG_TOKEN or SHORT_TOKEN.

Collateral is locked in USDC at order placement. For a buy order at price $p$ on quantity $q$:

$$\text{Collateral}_{\text{buy}} = p \times q$$

For a sell (short) order:

$$\text{Collateral}_{\text{sell}} = (1 - p) \times q$$

This ensures both sides are fully collateralized at all times, even before leverage is applied.

Dynamic Leverage

Leverage is not a flat cap. It scales with the risk room — the distance between the entry price and the nearest boundary ($0$ or $1$). A long position near $0$ has almost no room to fall further, so it gets capped at $1\times$. A long at $0.90$ has $0.90$ of room and can use up to $5\times$.

$$\text{leverage_cap}(p) = \left\lfloor \frac{\min(p,\ 1-p)}{0.20} \right\rfloor + 1, \quad \text{capped at } 5$$

This means leverage is a function of conviction and risk, not just account tier.

Rust Risk Engine

A standalone Axum/Tokio service sweeps all open positions every 500ms. It computes unrealized PnL against the latest mark price and checks against the maintenance margin threshold:

$$\text{Maintenance Margin} = 0.5 \times \text{Initial Margin}$$

$$\text{Initial Margin} = \frac{\text{size} \times \text{entry_price}}{\text{leverage}}$$

If a position breaches maintenance, it enters a three-stage liquidation waterfall: partial close to restore IM, full close if still undercollateralized, and ADL (auto-deleveraging) against profitable opposing positions as a last resort.

Market Data Layer

A Node.js backend maintains persistent WebSocket connections to Polymarket, streams live orderbook snapshots, and aggregates OHLCV candles in real time. Candles are persisted to Supabase (Postgres). The frontend subscribes to this stream to render live charts without polling.


Challenges

Collateral math at the boundary. Near $p = 0$ or $p = 1$, tiny price moves represent enormous percentage swings. Getting the collateral formula right so that neither side is ever undercollateralized at the extreme required careful modeling — and getting it wrong would mean the program could be drained.

On-chain account sizing. Solana accounts have fixed size at creation. Fitting the orderbook state (buy orders, sell orders, position records, trade history) into a single account with a deterministic PDA layout, while staying under the 10MB account size limit and keeping compute units reasonable, required iterating on the data layout multiple times.

Real-time margin at 500ms. Rust async with tokio made the risk engine fast, but coordinating shared mutable position state across the monitor loop and the HTTP handler threads without locking required using DashMap for lock-free concurrent access.

Quadratic voting UX. Explaining to users why casting 10 votes costs 100 tokens — not 10 — without losing them is genuinely hard. The math is elegant, the UX is not.


What We Learned

Prediction markets and derivatives are more complementary than they look. A prediction market gives you a clean, binary, time-bounded underlying. A derivatives layer on top gives you leverage, shorting, and composability. The combination is a new primitive: leveraged exposure to real-world truth.

Share this project:

Updates

Submission history