DEMO ONLY · SIMULATED CREDITS · NO REAL MONEY
Prototype

Architecture & limitations

BetProof is a technical proof of concept showing frontend/backend boundaries, transactional ledger logic, idempotent wagering and settlement, and wallet connectivity. It is a simulation — not a betting product.

Request flow

  1. 01

    Browser

    Zustand (UI state) · TanStack Query (server cache) · ethers v6 (read-only)

  2. 02

    Route handlers

    Next.js on Node · HttpOnly session cookie · Zod · origin check · rate limits

  3. 03

    BettingStore

    Business rules · BEGIN IMMEDIATE tx

  4. 04

    SQLite

    WAL · CHECK + UNIQUE constraints

GET|POST /api/session · GET /api/events · account · ledger · settlementsGET|POST /api/wagersPOST /api/demo/settle · close · reset · sample-history

Invariants enforced by the backend

  • Credits and odds are integers (minor units / basis points). Payout = floor(stake × oddsBp ÷ 10000) in BigInt.
  • Client never supplies odds, payout or balance — unknown request fields are rejected with 400.
  • Wager insert, debit ledger entry and balance update commit in one transaction, or not at all.
  • Idempotency key unique per account: replay returns the same wager; different payload returns 409.
  • Ledger reference keys are UNIQUE (initial:, debit:, win:) so no entry can be written twice.
  • Balance has a CHECK (>= 0) constraint and a guarded UPDATE — overdraft is impossible even under races.
  • Settlement is idempotent; a conflicting outcome returns 409 and changes nothing.
  • Every financial read and write is resolved from the session cookie; no endpoint accepts an account id.
  • Each session has its own copy of event state: one visitor's settlement or reset never touches another's records.
  • Server state lives only in the TanStack Query cache and is invalidated after every mutation; Zustand holds UI state only.

Prototype vs. what production would require

AreaThis demoProduction would need
FundsFictional integer credits seeded at 1,000.00Custody model, licensed payment rails or audited contracts; reconciled against external balances
IdentityAnonymous per-browser demo session (random HttpOnly cookie); wallet connection is not authenticationKYC/AML, Sign-In with Ethereum (EIP-4361) or equivalent, session management
AuthorizationOperator controls gated only by DEMO_MODE=true and scoped to the caller's own sessionRole-based operator access, 4-eyes approval for settlement, immutable audit log
OutcomesClicked by the visitor on the demo Operator page (per-session event state)Verified data feed or oracle with dispute and correction process
OddsFixed, illustrative, labelled simulatedTrading/risk engine, price-change handling, limits and liability management
LedgerSingle SQLite file, serialized writes, versioned schema (PRAGMA user_version)Double-entry ledger on a managed RDBMS, reconciliation jobs, backups, PITR
On-chainNothing is signed or sentAudited contracts, key management (HSM/MPC), chain reorg & gas handling
ComplianceOut of scopeJurisdictional gambling licences, responsible-gambling tooling, legal review
OperationsLocal process, console logs, in-memory per-IP / per-session rate limitsSecrets management, monitoring/alerting, rate limiting, fraud controls, incident response

Wallet connection is not identity

The wallet integration uses an injected EIP-1193 provider via ethers.BrowserProvider, requests accounts only on click, and reacts to account/chain changes. It never requests signatures, approvals or transactions. A connected address is public information the wallet chooses to share; without a signed challenge it does not prove ownership, which is why it is deliberately not linked to the demo credits.