Source of Truth: See
/ORACLE_TRUTH.mdfor canonical values. All implementations must align to that document.
- Real-time chart with price updates via Socket.io
- Betting UI with Long/Short buttons
- Fixed bet amounts: 5, 15, 25, 50, 100
- Timer showing countdown to lock/settle
- Two modes:
USE_ON_CHAIN_BETTINGflag switches between off-chain and on-chain usePredictionhook for on-chain interactions- Mock data currently displayed (needs real data integration)
- 30-second rounds (25s betting, 5s locked)
- In-memory round storage (not persistent)
- CoinGecko price feeds (30s updates with 1s simulated ticks)
- Socket events:
prediction_round,prediction_settled,prediction_bet_placed - XP awards on settlement via progressionService
- Wager tracking in SQLite
- 30-second rounds (20s betting, 10s locked)
- Pyth oracle for SOL/USD price
- 10% platform fee
- 0.01 SOL minimum bet
- Instructions:
initialize_game,place_bet,crank,claim_winnings - PDAs for escrow, round state, player positions
| Component | Betting Window | Lock Period |
|---|---|---|
| Frontend | Uses backend timing | Uses backend timing |
| Backend | 25 seconds | 5 seconds |
| Contract | 20 seconds | 10 seconds |
Decision Required: Standardize timing across all layers.
| Component | Bet Amounts |
|---|---|
| Frontend | Fixed: [5, 15, 25, 50, 100] (display as USD) |
| Backend | Fixed: [5, 15, 25, 50, 100] (validates these) |
| Contract | Minimum 0.01 SOL, any amount above |
Decision Required:
- Off-chain: Keep fixed amounts for simplicity
- On-chain: Convert USD to SOL at current price, or use fixed SOL amounts
| Component | Round ID Format |
|---|---|
| Frontend | Expects string UUID or number |
| Backend | UUID strings |
| Contract | Sequential u64 (0, 1, 2...) |
Decision Required: Frontend needs to handle both formats based on mode.
| Component | Settlement |
|---|---|
| Frontend | Displays results, no claim UI for on-chain |
| Backend | Auto-settles, credits virtual balance |
| Contract | Requires crank() call, then claim_winnings() |
Gap: Frontend has no UI for claiming on-chain winnings.
| Component | Price Source |
|---|---|
| Backend | CoinGecko (multiple assets) |
| Contract | Pyth (SOL/USD only) |
Gap: Contract only supports SOL, backend supports 8 assets.
| Component | Platform Fee |
|---|---|
| Backend | 5% of losing pool |
| Contract | 10% of total pool |
Decision: 5% is the canonical fee. Smart contract needs update.
| Component | Balance Handling |
|---|---|
| Frontend | Shows virtual balance from backend |
| Backend | In-memory tracking only |
| Contract | Real SOL in escrow, must claim |
Gap: No unified balance display, no claim flow UI.
Create shared constants file used by both frontend and backend:
// Shared timing constants
export const ROUND_DURATION = 30; // seconds
export const BETTING_WINDOW = 25; // seconds (off-chain)
export const BETTING_WINDOW_ONCHAIN = 20; // seconds (on-chain)
export const LOCK_PERIOD = 5; // seconds (off-chain)
export const LOCK_PERIOD_ONCHAIN = 10; // seconds (on-chain)- Keep fixed USD amounts for off-chain
- For on-chain: Convert to SOL equivalent at bet time
- Display both USD and SOL amounts in UI
- Canonical fee is 5% (see ORACLE_TRUTH.md)
- Backend already correct at 0.05
- Smart contract needs update from 10% to 5%
- Remove mock data from predict page
- Properly display real bets from
currentRound.longBets/shortBets - Show actual user profiles from progression system
- Add claim winnings button when user has unclaimed positions
- Show pending claims in sidebar
- Display SOL amounts when in on-chain mode
- Handle both UUID and sequential round IDs
- Format appropriately: "Round #42" for on-chain, truncated UUID for off-chain
- Store bets in SQLite instead of just in-memory
- Survive server restarts
- Enable bet history queries
- Ensure all events include complete round data
- Add explicit typing for all payloads
- Document event contracts
- Currently contract is SOL-only
- Would need separate game instances per asset
- Or contract upgrade to support multiple Pyth feeds
- Backend should auto-crank rounds when using on-chain mode
- Or implement keeper bot to call crank()
- Frontend needs claim button
- Show claimable amount
- Handle claim transaction
T-ORACLE-001: Standardize round timing constants
- Create /web/src/lib/prediction/constants.ts with timing values
- Update predict/page.tsx to use constants
- Update backend predictionService to use same constants
- Acceptance: Frontend and backend use identical timing for off-chain mode
T-ORACLE-002: Update platform fee to 10% in backend
- Modify predictionService.ts PLATFORM_FEE_RATE from 0.05 to 0.10
- Update any fee display in frontend
- Acceptance: Fee calculation matches smart contract
T-ORACLE-003: Remove mock data from predict page
- Delete mock bettors array
- Delete mock recent rounds array
- Wire up real data from currentRound
- Acceptance: Sidebars show real bets or empty state
T-ORACLE-004: Fix bet display in sidebars
- Left sidebar: Show real bets from currentRound.longBets + shortBets
- Fetch user profiles for usernames/levels
- Show obfuscated address if no username
- Acceptance: Real bets display correctly with user info
T-ORACLE-005: Fix recent rounds in right sidebar
- Show actual settled rounds from history
- Display correct winner, pools, % change
- Acceptance: History sidebar shows real completed rounds
T-ORACLE-006: Add on-chain mode toggle
- Add UI toggle to switch between off-chain and on-chain modes
- Persist preference in localStorage
- Show mode indicator in UI
- Acceptance: User can switch modes, preference persists
T-ORACLE-007: Display SOL amounts for on-chain mode
- When on-chain: Show bet amounts in SOL
- Convert USD selector to SOL equivalent
- Show SOL price for reference
- Acceptance: On-chain mode displays SOL values
T-ORACLE-008: Implement claim winnings UI
- Add "Claim" button when user has unclaimed positions
- Call claim_winnings instruction
- Show transaction status
- Acceptance: Users can claim on-chain winnings
T-ORACLE-009: Show unclaimed positions
- Query user's PlayerPosition accounts
- Display pending claims in UI
- Show claimable amount
- Acceptance: User sees their unclaimed winnings
T-ORACLE-010: Persist bets to SQLite
- Add bets table to userStatsDatabase
- Store bet details on placement
- Update on settlement
- Acceptance: Bets survive server restart
T-ORACLE-011: Add bet history endpoint
- GET /api/prediction/:wallet/bets
- Return user's bet history with outcomes
- Include pagination
- Acceptance: API returns user's prediction history
T-ORACLE-012: Backend auto-crank for on-chain mode
- When on-chain mode active, backend calls crank()
- Use dedicated wallet for gas
- Handle errors gracefully
- Acceptance: Rounds settle automatically on-chain
T-ORACLE-013: Add sound effects
- Play sound on bet placement
- Play sound on round lock
- Play sound on win/loss
- Acceptance: Audio feedback enhances UX
T-ORACLE-014: Add bet confirmation animation
- Animate when bet is placed
- Show bet flying to pool
- Acceptance: Visual feedback on bet
T-ORACLE-015: Mobile responsive improvements
- Collapse sidebars on mobile
- Touch-friendly bet buttons
- Acceptance: Usable on mobile devices
User clicks LONG/SHORT
↓
Frontend validates amount
↓
Socket emit: place_prediction(asset, side, amount, wallet)
↓
Backend validates round status & timing
↓
Backend adds bet to round pools
↓
Backend emits: prediction_bet_placed
↓
Frontend updates UI (pool totals, bet list)
↓
[At lock time] Backend emits: prediction_round (status: locked)
↓
[At end time] Backend settles, emits: prediction_settled
↓
Frontend shows result, awards displayed
User clicks LONG/SHORT
↓
Frontend validates amount & wallet connected
↓
Frontend builds place_bet transaction
↓
Wallet prompts for signature
↓
Transaction sent to Solana
↓
Contract validates & updates round state
↓
Frontend polls/subscribes for round updates
↓
[After end_time] Anyone calls crank()
↓
Contract settles round, calculates payouts
↓
User clicks "Claim" if winner
↓
Frontend builds claim_winnings transaction
↓
SOL transferred from escrow to user
- Timing Alignment: Frontend countdown matches backend round lifecycle exactly
- Fee Consistency: 10% fee across all modes
- Real Data: No mock data in production, sidebars show actual bets
- On-Chain Working: Full flow from bet → settle → claim functional
- User Experience: Clear indication of mode, amounts, and outcomes
- Should we support multiple assets on-chain, or keep it SOL-only?
- Should bet amounts be truly fixed, or allow custom amounts?
- Should we add a "demo mode" with fake credits for new users?
- How should we handle the case where no one bets on one side?
- Should rounds auto-start or require manual trigger?
- Review this plan and confirm priorities
- Create task files in
/tasks/directory for pipeline workers - Start with Priority 1 tasks (T-ORACLE-001 through T-ORACLE-005)
- Test alignment between frontend and backend
- Then move to Priority 2 for on-chain mode