Backend API, oracle workers, Supabase metadata sync, and Foundry contracts for DarkONNET, a confidential prediction market on Zama fhEVM Sepolia.
DarkONNET keeps user position sizes, cUSDT balances, and pool totals encrypted with euint64 while still allowing markets to be created, settled, claimed, refunded, and exited on-chain.
- Smart contracts, faucet, deployment scripts, and oracle workers are implemented.
- Foundry tests cover market creation, admin actions, encrypted betting, settlement claims, cancellation refunds, faucet minting, cooldowns, and early exits.
- The backend API supports markets, comments, threaded replies, notifications, participants, and wallet profiles.
- Supabase is the production storage path when credentials are present; local JSON storage remains available for development.
- Sports markets currently use BSD Sports for football events.
- Esports markets use PandaScore.
- Football team logos are synced into Supabase Storage and referenced through the
team_logoscatalog.
backend/ REST + WebSocket API, auth, stores, profile validation
relayer/ Oracle workers and Supabase market metadata writers
scripts/ Railway start helpers, Foundry runner, logo sync/backfill scripts
src/ Solidity contracts
test/ Foundry tests
supabase/migrations/ Supabase schema migrations
ecosystem.config.js PM2 process definitions
Current Sepolia addresses used by the frontend:
| Contract | Address |
|---|---|
ConfidentialPredictionMarket |
0x69a9f1D7FDE2D7c154C02fb6abC9d8e6fCED7565 |
EncryptedERC20 (cUSDT) |
0x0CbC92CA4D7eD07e935dc93bf6Ca6A5e26682035 |
ConfidentialUSDTFaucet |
0xcDda033C5F914cCBFf39D7517cc4Dba54Bf7eeD9 |
Set CONTRACT_ADDRESS to the prediction market address for oracle workers.
Copy .env.example to .env and fill the values you need.
Core values:
PRIVATE_KEY=0x...
CONTRACT_ADDRESS=0x69a9f1D7FDE2D7c154C02fb6abC9d8e6fCED7565
RPC_URL=https://...
ALCHEMY_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/...
COMMENTS_PORT=8787
API_STORE=supabase
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=...
API_AUTH_REQUIRED=true
API_ADMIN_WALLETS=0xAdminWallet,...
Oracle/provider values:
ESPORTS_API_KEY=... # PandaScore
BSD_SPORTS_API_KEY=... # BSD Sports
BSD_SPORTS_API_URL=https://sports.bzzoiro.com/api/v2
BSD_SPORTS_LEAGUE_IDS=7,1,5,4,39,6,35
NEWS_API_KEY=... # Politics
TECH_GUARDIAN_API_KEY=... # Tech
FINNHUB_API_KEY=... # Finance
CULTURE_FREENEWS_API_KEY=... # Culture
Logo catalog values:
TEAM_LOGO_BUCKET=team-logos
FOOTBALL_LOGOS_GITHUB_OWNER=luukhopman
FOOTBALL_LOGOS_GITHUB_REPO=football-logos
FOOTBALL_LOGOS_GITHUB_REF=master
FOOTBALL_LOGOS_GITHUB_PREFIX=logos/
Notes:
- Sports and esports workers prefer
ALCHEMY_RPC_URL, thenNEXT_PUBLIC_ALCHEMY_API_KEY, thenRPC_URL, then public Sepolia fallback. BSD_SPORTS_LEAGUE_IDScontrols football market creation and settlement. The default list is Champions League, Premier League, Bundesliga, Serie A, FA Cup, Ligue 1, and Copa do Brasil.- Other workers currently use
RPC_URLwith public Sepolia fallback. - Do not put
Authorization: Token ...into.env; store only the raw BSD token inBSD_SPORTS_API_KEY.
Install dependencies:
npm installRun the API:
npm run comments:devRun one oracle:
npm run oracle:sports
npm run oracle:esports
npm run oracle:crypto
npm run oracle:politics
npm run oracle:tech
npm run oracle:finance-cultureRun with PM2:
pm2 start ecosystem.config.js
pm2 status
pm2 logs oracle-sportsRun tests/checks:
npm run test:backend
npm run test:foundry
npm run foundry:build
npm run foundry:fmtApply migrations from supabase/migrations/ in Supabase SQL editor or your migration flow.
The backend stores:
marketscommentsnotificationsprofilesmarket_participantsteam_logos
Profile data is validated server-side. Profile images must be image data URLs and are compressed client-side before save.
The sports oracle uses BSD event/team data first, then looks up normalized team names in Supabase team_logos.
Useful scripts:
npm run logos:sync
npm run logos:sync:wikimedia
npm run logos:backfilllogos:sync imports from luukhopman/football-logos into Supabase Storage. The Wikimedia script is an optional fallback for missing teams. logos:backfill updates existing sports market metadata with catalog logos.
Common routes:
GET /api/markets
GET /api/markets/:marketId
PUT /api/markets/:marketId
POST /api/markets/:marketId/comments
POST /api/markets/:marketId/participants
GET /api/wallets/:walletAddress/profile
PUT /api/wallets/:walletAddress/profile
GET /api/wallets/:walletAddress/notifications
PATCH /api/wallets/:walletAddress/notifications/:notificationId
WS /ws/notifications?walletAddress=:walletAddress
When API_AUTH_REQUIRED is not false, mutating routes require signed wallet auth. Admin/oracle metadata writes require a wallet listed in API_ADMIN_WALLETS.
Message shape:
DarkONNET API request
Wallet: 0x...
Method: POST
Path: /api/markets/123/comments
Timestamp: 1770000000000
BodyHash: 0x...
npm run start:railway starts selected processes from scripts/start-railway.js.
Use RAILWAY_PROCESSES to choose processes, for example:
RAILWAY_PROCESSES=api,oracle-sports,oracle-esports
MIT