A decentralized demo prediction market project on Sepolia:
- users buy/sell YES/NO shares through an AMM in the smart contract
- market outcomes are resolved by an admin
- the frontend displays live data from a local SQLite database populated by the indexer
contracts/— Solidity contracts and Foundry scripts (deploy/seeding)backend/— TypeScript event indexer from RPC to SQLitefrontend/— Next.js 16 UI + API routes reading from SQLite
Additional documentation:
backend/README.md— backend indexer: env, run, tests, troubleshootingfrontend/README.md— frontend: env, local run, Docker flow
Data flow:
- The
PredictionMarketcontract emits events (MarketCreated,SharesBought,SharesSold,MarketResolved,WinningsClaimed). - The
backendindexes chain events and writes them to SQLite (/data/app.db). - The
frontendreads aggregated data from the same SQLite via server-side APIs (/api/markets,/api/markets/[id],/api/markets/[id]/activity,/api/markets/[id]/prices,/api/portfolio/[address]). - The UI renders markets, details, price chart, activity, and portfolio.
In Docker, both services (frontend, indexer) share the same app-data volume:
indexermounts it read-write and writes the databasefrontendmounts it read-only and only reads
contracts/src/PredictionMarket.sol:- buy/sell shares
resolveMarket(afterresolutionTime, admin only)forceResolveMarket(demo path, no time check, admin only)claimWinnings
backend/src/indexer.ts:- backfill + polling new blocks
- upsert into
markets,trades,resolutions,claims,pool_snapshots
backend/src/snapshot.ts:- on-chain pool sync (
yesReserve/noReserve/totalCollateral)
- on-chain pool sync (
frontend/lib/queries.ts:- SQL queries for frontend API routes
frontend/hooks/*:- market data, price history, activity, trading, portfolio
- Create
.envfrom template:
cp .env.example .env- Fill in required variables:
MARKET_ADDRESSUSDC_ADDRESSRPC_URLWALLETCONNECT_PROJECT_IDPRIVATE_KEY(used by Foundry scripts and demo resolve API by default)CONTRACT_DEPLOY_BLOCK(optional; default10696829)
docker-compose.yml maps canonical variables to NEXT_PUBLIC_* for frontend build/runtime, so values are defined once in root .env.
- Start the full stack with one command:
docker compose up --build -ddocker compose ps
docker compose logs --tail=100 frontend indexerExpected state:
frontend—healthyindexer—Up- UI is available at
http://localhost:3000 - health endpoint:
http://localhost:3000/api/health
docker compose downFull cleanup with volume removal (destructive):
docker compose down -v