The daily score calculation works via scheduled snapshots (like cron jobs), NOT triggered from the frontend.
- Snapshot System: The
/api/competitions/[id]/dailyUserScoreendpoint takes a snapshot of ALL on-chain KOL token holdings at the time it's called - All Tokens Count: The system fetches actual on-chain balances for all users, counting ALL tokens held regardless of when they were purchased (before or during the competition)
- Auto-Enrollment: Users who hold KOL tokens but haven't joined the competition are automatically enrolled during snapshots
- Score Calculation: For each snapshot, scores are calculated based on:
- User's actual on-chain token holdings
- Trader's PnL
- User's share ratio vs total supply held by all participants
- Snapshots at 14:00 UTC (2 PM) daily
- Use Vercel Cron or similar service
- Cron expression:
0 14 * * *
- Snapshots every 15 minutes
- Automatic finalization when competition ends
- Use background cron script (recommended) or manual triggers
The easiest way to test is to run the automated cron script alongside your dev server:
Terminal 1 - Start your dev server:
bun run devTerminal 2 - Start the cron job:
bun run cron
# or: node scripts/test-competition-cron.jsThe cron script will automatically:
- ✅ Detect when a competition starts
- ✅ Take snapshots every 15 minutes
- ✅ Finalize the competition when it ends
- ✅ Show detailed logs of all operations
Example output:
🚀 [CRON] Competition cron job started
API URL: http://localhost:3000
Check interval: 60s
Snapshot interval: 15 minutes
🔍 [CRON] Checking for active competitions...
✅ [CRON] Found new active competition: cm99abc...
Start: 2025-01-15T10:00:00.000Z
End: 2025-01-15T11:00:00.000Z
Time remaining: 60 minutes
📸 [SNAPSHOT] Taking snapshot...
✅ [SNAPSHOT] Successfully calculated scores
Users updated: 5
⏱️ [CRON] Next snapshot in 15 minutes
...
🏆 [FINALIZE] Finalizing competition...
✅ [FINALIZE] Competition finalized successfully!
Participants: 5
TP Pool: 1000
To stop: Press Ctrl+C in the cron terminal
If you prefer to trigger snapshots manually:
# Trigger daily score calculation
POST http://localhost:3000/api/cron/calculateDailyScores
# Or with curl:
curl -X POST http://localhost:3000/api/cron/calculateDailyScores- Start dev server:
bun run dev - Start cron job:
bun run cron(in separate terminal)
GET http://localhost:3000/api/competitions/start- Creates 1-hour test competition
- Returns
competitionId- save this! - Frontend banner appears automatically
- Navigate to any KOL page (e.g.,
/traders/some-kol) - Click "Buy" button
- Complete swap in modal
- User automatically enters competition on first purchase
- See "🏆 Welcome to the Arena!" toast
If using automated cron script (recommended):
- The cron job automatically takes snapshots every 15 minutes
- Watch the logs in the cron terminal to see snapshots happening
- Snapshots occur at: 0min, 15min, 30min, 45min
If doing manual testing:
# Snapshot 1 (at 0 min)
POST http://localhost:3000/api/cron/calculateDailyScores
# Wait 15 minutes, then snapshot 2 (at 15 min)
POST http://localhost:3000/api/cron/calculateDailyScores
# Wait 15 minutes, then snapshot 3 (at 30 min)
POST http://localhost:3000/api/cron/calculateDailyScores
# Wait 15 minutes, then snapshot 4 (at 45 min)
POST http://localhost:3000/api/cron/calculateDailyScoresBetween snapshots: Users can continue buying KOL tokens. Tokens bought after a snapshot are included in the NEXT snapshot.
- Click "View Live Scores" button in competition banner
- See all users ranked by daily score
- Expand users to see their individual KOL holdings
- Refresh after each snapshot to see updated scores
If using automated cron script (recommended):
- Competition ends after 1 hour
- Cron job automatically detects the end time
- Finalization happens automatically within 1 minute
- Watch the logs for the finalization confirmation
If doing manual testing:
- Wait for 1 hour to pass from start time
- Manually call finalization:
POST http://localhost:3000/api/competitions/{competitionId}/finalizeWhat finalization does:
- Calculates final window scores (sum of all daily scores)
- Distributes Tournament Points (TP) from the TP pool
- Calculates Leaderboard Points (LP) as percentage of max score
- Updates each user's total TP
- Changes competition status to FINALIZED
- Frontend automatically switches from banner to results page
- Results page appears automatically on homepage
- Shows podium (top 3 winners)
- Displays your rank, TP earned, and total TP
- Full leaderboard with all participants
- User's TP is now visible in profile dropdown
Check scores at any time with:
GET /api/competitions/[id]/dailyUserScore?userWallet=WALLET_ADDRESSView in UI:
- Click "View Live Scores" button in the competition banner
- Expand each user to see their individual KOL holdings and scores
- Scores not updating: Check that cron job is actually running every 15 minutes
- Zero scores: Ensure users bought tokens BEFORE the snapshot ran
- Missing holdings: KOLs bought after snapshot won't show until next snapshot