Curva Documentation
A serverless, peer-to-peer football prediction market.
Overview
Curva lets a group of fans run a real-money prediction market among themselves — no server matching bets, no oracle company calling the result, no custodian holding the money.
Everyone “knows” a prediction market needs three centralized things: a matching engine, an oracle, and a custodian. Curva removes all three. Every peer holds one append-only log of bets; the market only exists in the aggregate of the swarm. Kill any machine — including the one that created the market — and the market keeps trading.
How it works
The end-to-end flow of a single terrace (a match market), exactly as npm run demo exercises it, headless and with no network:
- Derive — each fan turns a WDK seed phrase into an identity key (signs every message) and a self-custodial USDt wallet.
- Open a terrace — a host opens a market for tonight's match and shares an invite key. Others join the swarm.
- Trade — fans place bets; the parimutuel pool odds shift live on every screen. Each bet is a signed message appended to that peer's log.
- Kill the host — the peer that created the market goes offline. The others keep trading and still converge. There is no host.
- Cutoff — at kickoff the market locks. Autobase's deterministic linearization is the single ordered fence; late bets after the fence are dropped.
- Resolve — at full time, each device's on-device ASR hears the score from the commentary and pre-fills an attestation. The crowd signs a dual-⅔ quorum; after a dispute window the outcome is final.
- Net & settle — the payout manifest is netted to a minimal transfer set; each loser signs their own USDt transfer from their own wallet. Receipts land on every log — everyone's square.
The insight: a parimutuel pool is a CRDT
This is why Curva can be serverless without consensus:
- Merge order doesn't matter. Pool totals are sums; sums are commutative and associative. The payout is a pure function of
(final bet-set, resolved outcome). Any permutation, partition, or merge of the same bets yields identical pools and payouts — so network partitions heal for free. - Only the cutoff needs order. The one thing requiring a total order is the betting deadline, and Autobase's deterministic linearization gives exactly that one primitive — the fence — and nothing more.
- Settlement is just netting. Self-custody + parimutuel means no pot to hold: compute the minimal set of transfers and each debtor signs their own.
Architecture
Ports-and-adapters throughout: everything money- or consensus-related is pure and fuzz-tested; Pears/QVAC/WDK live behind adapters with in-memory fakes, so the whole protocol is testable headless in Node with no Pear, no model, no wallet, and no network.
| Package | Responsibility |
|---|---|
@curva/market-kernel | Pure parimutuel core — odds, payouts, refunds, void. Exact conservation via largest-remainder dust (no treasury). |
@curva/terrace-base | Signed-message protocol · deterministic apply() fold · Hyperbee view · cutoff fence · Autobase multi-writer runtime. |
@curva/crowd-oracle | Quorum math (dual ⅔ + dispute→void) and QVAC ASR score extraction. |
@curva/wdk-vault | Seed → identity + wallet · minimal-transfer netting · USDt settlement. |
@curva/market-catalogue | Market factories — match-result, total-goals ladder, micro-rounds, first-scorer, correct-score. |
@curva/qvac-surfaces | The Gaffer (local LLM commentator) · terrace translate · hunch suggestions. |
@curva/steward-escrow | Tier-2 2-of-3 escrow — steward election, deposit verify, co-signing. |
@curva/terrace-ui | The app's tested render layer — view-models + formatters + the single HTML-escaping choke-point. |
@curva/sim | Lamport-ordered swarm simulator + adversarial fuzzer. |
@curva/e2e | The whole pipeline, headless (npm run demo). |
apps/terrace | The Pear desktop app — a thin DOM shell over @curva/terrace-ui. |
The three tracks
Each track is structurally load-bearing — remove any one and the product ceases to exist.
Pears — the market
Hyperswarm discovery, an Autobase multi-writer ledger with a deterministic apply fold, a Hyperbee view of market state, the cutoff fence, and pear for deployment. This is the exchange; there is no server.
QVAC — the oracle
On-device speech-to-text over the match commentary extracts the score and pre-fills attestations; a local-LLM “Gaffer” adds commentary; chat is translated locally across 32 languages. Zero cloud AI — a mic in a pub demands local inference.
WDK — the money
One seed derives the HD identity key that signs every message and the self-custodial USDt wallet. Payouts net to a minimal transfer set; each loser signs their own transfer; receipts append to the log.
noble, which keeps the protocol pure and Bare-runnable — WDK is load-bearing only for moving USDt.The crowd oracle
At watch-party scale the oracle problem dissolves: everyone is literally watching the answer. Curva makes that safe with a dual ⅔ quorum — an outcome resolves only when it holds two-thirds of both the stake and the writers. This makes it mathematically impossible for two outcomes to both reach quorum, so neither a whale nor a sock-puppet swarm can steer the result.
ASR is a pre-fill assist, never authority — a wrong or unheard score is always one manual tap away from correction. A dispute window (evaluated per-timestamp-batch, not per-event) lets the crowd contest a result; unresolved disputes void the market and refund every stake.
Trust & escrow
Curva is honest about its trust tiers:
- Mates Mode (default) — a small pool of people who know each other. Fast, frictionless, and the collusion risk is the same one that already exists at any pub table.
- Tier-2 escrow — a shipped 2-of-3 steward escrow (election, deposit verification, co-signing) for pools among people who don't all trust each other.
- Tier-3 (roadmap) —
t-of-nthreshold custody (FROST/MuSig2) so the swarm itself is the custodian, with no distinguished stewards.
What's proven, not asserted
237 tests run in CI — property, fuzz, quorum-safety, view-model, and a full headless end-to-end:
- Conservation — Σ payouts + Σ fees ≡ Σ stakes, exactly, for arbitrary bet sets.
- Commutativity (the CRDT claim) — any permutation, partition, or merge yields identical pools, odds, and payouts.
- Convergence under fuzz — 100 randomized runs of interleavings, writer churn, partitions/heals, late bets, double-attests, and whale stakes all heal to one byte-identical view.
- Quorum safety — the dual ⅔ threshold makes two outcomes reaching quorum impossible.
- Netting soundness — the transfer set settles every party exactly in ≤ n−1 edges.
Run & build
# the whole thesis, headless, no external services npm install npm run demo # typecheck + lint + 237 tests (Node ≥20.19 / 22.12 / 24) npm run check # the live P2P app (needs the Pear runtime: npm i -g pear) npm run build && pear run apps/terrace
The demo uses in-memory fakes for the wallet and ASR (clearly labelled in-app), so the entire claim is verifiable without Pear, a QVAC model, a funded wallet, or a network. Swapping in the real WDK/QVAC adapters is a configuration change, not a protocol change.
FAQ
Is there really no server?
No server. Peers discover each other over Hyperswarm and each holds the full append-only ledger. The only external service in real mode is a chain RPC endpoint to broadcast USDt transfers — no backend, no cloud AI, no analytics.
What stops someone double-spending or resolving falsely?
Bets are signed and folded deterministically; the cutoff fence drops late bets; and the dual-⅔ quorum plus dispute→void protects resolution. In adversarial (non-mates) settings, the 2-of-3 escrow tier adds custody guarantees.
Can I run it in a browser?
The live app runs on the Pear runtime, not a plain browser (it uses Bare modules like Autobase and Hyperswarm). A zero-install browser demo of the UI on fake adapters is on the roadmap.