Skip to content

Repository files navigation

TxPredict — Trustless World Cup Prediction Market

TxPredict Banner

Powered by TxLINE Built on Solana Anchor License: MIT

Real-time World Cup predictions · Cryptographic Merkle verification · Automated on-chain settlement


🏆 What is TxPredict?

TxPredict is a full-tournament, trustless prediction market for the FIFA World Cup 2026, built for the TxODDS hackathon on Superteam Earn.

It solves a fundamental Web3 problem: how do you run a decentralized sports betting market without trusting anyone — no oracle admins, no multisig keepers, no centralized price feeds?

The answer: TxLINE's cryptographically signed, Solana-anchored data feeds + a custom Anchor smart contract that CPIs into validate_stat to verify match outcomes on-chain before releasing a single lamport.


✨ Key Features

Feature Description
📡 Real-Time SSE Odds Live consensus odds from TxLINE StablePrice feed, streamed via SSE
Full Tournament All 104 FIFA World Cup 2026 matches, live status tracking
🎯 3 Prediction Markets Match Winner (1X2), Total Goals (Over/Under 2.5), Both Teams to Score
🤖 Automated Settlement Bot FastAPI asyncio worker polls scores every 30s, dispatches payouts automatically
🔐 Merkle Proof Verification Ed25519 signature verification using TweetNaCl — real cryptographic validation
Anchor Smart Contract PDA vault escrow with CPI into TxLINE validate_stat for trustless settlement
📊 Live Odds Charts SVG charts showing real-time odds movement per fixture
🏅 Global Leaderboard Platform-wide predictor rankings by win rate, profit, and streak
📱 PWA + Mobile Installable Progressive Web App with hamburger navigation
🛡️ Developer Hub Interactive Merkle proof terminal with step-by-step verification

🏗 Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         CLIENT BROWSER (SPA)                        │
│   Dashboard │ Schedule │ Analytics │ Leaderboard │ Developer Hub    │
│                     Phantom Wallet + TweetNaCl                      │
└────────────────────────────┬────────────────────────────────────────┘
                             │ HTTP / SSE
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    FASTAPI BACKEND (Python)                          │
│                                                                     │
│  ┌─────────────────┐   ┌──────────────────┐   ┌─────────────────┐  │
│  │  REST Proxy      │   │  SSE Relay       │   │ Settlement Bot  │  │
│  │  /api/fixtures   │   │  /sse/odds       │   │ (asyncio task)  │  │
│  │  /api/odds/:id   │   │  /sse/scores     │   │ Polls every 30s │  │
│  │  /api/scores/:id │   │                  │   │ auto-dispatches │  │
│  └─────────────────┘   └──────────────────┘   └────────┬────────┘  │
│                                                          │           │
│  ┌─────────────────┐   ┌──────────────────┐             │           │
│  │  Prediction API  │   │  Leaderboard API │             │           │
│  │  /api/predictions│   │  /api/leaderboard│    vault_pda.js        │
│  │  submit/portfolio│   │                  │             │           │
│  └─────────────────┘   └──────────────────┘             │           │
└───────────────────────────────────────────┬─────────────┼───────────┘
                                            │             │
                   SSE / REST               │        Solana RPC
                                            ▼             ▼
┌─────────────────────────────┐   ┌─────────────────────────────────┐
│         TxLINE API          │   │     SOLANA BLOCKCHAIN            │
│                             │   │                                  │
│  • /fixtures/snapshot       │   │  ┌──────────────────────────┐   │
│  • /odds/snapshot/:id       │   │  │  TxPredict Anchor Program │   │
│  • /scores/snapshot/:id     │   │  │  (PDA Vault Escrow)       │   │
│  • /scores/historical/:id   │   │  │                           │   │
│  • /odds/stream (SSE)       │   │  │  • initialize_wager()     │   │
│  • /scores/stream (SSE)     │   │  │  • place_bet()            │   │
│  • /auth/guest/start        │   │  │  • settle_wager() ──CPI──►│   │
│  • /token/activate          │   │  │  • claim_payout()         │   │
│                             │   │  │  • reclaim_expired()      │   │
│  Cryptographic Layer:       │   │  └──────────┬───────────────┘   │
│  • Ed25519 signatures       │   │             │ CPI               │
│  • Merkle root anchoring    │   │  ┌──────────▼───────────────┐   │
│  • validate_stat program    │◄──┼──│  TxLINE validate_stat    │   │
│                             │   │  │  (Merkle proof verifier)  │   │
└─────────────────────────────┘   │  └──────────────────────────┘   │
                                  └─────────────────────────────────┘

Settlement Flow (Trustless)

TxLINE SSE Score Feed                     Solana Blockchain
        │                                         │
        │  GameState: "finished"                  │
        ▼                                         │
 Settlement Bot                                   │
  ├─ Fetch score receipt                          │
  ├─ Extract Merkle proof bytes                   │
  └─ Call settle_wager() ──────────────────────►  │
                                   CPI to validate_stat
                                   ├─ Verify Ed25519 sig ✓
                                   ├─ Verify Merkle path ✓
                                   └─ Record winning outcome ✓
                                                  │
                                    Winners call claim_payout()
                                    Vault PDA transfers SOL directly
                                    No admin. No trust. Math only.

📡 TxLINE Endpoints Used

# Endpoint Method Purpose
1 /auth/guest/start POST Obtain guest JWT for API authentication
2 /api/token/activate POST Activate API token post on-chain subscription
3 /api/fixtures/snapshot GET Fetch all 104 World Cup fixture metadata
4 /api/odds/snapshot/{fixtureId} GET Latest StablePrice consensus odds for a match
5 /api/scores/snapshot/{fixtureId} GET Current score + match state for a fixture
6 /api/scores/historical/{fixtureId} GET Complete historical score update timeline
7 /api/odds/stream GET (SSE) Real-time odds updates via Server-Sent Events
8 /api/scores/stream GET (SSE) Real-time score updates via Server-Sent Events

Why a proxy architecture? Our FastAPI backend acts as a secure proxy:

  • API JWT/tokens are never exposed to client browsers
  • SSE streams are relayed with proper backpressure handling
  • Fixture snapshots are cached with concurrent batching (15-connection semaphore)
  • Completed match scores are permanently cached to reduce upstream load

⚓ Smart Contract — Anchor Program

Located in anchor_program/

Instructions

Instruction Description
initialize_wager Create PDA escrow for a fixture/market pair
place_bet Deposit SOL into vault; store odds + outcome hash
settle_wager CPI into TxLINE validate_stat — verify Merkle proof on-chain, record winner
claim_payout Winner withdraws stake × odds from vault (2.5% fee deducted)
reclaim_expired Safety: refund user after 48h if oracle never settles

PDA Derivation

// Wager state account
wager_pda = find_pda(["wager", fixture_id_le_bytes, market_hash], PROGRAM_ID)

// SOL escrow vault (system-owned, signed by bump)
vault_pda = find_pda(["vault", fixture_id_le_bytes, market_hash], PROGRAM_ID)

Key Design Decisions

  • Outcome hashes — outcomes are stored as sha256(outcome_string) to save on-chain space while remaining verifiable
  • Fixed-point oddsodds_fp = decimal_odds * 10000 avoids floating point in Rust
  • 2.5% platform fee — deducted atomically from each payout in the same transaction
  • 48h expiry — users can always reclaim if oracle is unavailable (no permanent lockup)
  • CPI trustlessnesssettle_wager reverts entirely if the Merkle proof fails; impossible to settle with a forged score

Build & Deploy

cd anchor_program

# Install Anchor CLI
cargo install --git https://github.com/coral-xyz/anchor avm --locked
avm install 0.30.1 && avm use 0.30.1

# Build
anchor build

# Run tests (local validator)
anchor test

# Deploy to Devnet
anchor deploy --provider.cluster devnet

🔐 Cryptographic Verification

TxPredict's Developer Hub implements real Ed25519 signature verification using TweetNaCl directly in the browser:

TxLINE Score Receipt
       │
       ├─ message bytes (fixture_id + score data)
       ├─ signature (Ed25519, 64 bytes)
       └─ public key (TxLINE signer, 32 bytes)
              │
              ▼
      nacl.sign.detached.verify(message, signature, publicKey)
              │
              ├─ PASS → ✓ CRYPTO SECURED
              └─ FAIL → ✗ SIGNATURE INVALID

The Merkle path is then validated step-by-step:

  1. Hash the score leaf node
  2. Hash with each sibling on the path
  3. Compare final root against TxLINE's Solana-anchored root

🚀 Quick Start

Prerequisites

  • Python 3.11+
  • Node.js 18+
  • Phantom Wallet (browser extension) set to Devnet

Local Development

# 1. Clone the repository
git clone https://github.com/YOUR_USERNAME/txpredict.git
cd txpredict

# 2. Configure environment
cp .env.example .env
# Fill in your TXLINE_JWT and TXLINE_API_TOKEN

# 3. Set up Python backend
cd backend
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install -r requirements.txt

# 4. Start the server
cd src
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

# 5. Open http://localhost:8000

Environment Variables

# Obtain from: https://txline.txodds.com/documentation/quickstart
TXLINE_JWT=your_guest_jwt_token
TXLINE_API_TOKEN=your_activated_api_token

# Optional: "mainnet" or "devnet" (default: mainnet)
TXLINE_NETWORK=mainnet

Vault Setup (for automated payouts)

# Generate a devnet vault keypair
solana-keygen new -o .devnet-keypair.json

# Fund it with devnet SOL
solana airdrop 2 $(solana-keygen pubkey .devnet-keypair.json) --url devnet

# Verify balance
solana balance $(solana-keygen pubkey .devnet-keypair.json) --url devnet

🎨 Frontend Design

  • Zero framework — Vanilla HTML/CSS/JS, instant load, no build step
  • Glassmorphism dark themergba + backdrop-filter: blur() throughout
  • Typography — Space Grotesk (UI) + JetBrains Mono (data/terminal)
  • SPA routing — Hash-based (#/, #/schedule, etc.)
  • SSE streaming — Native EventSource API matching TxLINE's protocol
  • PWAmanifest.json + service worker for install-to-home-screen
  • Mobile — Hamburger menu, responsive grid, touch-optimized

📋 Project Structure

txpredict/
├── frontend/               # Vanilla SPA (HTML + CSS + JS)
│   ├── index.html          # Single entry point, all views
│   ├── styles.css          # Design system + glassmorphism
│   ├── app.js              # SPA routing, TxLINE integration, charts
│   ├── manifest.json       # PWA manifest
│   └── sw.js               # Service worker
│
├── backend/                # FastAPI Python server
│   ├── src/
│   │   ├── main.py         # API routes + settlement worker
│   │   ├── txline_client.py # TxLINE API + SSE client
│   │   ├── solana_engine.py # Solana RPC + Anchor program bridge
│   │   └── wagers.json     # Active wager database
│   └── requirements.txt
│
├── anchor_program/         # Solana Anchor smart contract
│   ├── programs/txpredict/src/lib.rs  # Full PDA escrow program
│   ├── tests/txpredict.ts  # Integration tests
│   ├── Anchor.toml         # Devnet config
│   └── Cargo.toml
│
├── vault_pda.js            # Vault settlement dispatcher
├── subscribe.cjs           # On-chain TxLINE subscription
└── Dockerfile              # Container build

💬 TxLINE API Feedback

What we loved:

  • SSE streaming maps perfectly to EventSource — zero latency odds updates
  • Consistent JSON schema across all endpoints — parsing is straightforward
  • Free World Cup tier during the hackathon is extremely generous
  • The fixture snapshot gave us everything needed to bootstrap the full schedule
  • Merkle proof receipts are a genuinely innovative data integrity primitive

Where we hit friction:

  • The on-chain subscription flow requires non-trivial Solana/Anchor knowledge upfront — a simplified "API key" mode for hackathons would help
  • The historical scores endpoint's 2-week to 6-hour time window constraint could be documented more prominently
  • Would love a WebSocket option alongside SSE for environments where EventSource is unavailable

📄 License

MIT — Built for the TxODDS World Cup Prediction Markets & Settlement Hackathon on Superteam Earn.


Built by Team TxPredict · Powered by TxLINE · Deployed on Solana

About

TxPredict — Trustless World Cup Prediction Market on Solana

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages