dubs-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +280 -0
- package/CLAUDE.md +46 -0
- package/CONNECT4_PRODUCTION_DEPLOY.md +155 -0
- package/CURRENT_SESSION.md +171 -0
- package/CURRENT_SESSION_DRAW.md +516 -0
- package/MARCH_MADNESS_SURVIVOR.md +254 -0
- package/PANDA.md +166 -0
- package/Procfile +4 -0
- package/README.md +476 -0
- package/controllers/livescoresController.js +376 -0
- package/controllers/pickemController.js +554 -0
- package/controllers/survivorAdminController.js +887 -0
- package/controllers/survivorController.js +623 -0
- package/cron/oracleMonitor.js +77 -0
- package/cron/pickemOracleMonitor.js +73 -0
- package/data/jackpot-history.json +952 -0
- package/data/ncaaTeams.js +406 -0
- package/documentation/API_SECURITY_GUIDE.md +327 -0
- package/documentation/ARCADE_API.md +593 -0
- package/documentation/ARCADE_IMPLEMENTATION_SUMMARY.md +399 -0
- package/documentation/ARCADE_QUICKSTART.md +242 -0
- package/documentation/AUTOMATIC_MODE_ORACLE.md +321 -0
- package/documentation/BUG_FIX_COHORT_DATE_DISPLAY.md +171 -0
- package/documentation/CLAIM_MIGRATION_INSTRUCTIONS.md +52 -0
- package/documentation/CLAIM_STATUS_FIX.md +67 -0
- package/documentation/CLI_TOOL_GUIDE.md +372 -0
- package/documentation/COHORT_RETENTION_ANALYSIS.md +295 -0
- package/documentation/COHORT_RETENTION_IMPLEMENTATION_COMPLETE.md +461 -0
- package/documentation/COHORT_RETENTION_SUMMARY.md +204 -0
- package/documentation/COMPLETE_PROJECT_SUMMARY.md +490 -0
- package/documentation/DATABASE_QUERIES.md +269 -0
- package/documentation/DATABASE_RETENTION_POLICY.md +390 -0
- package/documentation/DATABASE_SETUP_GUIDE.md +361 -0
- package/documentation/DATABASE_SETUP_SUMMARY.md +247 -0
- package/documentation/DEMO_API_CURL_COMMANDS.md +656 -0
- package/documentation/DEPLOYMENT_SUMMARY.txt +100 -0
- package/documentation/DUPLICATE_NOTIFICATIONS_FIXED.md +201 -0
- package/documentation/EXCHANGE_RATES_INTEGRATION.md +371 -0
- package/documentation/FINAL_API_PROTECTION_TABLE.md +175 -0
- package/documentation/GAME_START_NOTIFICATIONS_DEPLOYMENT.md +256 -0
- package/documentation/GAME_START_NOTIFICATIONS_INTEGRATION.md +275 -0
- package/documentation/HEROKU_DEPLOYMENT.md +134 -0
- package/documentation/HEROKU_SCHEDULER_SETUP.md +271 -0
- package/documentation/JACKPOT_API.md +521 -0
- package/documentation/JACKPOT_DEPLOYMENT_GUIDE.md +362 -0
- package/documentation/JWT_IMPLEMENTATION_SUMMARY.md +373 -0
- package/documentation/JWT_QUICK_SETUP.md +268 -0
- package/documentation/JWT_TESTING_GUIDE.md +404 -0
- package/documentation/KEEPER_RECOVERY_GUIDE.md +381 -0
- package/documentation/KEEPER_SETUP.md +206 -0
- package/documentation/KEEPER_STATE_MACHINE.md +423 -0
- package/documentation/LATEST_PRODUCTION_SETUP.md +387 -0
- package/documentation/LOCAL_VOTING_TEST.md +279 -0
- package/documentation/ORACLE_FIXES_SUMMARY.md +188 -0
- package/documentation/ORACLE_POSTGRESQL_UPDATE.md +202 -0
- package/documentation/PAYMENT_DEPLOYMENT.md +209 -0
- package/documentation/PNL_TRACKING_SETUP.md +189 -0
- package/documentation/PREVENTING_LOCKUP_ERRORS.md +472 -0
- package/documentation/PRODUCTION_READY_SUMMARY.md +227 -0
- package/documentation/PUBLIC_VS_PRIVATE_ENDPOINTS.md +278 -0
- package/documentation/QUICK_AUTH_SETUP.md +99 -0
- package/documentation/QUICK_DEPLOY.md +224 -0
- package/documentation/QUICK_FIX.md +114 -0
- package/documentation/QUICK_START.md +152 -0
- package/documentation/REFEREE_MODE_GUIDE.md +392 -0
- package/documentation/RETENTION_CORE_ACTION_UPDATE.md +313 -0
- package/documentation/RETENTION_UPDATE_SUMMARY.md +108 -0
- package/documentation/RUN_MIGRATION_NOW.md +39 -0
- package/documentation/SCRIPTS_UPDATE_SUMMARY.md +251 -0
- package/documentation/SETUP_GUIDE.md +184 -0
- package/documentation/STATE_MACHINE_IMPLEMENTATION.md +250 -0
- package/documentation/TELEGRAM_NOTIFICATIONS_DIAGNOSIS.md +361 -0
- package/documentation/UNIFIED_ARCHITECTURE.md +231 -0
- package/documentation/VOTING_DEPLOYMENT_SUMMARY.md +392 -0
- package/documentation/WEBSOCKET_ARCHITECTURE.md +881 -0
- package/documentation/WHAT_WE_BUILT_TODAY.md +369 -0
- package/documentation/latest/LATEST_PRODUCTION_SETUP.md +865 -0
- package/ecosystem.config.js +65 -0
- package/env.template +125 -0
- package/middleware/apiKeyAuth.js +136 -0
- package/middleware/authenticate.js +214 -0
- package/middleware/developerUserAuth.js +76 -0
- package/middleware/socketAuth.js +69 -0
- package/package.json +49 -0
- package/postman/Dubs-API-v1-With-Voting.postman_collection.json +555 -0
- package/postman/Dubs-API-v1.postman_collection.json +205 -0
- package/postman/Dubs_Developer_API.postman_collection.json +662 -0
- package/postman/QUICKSTART.md +118 -0
- package/postman/QUICK_REFERENCE.md +246 -0
- package/postman/README.md +71 -0
- package/postman/VOTING_API_GUIDE.md +426 -0
- package/refactor/Animations.md +148 -0
- package/refactor/Chat.md +252 -0
- package/routes/actionsRoutes.js +699 -0
- package/routes/adminRoutes.js +370 -0
- package/routes/analyticsRoutes.js +1262 -0
- package/routes/arcadeRoutes.js +557 -0
- package/routes/authRoutes.js +2310 -0
- package/routes/avatarRoutes.js +85 -0
- package/routes/botRoutes.js +211 -0
- package/routes/chatRoutes.js +377 -0
- package/routes/cryptoPriceRoutes.js +105 -0
- package/routes/developerRoutes.js +4201 -0
- package/routes/deviceRoutes.js +214 -0
- package/routes/dmRoutes.js +167 -0
- package/routes/esportsRoutes.js +806 -0
- package/routes/exchangeRateRoutes.js +233 -0
- package/routes/gamesRoutes.js +3028 -0
- package/routes/jackpotRoutes.js +754 -0
- package/routes/keeperMonitoringRoutes.js +156 -0
- package/routes/keeperWebhookRoutes.js +466 -0
- package/routes/livescoresRoutes.js +31 -0
- package/routes/pickemAdminRoutes.js +199 -0
- package/routes/pickemRoutes.js +231 -0
- package/routes/playerStatsRoutes.js +147 -0
- package/routes/portfolioRoutes.js +217 -0
- package/routes/promoRoutes.js +418 -0
- package/routes/referralEarningsRoutes.js +392 -0
- package/routes/socialRoutes.js +459 -0
- package/routes/sportsRoutes.js +1271 -0
- package/routes/survivorAdminRoutes.js +345 -0
- package/routes/survivorRoutes.js +756 -0
- package/routes/uploadRoutes.js +256 -0
- package/routes/userProfileRoutes.js +244 -0
- package/routes/whatsNewRoutes.js +331 -0
- package/scripts/.claude/settings.local.json +15 -0
- package/scripts/README.md +170 -0
- package/scripts/RESTART_EVERYTHING.sh +104 -0
- package/scripts/add-claim-columns.sql +48 -0
- package/scripts/add-crypto-prices-cache.sql +27 -0
- package/scripts/add-exchange-rates-cache.sql +40 -0
- package/scripts/add-game-invite-column.sql +23 -0
- package/scripts/add-game-invite-notification.sql +33 -0
- package/scripts/add-game-invite-telegram-pref.sql +16 -0
- package/scripts/add-game-joined-notification.sql +16 -0
- package/scripts/add-game-joined-pref.js +40 -0
- package/scripts/add-game-joined-preference.sql +6 -0
- package/scripts/add-game-start-notifications.sql +41 -0
- package/scripts/add-notification-flags-to-games.sql +55 -0
- package/scripts/add-pending-game-dismissals.sql +19 -0
- package/scripts/add-preferred-currency.sql +34 -0
- package/scripts/add-winner-columns.js +61 -0
- package/scripts/add_mention_system.sql +53 -0
- package/scripts/add_payment_system.sql +96 -0
- package/scripts/add_sports_event_id_column.sql +22 -0
- package/scripts/analyze-cohort-data-heroku.js +276 -0
- package/scripts/analyze-cohort-data.js +295 -0
- package/scripts/analyze-prod-cohorts.sh +10 -0
- package/scripts/backfill-matchup-images.js +245 -0
- package/scripts/backfill-missing-signatures.js +175 -0
- package/scripts/backfill-referral-earnings.js +202 -0
- package/scripts/check-chat-schema.js +130 -0
- package/scripts/check-db.sh +14 -0
- package/scripts/check_oracle_in_game.js +54 -0
- package/scripts/cleanup-database.js +193 -0
- package/scripts/clear-notification-cache.js +85 -0
- package/scripts/convert-mnemonic.js +50 -0
- package/scripts/create-users-table.sql +44 -0
- package/scripts/debug-cohort-counts.js +248 -0
- package/scripts/debug-winner-calc.js +84 -0
- package/scripts/deploy-payment-system.sh +118 -0
- package/scripts/deploy-to-heroku.sh +63 -0
- package/scripts/diagnose-locked-round.js +143 -0
- package/scripts/dubs-cli.js +720 -0
- package/scripts/dump-account.js +65 -0
- package/scripts/find-vrf-offset.js +48 -0
- package/scripts/fix-chat-notifications-constraint.sql +122 -0
- package/scripts/fix-claim-columns.js +124 -0
- package/scripts/fix-constraint-now.js +44 -0
- package/scripts/fix-lock-timestamps.js +96 -0
- package/scripts/fix-locked-round.sh +126 -0
- package/scripts/fix-missing-badges.sql +91 -0
- package/scripts/fix-payment-notifications.sql +41 -0
- package/scripts/force-new-round.js +55 -0
- package/scripts/force-resolve-and-claim.js +278 -0
- package/scripts/important/README.md +115 -0
- package/scripts/important/authority-force-lock.js +197 -0
- package/scripts/important/authority-resolve-game.js +267 -0
- package/scripts/important/check-game-status.js +373 -0
- package/scripts/important/list-pending-games-by-version.js +270 -0
- package/scripts/important/reconcile-v1-v2-payouts.js +270 -0
- package/scripts/initialize-jackpot.js +111 -0
- package/scripts/jackpot/.claude/settings.local.json +10 -0
- package/scripts/jackpot/force-reset.js +84 -0
- package/scripts/jackpot/initialize-mainnet.js +100 -0
- package/scripts/jackpot/keeper.js +742 -0
- package/scripts/jackpot/status.js +107 -0
- package/scripts/jackpot/update-round-duration.js +143 -0
- package/scripts/keeper-bot.js +112 -0
- package/scripts/list-pending-games.js +131 -0
- package/scripts/migrate-chat-v2.js +127 -0
- package/scripts/migrate-chat-winners.js +84 -0
- package/scripts/migrate-chat.sh +17 -0
- package/scripts/migrate-game-invite.js +83 -0
- package/scripts/migrate-heroku-game-notifications.sh +159 -0
- package/scripts/migrations/001_analytics_tables.sql +422 -0
- package/scripts/migrations/002_add_matchup_image_url.sql +14 -0
- package/scripts/migrations/003_referral_earnings.sql +208 -0
- package/scripts/migrations/004_add_whats_new_notification_type.sql +62 -0
- package/scripts/migrations/005_add_connect4_your_turn_notification.sql +61 -0
- package/scripts/migrations/005_push_notifications.sql +55 -0
- package/scripts/migrations/006_add_draw_team_players.sql +28 -0
- package/scripts/migrations/006_add_game_cancelled_notification.sql +62 -0
- package/scripts/migrations/007_add_gif_url.sql +8 -0
- package/scripts/migrations/008_add_connect4_columns.sql +139 -0
- package/scripts/migrations/008_add_pool_tracking.sql +22 -0
- package/scripts/migrations/009_create_survivor_pool_tables.sql +174 -0
- package/scripts/migrations/010_add_survivor_pool_outcome.sql +28 -0
- package/scripts/migrations/011_create_developer_tables.sql +67 -0
- package/scripts/migrations/011_fix_keeper_tables.sql +85 -0
- package/scripts/migrations/012_create_developer_webhooks.sql +31 -0
- package/scripts/migrations/013_add_network_mode.sql +18 -0
- package/scripts/migrations/014_create_developer_app_users.sql +19 -0
- package/scripts/migrations/015_add_ui_config.sql +4 -0
- package/scripts/migrations/016_add_resolution_secret.sql +4 -0
- package/scripts/migrations/017_add_external_game_id.sql +3 -0
- package/scripts/migrations/018_create_pickem_tables.sql +115 -0
- package/scripts/migrations/019_expo_push_tokens.sql +19 -0
- package/scripts/migrations/create_whats_new_tables.sql +88 -0
- package/scripts/migrations/drop_live_games_tables.sql +34 -0
- package/scripts/open-jackpot-round.js +85 -0
- package/scripts/purge-all-data.sh +329 -0
- package/scripts/purge-all-data.sql +142 -0
- package/scripts/purge-heroku-data.sh +149 -0
- package/scripts/purge-heroku-data.sql +62 -0
- package/scripts/rebuild-heroku-database.sh +113 -0
- package/scripts/recover-funds.js +357 -0
- package/scripts/regenerate-epl-images.js +278 -0
- package/scripts/resize-s3-matchup-images.js +374 -0
- package/scripts/resolve-direct.js +88 -0
- package/scripts/resolve-mock-game.js +124 -0
- package/scripts/resolve-pickem-game.js +55 -0
- package/scripts/resolve-round-manual.js +83 -0
- package/scripts/resolve-stuck-game.js +382 -0
- package/scripts/resolve-stuck-round.js +42 -0
- package/scripts/run-connect4-migration.sh +16 -0
- package/scripts/run-mention-migration.sh +32 -0
- package/scripts/run-payment-migration.sh +51 -0
- package/scripts/run-preferred-currency-migration.sh +31 -0
- package/scripts/run-referral-earnings-migration.sh +32 -0
- package/scripts/run-survivor-outcome-migration.sh +16 -0
- package/scripts/seed-test-users.js +346 -0
- package/scripts/setup-auth-tables.js +78 -0
- package/scripts/setup-complete-database.sql +992 -0
- package/scripts/setup-database-fresh.sh +359 -0
- package/scripts/setup-heroku-keeper.sh +48 -0
- package/scripts/setup-keeper-database.js +83 -0
- package/scripts/setup-keeper-state-db.sql +110 -0
- package/scripts/setup-oracle.sh +39 -0
- package/scripts/setup-pnl-tracking.js +111 -0
- package/scripts/start-devnet.sh +14 -0
- package/scripts/test-arcade-devnet.sh +160 -0
- package/scripts/test-arcade-match.sh +109 -0
- package/scripts/test-automatic-mode.sh +239 -0
- package/scripts/test-connect4-cancel-claim.js +370 -0
- package/scripts/test-connect4-e2e.js +369 -0
- package/scripts/test-connect4-resolve.js +369 -0
- package/scripts/test-game-state-endpoint.js +136 -0
- package/scripts/test-invite-notification.js +86 -0
- package/scripts/test-jackpot-api.sh +71 -0
- package/scripts/test-poll-confirmation.js +267 -0
- package/scripts/test-resolve-game.js +271 -0
- package/scripts/test-resolve-signature.js +223 -0
- package/scripts/test-signature-preservation.js +124 -0
- package/scripts/test-state-machine.js +291 -0
- package/scripts/test-webhook-receiver.js +60 -0
- package/scripts/update-notification-constraint.js +52 -0
- package/scripts/verify-account-layout.js +145 -0
- package/scripts/verify-winner-algorithm.js +278 -0
- package/server.js +5259 -0
- package/services/arcadeMatchService.js +763 -0
- package/services/automaticGameOracle.js +1596 -0
- package/services/chatService.js +1612 -0
- package/services/connect4GameService.js +1049 -0
- package/services/connect4NotificationService.js +374 -0
- package/services/cryptoPriceService.js +223 -0
- package/services/customGameResolver.js +260 -0
- package/services/db.js +79 -0
- package/services/directMessageService.js +389 -0
- package/services/discordNotifications.js +160 -0
- package/services/exchangeRateService.js +289 -0
- package/services/expoPushService.js +314 -0
- package/services/gamesCacheService.js +539 -0
- package/services/jackpotHistory.js +331 -0
- package/services/jackpotService.js +856 -0
- package/services/keeperStateService.js +355 -0
- package/services/matchupImageService.js +591 -0
- package/services/notificationCacheService.js +407 -0
- package/services/pickemOracle.js +440 -0
- package/services/playerStatsService.js +389 -0
- package/services/portfolioService.js +555 -0
- package/services/promoService.js +757 -0
- package/services/promoTreasuryService.js +239 -0
- package/services/pushNotifications.js +353 -0
- package/services/redisService.js +422 -0
- package/services/referralEarningsService.js +728 -0
- package/services/s3Service.js +396 -0
- package/services/socialService.js +1202 -0
- package/services/survivorOracle.js +469 -0
- package/services/survivorSimulator.js +475 -0
- package/services/telegramNotifications.js +461 -0
- package/services/userProfileStatsService.js +1185 -0
- package/services/whatsNewService.js +388 -0
- package/utils/urlHelper.js +95 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Automatic Sports Mode - Oracle System
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
The oracle system monitors automatic sports betting games and resolves them based on real-world game outcomes.
|
|
5
|
+
|
|
6
|
+
## Architecture
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
┌─────────────────────┐
|
|
10
|
+
│ Oracle Monitor │ Every 5 minutes
|
|
11
|
+
│ (cron/oracle │ ─────────────────▶
|
|
12
|
+
│ Monitor.js) │
|
|
13
|
+
└─────────────────────┘
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
┌─────────────────────┐
|
|
17
|
+
│ Fetch Pending │ GET /api/auth/games/automatic/pending
|
|
18
|
+
│ Games │ ◀──────────────────
|
|
19
|
+
└─────────────────────┘ dubs-games-api
|
|
20
|
+
│
|
|
21
|
+
▼
|
|
22
|
+
┌─────────────────────┐
|
|
23
|
+
│ Check Live Scores │ GET /api/livescores/:league
|
|
24
|
+
│ for Each Game │ ◀──────────────────
|
|
25
|
+
└─────────────────────┘ dubs-api
|
|
26
|
+
│
|
|
27
|
+
▼
|
|
28
|
+
┌─────────────────────┐
|
|
29
|
+
│ If Game is FINAL: │
|
|
30
|
+
│ - Determine Winner │
|
|
31
|
+
│ - Resolve on-chain │ resolve_automatic_game instruction
|
|
32
|
+
│ - Update Firebase │ POST /api/games/:id/resolve
|
|
33
|
+
└─────────────────────┘
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
┌─────────────────────┐
|
|
37
|
+
│ Winners Claim │ claim_automatic_winnings instruction
|
|
38
|
+
│ Their Payouts │ (called by players)
|
|
39
|
+
└─────────────────────┘
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Setup
|
|
43
|
+
|
|
44
|
+
### 1. Create Oracle Wallet
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run oracle:setup
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This creates an oracle wallet at `wallets/oracle.json` and funds it on devnet.
|
|
51
|
+
|
|
52
|
+
**Save the Oracle Public Key** - you'll need it when creating automatic games!
|
|
53
|
+
|
|
54
|
+
### 2. Configure Environment
|
|
55
|
+
|
|
56
|
+
Copy `env.template` to `.env`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cp env.template .env
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Update values:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# For local development
|
|
66
|
+
SOLANA_NETWORK=http://127.0.0.1:8899
|
|
67
|
+
LIVE_SCORES_API_URL=http://localhost:3000
|
|
68
|
+
DUBS_GAMES_API_URL=http://localhost:3001
|
|
69
|
+
|
|
70
|
+
# For production
|
|
71
|
+
SOLANA_NETWORK=https://api.mainnet-beta.solana.com
|
|
72
|
+
LIVE_SCORES_API_URL=https://dubs-api.herokuapp.com
|
|
73
|
+
DUBS_GAMES_API_URL=https://dubs-games-api.herokuapp.com
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 3. Start the Oracle
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Production mode
|
|
80
|
+
npm run oracle:start
|
|
81
|
+
|
|
82
|
+
# Development mode (auto-restart on changes)
|
|
83
|
+
npm run oracle:dev
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The oracle will:
|
|
87
|
+
- ✅ Check every 5 minutes (configurable)
|
|
88
|
+
- ✅ Find games past their lock time
|
|
89
|
+
- ✅ Query live scores API
|
|
90
|
+
- ✅ Resolve games when sports events finish
|
|
91
|
+
- ✅ Update Firebase with results
|
|
92
|
+
|
|
93
|
+
## How It Works
|
|
94
|
+
|
|
95
|
+
### Game Lifecycle
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
1. User Creates Automatic Game
|
|
99
|
+
- Picks upcoming sports event (e.g., Lakers vs Celtics at 7:00 PM)
|
|
100
|
+
- Sets buy-in amount
|
|
101
|
+
- Oracle wallet address is set
|
|
102
|
+
- Lock time = 6:50 PM (10 min before tip-off)
|
|
103
|
+
|
|
104
|
+
2. Players Join & Pick Teams
|
|
105
|
+
- Alice picks Lakers (home) - 0.5 SOL
|
|
106
|
+
- Bob picks Celtics (away) - 0.5 SOL
|
|
107
|
+
- Carol picks Lakers (home) - 0.5 SOL
|
|
108
|
+
- Total pot: 1.5 SOL
|
|
109
|
+
|
|
110
|
+
3. Lock Time Arrives (6:50 PM)
|
|
111
|
+
- Game auto-locks
|
|
112
|
+
- No more joins allowed
|
|
113
|
+
|
|
114
|
+
4. Real Game Happens (7:00 PM - 9:30 PM)
|
|
115
|
+
- Lakers vs Celtics plays out
|
|
116
|
+
- Oracle monitor checks every 5 minutes
|
|
117
|
+
|
|
118
|
+
5. Game Finishes (9:30 PM)
|
|
119
|
+
- Oracle detects: Lakers won 110-105
|
|
120
|
+
- Calls resolve_automatic_game on-chain
|
|
121
|
+
- Sets winning_team = Home
|
|
122
|
+
- Updates Firebase
|
|
123
|
+
|
|
124
|
+
6. Winners Claim Payouts
|
|
125
|
+
- Alice calls claim_automatic_winnings → Gets 0.75 SOL
|
|
126
|
+
- Carol calls claim_automatic_winnings → Gets 0.75 SOL
|
|
127
|
+
- Bob gets nothing (picked wrong team)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Score Matching Logic
|
|
131
|
+
|
|
132
|
+
The oracle uses fuzzy team name matching:
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
normalizeTeamName("Los Angeles Lakers") → "lakers"
|
|
136
|
+
normalizeTeamName("LA Lakers") → "lakers"
|
|
137
|
+
normalizeTeamName("Lakers") → "lakers"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This ensures games are matched even if team names differ slightly between APIs.
|
|
141
|
+
|
|
142
|
+
## Files
|
|
143
|
+
|
|
144
|
+
| File | Purpose |
|
|
145
|
+
|------|---------|
|
|
146
|
+
| `services/automaticGameOracle.js` | Oracle service class |
|
|
147
|
+
| `cron/oracleMonitor.js` | Cron job runner |
|
|
148
|
+
| `setup-oracle.sh` | Oracle wallet setup script |
|
|
149
|
+
| `env.template` | Environment variables template |
|
|
150
|
+
|
|
151
|
+
## API Integration
|
|
152
|
+
|
|
153
|
+
### dubs-games-api Endpoints Used:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
GET /api/auth/games/automatic/pending
|
|
157
|
+
POST /api/games/:gameId/resolve
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### dubs-api Endpoints Used:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
GET /api/livescores/:league
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
```json
|
|
168
|
+
[
|
|
169
|
+
{
|
|
170
|
+
"date": "2025-10-27",
|
|
171
|
+
"game": "Lakers vs Celtics",
|
|
172
|
+
"status": "Final",
|
|
173
|
+
"competitors": [
|
|
174
|
+
{ "name": "Los Angeles Lakers", "homeAway": "home", "score": 110 },
|
|
175
|
+
{ "name": "Boston Celtics", "homeAway": "away", "score": 105 }
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Monitoring
|
|
182
|
+
|
|
183
|
+
### Check Oracle Status
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# Check if oracle process is running
|
|
187
|
+
ps aux | grep oracleMonitor
|
|
188
|
+
|
|
189
|
+
# View logs
|
|
190
|
+
tail -f /path/to/your/logs
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Manual Resolution (if needed)
|
|
194
|
+
|
|
195
|
+
If oracle misses a game, you can manually trigger resolution:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
curl -X POST http://localhost:3001/api/games/adam-amy-001/resolve \
|
|
199
|
+
-H "Content-Type: application/json" \
|
|
200
|
+
-d '{
|
|
201
|
+
"winner": "home",
|
|
202
|
+
"homeScore": 105,
|
|
203
|
+
"awayScore": 98,
|
|
204
|
+
"resolvedBy": "manual"
|
|
205
|
+
}'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Security
|
|
209
|
+
|
|
210
|
+
### Oracle Authorization
|
|
211
|
+
|
|
212
|
+
- Only the designated oracle wallet can resolve games
|
|
213
|
+
- Validated on-chain: `require!(oracle.key() == game.oracle)`
|
|
214
|
+
- Oracle private key must be kept secure
|
|
215
|
+
|
|
216
|
+
### Best Practices
|
|
217
|
+
|
|
218
|
+
1. **Secure the Oracle Wallet**
|
|
219
|
+
- Keep `wallets/oracle.json` in `.gitignore`
|
|
220
|
+
- Use environment variables in production
|
|
221
|
+
- Consider hardware wallet for mainnet
|
|
222
|
+
|
|
223
|
+
2. **Monitor Oracle Health**
|
|
224
|
+
- Set up alerts if oracle stops
|
|
225
|
+
- Log all resolution attempts
|
|
226
|
+
- Have backup oracle wallet ready
|
|
227
|
+
|
|
228
|
+
3. **Handle Edge Cases**
|
|
229
|
+
- Postponed games → Manual resolution
|
|
230
|
+
- Cancelled games → Refund all players
|
|
231
|
+
- API downtime → Retry logic
|
|
232
|
+
|
|
233
|
+
## Testing
|
|
234
|
+
|
|
235
|
+
### Test the Oracle Locally
|
|
236
|
+
|
|
237
|
+
1. Start local validator:
|
|
238
|
+
```bash
|
|
239
|
+
solana-test-validator --reset
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
2. Deploy program:
|
|
243
|
+
```bash
|
|
244
|
+
anchor deploy
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
3. Setup oracle:
|
|
248
|
+
```bash
|
|
249
|
+
npm run oracle:setup
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
4. Create test game (with mock event that's already finished):
|
|
253
|
+
```bash
|
|
254
|
+
curl -X POST http://localhost:3001/api/auth/games/save \
|
|
255
|
+
-d '{ "gameId": "test-001", "sportsEvent": {...} }'
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
5. Start oracle:
|
|
259
|
+
```bash
|
|
260
|
+
npm run oracle:dev
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
6. Watch logs - oracle should detect and resolve the game!
|
|
264
|
+
|
|
265
|
+
## Production Deployment
|
|
266
|
+
|
|
267
|
+
### Heroku
|
|
268
|
+
|
|
269
|
+
Add to `Procfile`:
|
|
270
|
+
```
|
|
271
|
+
web: node server.js
|
|
272
|
+
oracle: node cron/oracleMonitor.js
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Then scale:
|
|
276
|
+
```bash
|
|
277
|
+
heroku ps:scale web=1 oracle=1
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Environment Variables
|
|
281
|
+
|
|
282
|
+
Set in Heroku:
|
|
283
|
+
```bash
|
|
284
|
+
heroku config:set ORACLE_WALLET_PATH=/app/wallets/oracle.json
|
|
285
|
+
heroku config:set LIVE_SCORES_API_URL=https://dubs-api.herokuapp.com
|
|
286
|
+
heroku config:set DUBS_GAMES_API_URL=https://dubs-games-api.herokuapp.com
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Troubleshooting
|
|
290
|
+
|
|
291
|
+
### Oracle not resolving games
|
|
292
|
+
|
|
293
|
+
1. Check oracle is running: `ps aux | grep oracle`
|
|
294
|
+
2. Check API connectivity: `curl $LIVE_SCORES_API_URL/api/livescores/NBA`
|
|
295
|
+
3. Check pending games exist: `curl $DUBS_GAMES_API_URL/api/auth/games/automatic/pending`
|
|
296
|
+
4. Check oracle wallet has SOL for transactions
|
|
297
|
+
|
|
298
|
+
### Games resolved with wrong winner
|
|
299
|
+
|
|
300
|
+
1. Check live scores API response format
|
|
301
|
+
2. Verify team name normalization logic
|
|
302
|
+
3. Check date matching (timezone issues?)
|
|
303
|
+
|
|
304
|
+
### Transactions failing
|
|
305
|
+
|
|
306
|
+
1. Oracle wallet needs SOL for transaction fees
|
|
307
|
+
2. Check program ID is correct
|
|
308
|
+
3. Verify game exists on-chain
|
|
309
|
+
|
|
310
|
+
## Future Enhancements
|
|
311
|
+
|
|
312
|
+
- [ ] Multi-oracle consensus (2-of-3 oracles must agree)
|
|
313
|
+
- [ ] Automatic refunds for postponed/cancelled games
|
|
314
|
+
- [ ] Discord/Telegram notifications when games resolve
|
|
315
|
+
- [ ] Dashboard for monitoring oracle health
|
|
316
|
+
- [ ] Automatic oracle wallet top-up
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
**Phase 3: Oracle System** ✅ Complete!
|
|
321
|
+
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# 🐛 Bug Fix: Cohort Date Display - "Nov 30, 2025" Issue
|
|
2
|
+
|
|
3
|
+
## Problem Identified
|
|
4
|
+
|
|
5
|
+
**User Report:**
|
|
6
|
+
> "How can we have more than 20 users but only 7 signups - this data makes no sense"
|
|
7
|
+
|
|
8
|
+
**Screenshot showed:**
|
|
9
|
+
- Cohort labeled: "December 2025" with subtitle "Nov 30, 2025"
|
|
10
|
+
- 7 signups in that cohort
|
|
11
|
+
- Data seemed inconsistent
|
|
12
|
+
|
|
13
|
+
## Root Cause Analysis
|
|
14
|
+
|
|
15
|
+
### Investigation Results (dubs-server-dev):
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Total Unique Users: 7
|
|
19
|
+
Total registration_completed Events: 11
|
|
20
|
+
Date Range: Dec 14, 2025 to Dec 31, 2025
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**All 7 users signed up in DECEMBER**, but the label showed "Nov 30, 2025"!
|
|
24
|
+
|
|
25
|
+
### The Bug
|
|
26
|
+
|
|
27
|
+
When PostgreSQL returns monthly cohort data:
|
|
28
|
+
```sql
|
|
29
|
+
DATE_TRUNC('month', '2025-12-15')
|
|
30
|
+
-- Returns: 2025-12-01T00:00:00.000Z (December 1st, UTC)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
JavaScript's `toLocaleDateString()` without timezone specification:
|
|
34
|
+
```javascript
|
|
35
|
+
new Date('2025-12-01T00:00:00.000Z').toLocaleDateString('en-US')
|
|
36
|
+
// In PST timezone: "Nov 30, 2025" ❌ (off by one day!)
|
|
37
|
+
// Should be: "December 2025" ✅
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Why it happens:**
|
|
41
|
+
- PostgreSQL stores dates in UTC
|
|
42
|
+
- `DATE_TRUNC('month')` returns midnight UTC on the 1st of the month
|
|
43
|
+
- JavaScript `toLocaleDateString()` converts to local timezone
|
|
44
|
+
- In Pacific timezone (UTC-8), midnight UTC on Dec 1 = 4pm Nov 30
|
|
45
|
+
- Result: **November 30 displayed instead of December!**
|
|
46
|
+
|
|
47
|
+
## The Fix
|
|
48
|
+
|
|
49
|
+
### Backend (routes/analyticsRoutes.js)
|
|
50
|
+
|
|
51
|
+
**Before:**
|
|
52
|
+
```javascript
|
|
53
|
+
dateRange = cohortDate.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**After:**
|
|
57
|
+
```javascript
|
|
58
|
+
dateRange = cohortDate.toLocaleDateString('en-US', {
|
|
59
|
+
month: 'long',
|
|
60
|
+
year: 'numeric',
|
|
61
|
+
timeZone: 'UTC' // ✅ Force UTC interpretation
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Frontend (AnalyticsDashboard.tsx)
|
|
66
|
+
|
|
67
|
+
**Before:**
|
|
68
|
+
```javascript
|
|
69
|
+
{new Date(cohort.signup_cohort).toLocaleDateString('en-US', {
|
|
70
|
+
month: 'short', day: 'numeric', year: 'numeric'
|
|
71
|
+
})}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**After:**
|
|
75
|
+
```javascript
|
|
76
|
+
{new Date(cohort.signup_cohort).toLocaleDateString('en-US', {
|
|
77
|
+
month: 'short', day: 'numeric', year: 'numeric',
|
|
78
|
+
timeZone: 'UTC' // ✅ Force UTC interpretation
|
|
79
|
+
})}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Files Changed
|
|
83
|
+
|
|
84
|
+
1. **Backend:** `routes/analyticsRoutes.js`
|
|
85
|
+
- Fixed `GET /api/analytics/cohort-retention` date formatting (line ~997-1000)
|
|
86
|
+
- Fixed `GET /api/analytics/cohort-retention/csv` date formatting (line ~1166-1172)
|
|
87
|
+
|
|
88
|
+
2. **Frontend:** `app/v2/components/overlay/AnalyticsDashboard.tsx`
|
|
89
|
+
- Fixed cohort subtitle date display (line ~1160)
|
|
90
|
+
|
|
91
|
+
## Testing
|
|
92
|
+
|
|
93
|
+
### Before Fix (Dev Database):
|
|
94
|
+
```
|
|
95
|
+
Cohort: December 2025
|
|
96
|
+
Subtitle: Nov 30, 2025 ❌ WRONG
|
|
97
|
+
Signups: 7
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### After Fix (Expected):
|
|
101
|
+
```
|
|
102
|
+
Cohort: December 2025
|
|
103
|
+
Subtitle: Dec 1, 2025 ✅ CORRECT
|
|
104
|
+
Signups: 7
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Verification Steps
|
|
108
|
+
|
|
109
|
+
1. **Deploy fixes to dev:**
|
|
110
|
+
```bash
|
|
111
|
+
cd /Users/adamdahan/Developer/iheartsolana/solana-programs/dubs-server
|
|
112
|
+
git add routes/analyticsRoutes.js
|
|
113
|
+
git commit -m "fix: Cohort date display timezone bug"
|
|
114
|
+
git push heroku-dev main
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
2. **Refresh dashboard:**
|
|
118
|
+
- Open dubs-jackpot-spa in dev
|
|
119
|
+
- Navigate to Analytics Dashboard
|
|
120
|
+
- Expand "Cohort Retention Analysis"
|
|
121
|
+
- Verify "December 2025" shows correct date
|
|
122
|
+
|
|
123
|
+
3. **Test CSV export:**
|
|
124
|
+
- Click "Export CSV"
|
|
125
|
+
- Open file
|
|
126
|
+
- Verify dates are correct
|
|
127
|
+
|
|
128
|
+
## Impact
|
|
129
|
+
|
|
130
|
+
**Before:**
|
|
131
|
+
- ❌ Confusing "Nov 30, 2025" label for December cohort
|
|
132
|
+
- ❌ Off-by-one-day errors in weekly cohorts
|
|
133
|
+
- ❌ Users questioning data accuracy
|
|
134
|
+
|
|
135
|
+
**After:**
|
|
136
|
+
- ✅ Correct month/year labels
|
|
137
|
+
- ✅ Accurate date ranges
|
|
138
|
+
- ✅ Clear, trustworthy data presentation
|
|
139
|
+
|
|
140
|
+
## Related Issues
|
|
141
|
+
|
|
142
|
+
This timezone bug affected:
|
|
143
|
+
1. Monthly cohort labels (most visible)
|
|
144
|
+
2. Weekly cohort date ranges
|
|
145
|
+
3. CSV export headers
|
|
146
|
+
4. Frontend subtitle displays
|
|
147
|
+
|
|
148
|
+
All fixed with `timeZone: 'UTC'` parameter!
|
|
149
|
+
|
|
150
|
+
## Lessons Learned
|
|
151
|
+
|
|
152
|
+
1. **Always specify timezone** when formatting dates from database
|
|
153
|
+
2. **PostgreSQL returns UTC** - JavaScript must interpret as UTC
|
|
154
|
+
3. **Test across timezones** - PST/EST/UTC can show different dates
|
|
155
|
+
4. **Use UTC for cohort logic** - Business logic should be timezone-agnostic
|
|
156
|
+
|
|
157
|
+
## Prevention
|
|
158
|
+
|
|
159
|
+
Add to code review checklist:
|
|
160
|
+
- [ ] All `toLocaleDateString()` calls have `timeZone` specified
|
|
161
|
+
- [ ] Date formatting uses UTC for database timestamps
|
|
162
|
+
- [ ] Test in different timezones (PST, EST, UTC)
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
**Status:** ✅ FIXED
|
|
167
|
+
**Deployed:** Pending (commit ready)
|
|
168
|
+
**Impact:** High (user-facing data display)
|
|
169
|
+
**Complexity:** Low (timezone parameter addition)
|
|
170
|
+
|
|
171
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Add Claim Columns Migration
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
The claim endpoint is failing with:
|
|
5
|
+
```
|
|
6
|
+
ERROR: column "claimed_at" of relation "user_game_refs" does not exist
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Solution
|
|
10
|
+
Run this migration to add claim tracking columns to the `user_game_refs` table.
|
|
11
|
+
|
|
12
|
+
## Run on Heroku:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Option 1: Via Heroku CLI
|
|
16
|
+
heroku pg:psql --app dubs-server-dev < scripts/add-claim-columns.sql
|
|
17
|
+
|
|
18
|
+
# Option 2: Interactive
|
|
19
|
+
heroku pg:psql --app dubs-server-dev
|
|
20
|
+
# Then paste the SQL from add-claim-columns.sql
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## What It Adds:
|
|
24
|
+
|
|
25
|
+
| Column | Type | Purpose |
|
|
26
|
+
|--------|------|---------|
|
|
27
|
+
| `claimed_at` | TIMESTAMP | When user claimed prize |
|
|
28
|
+
| `claim_signature` | TEXT | Solana transaction signature |
|
|
29
|
+
| `claim_explorer_url` | TEXT | Explorer link for claim tx |
|
|
30
|
+
| `amount_claimed` | DECIMAL(20,9) | Amount of SOL claimed |
|
|
31
|
+
|
|
32
|
+
## Verify:
|
|
33
|
+
|
|
34
|
+
After running, you should see:
|
|
35
|
+
```
|
|
36
|
+
NOTICE: Added claimed_at column
|
|
37
|
+
NOTICE: Added claim_signature column
|
|
38
|
+
NOTICE: Added claim_explorer_url column
|
|
39
|
+
NOTICE: Added amount_claimed column
|
|
40
|
+
|
|
41
|
+
column_name | data_type
|
|
42
|
+
---------------------+-----------
|
|
43
|
+
amount_claimed | numeric
|
|
44
|
+
claim_explorer_url | text
|
|
45
|
+
claim_signature | text
|
|
46
|
+
claimed_at | timestamp
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Test:
|
|
50
|
+
|
|
51
|
+
After migration, try claiming a prize again. It should work!
|
|
52
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Claim Status Fix - Deployed ✅
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
The MyGamesWidget was showing already-claimed games as still "Claimable". When users tried to claim, they got the error: "You have already claimed your winnings for this game"
|
|
5
|
+
|
|
6
|
+
## Root Cause
|
|
7
|
+
The backend API endpoint `GET /api/auth/games/user/:walletAddress` was **not returning** the `claimedAt` field, even though it existed in the database. This meant the frontend had no way to detect if a game had already been claimed.
|
|
8
|
+
|
|
9
|
+
## What Was Fixed
|
|
10
|
+
|
|
11
|
+
### 1. Backend API Response (routes/gamesRoutes.js)
|
|
12
|
+
Added claim-related fields to the API response:
|
|
13
|
+
- `claimedAt` - Timestamp when user claimed
|
|
14
|
+
- `claimSignature` - Solana transaction signature
|
|
15
|
+
- `claimExplorerUrl` - Explorer link for the claim transaction
|
|
16
|
+
- `amountClaimed` - Amount of SOL claimed
|
|
17
|
+
|
|
18
|
+
### 2. Table Schema (routes/gamesRoutes.js)
|
|
19
|
+
Updated the `user_game_refs` table creation to include claim columns by default:
|
|
20
|
+
- `claimed_at TIMESTAMP`
|
|
21
|
+
- `claim_signature TEXT`
|
|
22
|
+
- `claim_explorer_url TEXT`
|
|
23
|
+
- `amount_claimed DECIMAL(20, 9)`
|
|
24
|
+
- `updated_at TIMESTAMP DEFAULT NOW()`
|
|
25
|
+
|
|
26
|
+
### 3. Migration Script (scripts/fix-claim-columns.js)
|
|
27
|
+
Created a migration script to add these columns to existing databases.
|
|
28
|
+
|
|
29
|
+
## Database Status
|
|
30
|
+
✅ All claim columns already exist in the Heroku database (they were added previously)
|
|
31
|
+
✅ Verified columns with correct data types
|
|
32
|
+
|
|
33
|
+
## Deployment
|
|
34
|
+
- **Committed**: 4e8f22e
|
|
35
|
+
- **Deployed to Heroku**: v179
|
|
36
|
+
- **Pushed to GitHub**: ✅
|
|
37
|
+
|
|
38
|
+
## How It Works Now
|
|
39
|
+
|
|
40
|
+
1. User views their games in MyGamesWidget
|
|
41
|
+
2. API returns `claimedAt` field for each game
|
|
42
|
+
3. Frontend checks `game.claimedAt` at line 109:
|
|
43
|
+
```typescript
|
|
44
|
+
if (game.claimedAt) {
|
|
45
|
+
return 'claimed';
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
4. Already-claimed games show blue "✓ Claimed" status
|
|
49
|
+
5. Only truly claimable games show green "💰 Claimable" status
|
|
50
|
+
|
|
51
|
+
## Testing
|
|
52
|
+
To test with your wallet `3sgQXvLKs4XfBTxG3jY2J2E5NougemfC6i4nZbUVx8xt`:
|
|
53
|
+
|
|
54
|
+
**Expected Results:**
|
|
55
|
+
- `sport-1764428545106-jeet2jl9s`: Shows as "Claimed" (claimed on Nov 29)
|
|
56
|
+
- `sport-1764428315170-5bq7g8tqe`: Shows as "Claimable" (not claimed yet)
|
|
57
|
+
- Other games show appropriate status based on win/loss
|
|
58
|
+
|
|
59
|
+
## Next Steps
|
|
60
|
+
Just refresh your dubs-jackpot app - the API is now returning the claim status correctly!
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|