Docs

ProofBook is a prediction market where settlement is a cryptographic proof, not a decision. Everything below exists so you can check that claim yourself.

Verify it yourself in one command

Pick any receipt on this site, copy its market address, and run:

npx @h4rsharma/txline-settle verify <marketPda>

Five steps, none of which trust ProofBook: the settlement and its predicate are read from the Solana account, the merkle root from TxLINE’s own on-chain PDA, the proof from TxLINE’s API, and the verdict from TxLINE’s own program by simulation. Add --tamper to corrupt one byte and watch the oracle refuse it. There is also an in-browser version at /verify.

How a market settles itself

  1. 1

    Market created

    The predicate is fixed on-chain at creation: which stats, which comparison, which threshold. Nobody can change the question later.

  2. 2

    Bets escrowed

    USDC sits in a PDA vault. Parimutuel pools, no counterparty.

  3. 3

    Match finalises

    TxLINE publishes a merkle root of every match stat to their own Solana program, daily.

  4. 4

    Keeper submits the proof

    Anyone may. The proof carries values + merkle paths; the market supplies the question. settle_market CPIs TxLINE's validate_stat_v3.

  5. 5

    The oracle adjudicates

    TxLINE's program, not ours, checks the multiproof against the root TxLINE published, evaluates the predicate, and returns true or the transaction fails.

  6. 6

    Receipt

    The settlement writes the proof ref, root PDA, resolver and timestamp into the account. That record is what this site renders, and what you can re-verify below.

market (question, fixed) + proof (values, merkle paths) → validate_stat_v3 → true | fail. there is no admin path.

SDK · @h4rsharma/txline-settle

The settlement core of this site, published as a library. Unofficial, community-built; not affiliated with TxODDS/TxLINE. It is the same code the keeper runs. The app imports the package.

npm i @h4rsharma/txline-settle
import { parlay, homeWin, overCorners, strategyFor,
         TxLineSession, findFinalisedSeq, fetchProofV3,
         toPayloadV3, dailyRootsPda } from "@h4rsharma/txline-settle";

// "Home win AND over 9.5 corners" as an exhaustive 2×2 grid.
// Overlapping stat families throw at build time (TxLINE 6070).
const market   = parlay(homeWin, overCorners(9.5));   // legs [1,2,7,8]
const seq      = await findFinalisedSeq(session, fixtureId);
const val      = await fetchProofV3(session, fixtureId, seq,
                                    market.legs.map(l => l.key));
const payload  = toPayloadV3(val, BN);                // ONE shared multiproof
const strategy = strategyFor(market, 0);              // outcome 0 = the parlay

await myProgram.methods.settle(0, payload).accounts({
  market: myMarket,
  oracleProgram: TXORACLE_DEVNET,
  oracleRoots: dailyRootsPda(proofEpochDay(val)),     // TxLINE's own PDA
}).rpc();

modules

session guest JWT · free-tier subscribe · 403 re-subscribe · feed fixtures, scores · proof v3 multiproof fetch + payload · predicate conditions, 2×2 parlays, coverage checks · verify trust-nothing settlement verification · cpi roots PDA + a copy-paste Rust module · receipts chain-only reconstruction

for Rust programs

The package ships rust/txline_cpi.rs: wire types byte-identical to txoracle v1.5.6 plus invoke_validate_stat_v3, so any Anchor program can settle from a TxLINE proof. One rule: take the VALUES from the caller, take the PREDICATE from your own account.

CLI reference

Every command works via npx @h4rsharma/txline-settle with nothing installed (short alias once installed: txsettle). Each example below is copyable and real.

auth

Authenticate with TxLINE: guest JWT → FREE on-chain World-Cup subscription (Token-2022, price 0) → activate. Caches the session at ~/.txline-settle/ (read credentials, not funds). Needs a funded devnet keypair to sign the subscribe transaction.

npx @h4rsharma/txline-settle auth --keypair ~/.config/solana/id.json

fixtures

List fixtures with kickoff times and ids. --league selects the competition (World Cup = 72, the default).

npx @h4rsharma/txline-settle fixtures --league 72

scores <fixtureId>

The retained score records for a fixture, with the best terminal record highlighted (statusId 100 = game_finalised). --watch streams every live update over SSE instead.

npx @h4rsharma/txline-settle scores 18237038 --watch

proof <fixtureId> --stats 1,2

Fetch a real stat-validation-v3 merkle multiproof. --stats is the leg list in key order (max 5; the API rejects a 6th); --seq pins a record, otherwise the finalised one is used.

npx @h4rsharma/txline-settle proof 18218149 --stats 1,2,7,8

predicate

Build the exhaustive 2×2 parlay grid from two conditions, or check leg-set compatibility with --check. Overlapping stat families are refused with the DuplicateStatCoverage (6070) explanation, because the oracle would refuse them too.

npx @h4rsharma/txline-settle predicate --a homeWin --b overCorners:9.5
npx @h4rsharma/txline-settle predicate --check "1,2+7,8"

verify <marketPda|txSig>

★ The hero. Independently re-verify a settlement: settlement + predicate from the Solana account, merkle root from TxLINE's own PDA, proof from TxLINE, verdict from TxLINE's own program by simulation. --tamper corrupts one byte to prove a forgery cannot pass. Accepts a settle transaction signature too.

npx @h4rsharma/txline-settle verify 8m3iQDertFPaamME5zWgMyPU5KrSfBCFq1MSAjBj7Txx
npx @h4rsharma/txline-settle verify 8m3iQDertFPaamME5zWgMyPU5KrSfBCFq1MSAjBj7Txx --tamper

market create

Create a 1X2 market on a fixture (the reference market shape). --period matters. Pin the period the fixture's proof actually carries: 100 only survives ~10 days, older fixtures prove at 5.

npx @h4rsharma/txline-settle market create --fixture 18237038 --mint <usdcMint> --lock 1784055600 --period 100

market bet / lock / settle / claim

The rest of the lifecycle. settle fetches the real proof, derives the outcome the proven values satisfy, and submits the oracle CPI, the same trustless path the keeper takes. claim pays a winning position.

npx @h4rsharma/txline-settle market bet --market <pda> --outcome 0 --amount 25
npx @h4rsharma/txline-settle market settle --market <pda>

market receipt

Reconstruct a settlement receipt purely from chain accounts: proof ref, epoch day, roots PDA, resolver, pools. No API, no database.

npx @h4rsharma/txline-settle market receipt --market <pda> --json

global flags on every command: --json (machine output) · --devnet (default) | --mainnet · --rpc <url> · --api <origin> · --keypair <path>

The findings that shape everything here

Parlay legs must read disjoint stat families

The oracle evaluates each proven stat exactly once (errors 6070/6071, confirmed live). “Home win AND over 2.5 goals” is therefore not expressible, because both legs read goals. Families: goals 1|2 · yellows 3|4 · reds 5|6 · corners 7|8. The SDK and the on-chain program both refuse an overlapping combo before it can become a market.

period 100 vs period 5: the retention trap

TxLINE keeps the game_finalised(period 100) record only ~10 days; older fixtures prove at period 5 (full time). The proof leaf commits to the period, and a market spec pinned to the wrong one can never settle (InvalidStatProof 6023). Read the proof’s period first, then create the market.

The zero-stake cancel

If the proven outcome has an empty pool, settlement routes to Cancelled (refunds, no fee). Correct, but the market never earns a receipt. It once silently voided 74 markets. Stake every outcome before lock, atomically.

Cancellation is not provable, by design of the tree

The fixture leaf TxLINE commits to has no status field, and a merkle inclusion proof cannot prove absence. The time-based permissionless cancel is not a fallback; it is the only sound liveness primitive this interface admits.

package: @h4rsharma/txline-settle · MIT · unofficial, not affiliated with TxODDS/TxLINE · the on-chain interface reference lives in docs/TXLINE_INTERFACE.md and docs/ONCHAIN_INTERFACE.md in the repo.