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.
Files changed (304) hide show
  1. package/.claude/settings.local.json +280 -0
  2. package/CLAUDE.md +46 -0
  3. package/CONNECT4_PRODUCTION_DEPLOY.md +155 -0
  4. package/CURRENT_SESSION.md +171 -0
  5. package/CURRENT_SESSION_DRAW.md +516 -0
  6. package/MARCH_MADNESS_SURVIVOR.md +254 -0
  7. package/PANDA.md +166 -0
  8. package/Procfile +4 -0
  9. package/README.md +476 -0
  10. package/controllers/livescoresController.js +376 -0
  11. package/controllers/pickemController.js +554 -0
  12. package/controllers/survivorAdminController.js +887 -0
  13. package/controllers/survivorController.js +623 -0
  14. package/cron/oracleMonitor.js +77 -0
  15. package/cron/pickemOracleMonitor.js +73 -0
  16. package/data/jackpot-history.json +952 -0
  17. package/data/ncaaTeams.js +406 -0
  18. package/documentation/API_SECURITY_GUIDE.md +327 -0
  19. package/documentation/ARCADE_API.md +593 -0
  20. package/documentation/ARCADE_IMPLEMENTATION_SUMMARY.md +399 -0
  21. package/documentation/ARCADE_QUICKSTART.md +242 -0
  22. package/documentation/AUTOMATIC_MODE_ORACLE.md +321 -0
  23. package/documentation/BUG_FIX_COHORT_DATE_DISPLAY.md +171 -0
  24. package/documentation/CLAIM_MIGRATION_INSTRUCTIONS.md +52 -0
  25. package/documentation/CLAIM_STATUS_FIX.md +67 -0
  26. package/documentation/CLI_TOOL_GUIDE.md +372 -0
  27. package/documentation/COHORT_RETENTION_ANALYSIS.md +295 -0
  28. package/documentation/COHORT_RETENTION_IMPLEMENTATION_COMPLETE.md +461 -0
  29. package/documentation/COHORT_RETENTION_SUMMARY.md +204 -0
  30. package/documentation/COMPLETE_PROJECT_SUMMARY.md +490 -0
  31. package/documentation/DATABASE_QUERIES.md +269 -0
  32. package/documentation/DATABASE_RETENTION_POLICY.md +390 -0
  33. package/documentation/DATABASE_SETUP_GUIDE.md +361 -0
  34. package/documentation/DATABASE_SETUP_SUMMARY.md +247 -0
  35. package/documentation/DEMO_API_CURL_COMMANDS.md +656 -0
  36. package/documentation/DEPLOYMENT_SUMMARY.txt +100 -0
  37. package/documentation/DUPLICATE_NOTIFICATIONS_FIXED.md +201 -0
  38. package/documentation/EXCHANGE_RATES_INTEGRATION.md +371 -0
  39. package/documentation/FINAL_API_PROTECTION_TABLE.md +175 -0
  40. package/documentation/GAME_START_NOTIFICATIONS_DEPLOYMENT.md +256 -0
  41. package/documentation/GAME_START_NOTIFICATIONS_INTEGRATION.md +275 -0
  42. package/documentation/HEROKU_DEPLOYMENT.md +134 -0
  43. package/documentation/HEROKU_SCHEDULER_SETUP.md +271 -0
  44. package/documentation/JACKPOT_API.md +521 -0
  45. package/documentation/JACKPOT_DEPLOYMENT_GUIDE.md +362 -0
  46. package/documentation/JWT_IMPLEMENTATION_SUMMARY.md +373 -0
  47. package/documentation/JWT_QUICK_SETUP.md +268 -0
  48. package/documentation/JWT_TESTING_GUIDE.md +404 -0
  49. package/documentation/KEEPER_RECOVERY_GUIDE.md +381 -0
  50. package/documentation/KEEPER_SETUP.md +206 -0
  51. package/documentation/KEEPER_STATE_MACHINE.md +423 -0
  52. package/documentation/LATEST_PRODUCTION_SETUP.md +387 -0
  53. package/documentation/LOCAL_VOTING_TEST.md +279 -0
  54. package/documentation/ORACLE_FIXES_SUMMARY.md +188 -0
  55. package/documentation/ORACLE_POSTGRESQL_UPDATE.md +202 -0
  56. package/documentation/PAYMENT_DEPLOYMENT.md +209 -0
  57. package/documentation/PNL_TRACKING_SETUP.md +189 -0
  58. package/documentation/PREVENTING_LOCKUP_ERRORS.md +472 -0
  59. package/documentation/PRODUCTION_READY_SUMMARY.md +227 -0
  60. package/documentation/PUBLIC_VS_PRIVATE_ENDPOINTS.md +278 -0
  61. package/documentation/QUICK_AUTH_SETUP.md +99 -0
  62. package/documentation/QUICK_DEPLOY.md +224 -0
  63. package/documentation/QUICK_FIX.md +114 -0
  64. package/documentation/QUICK_START.md +152 -0
  65. package/documentation/REFEREE_MODE_GUIDE.md +392 -0
  66. package/documentation/RETENTION_CORE_ACTION_UPDATE.md +313 -0
  67. package/documentation/RETENTION_UPDATE_SUMMARY.md +108 -0
  68. package/documentation/RUN_MIGRATION_NOW.md +39 -0
  69. package/documentation/SCRIPTS_UPDATE_SUMMARY.md +251 -0
  70. package/documentation/SETUP_GUIDE.md +184 -0
  71. package/documentation/STATE_MACHINE_IMPLEMENTATION.md +250 -0
  72. package/documentation/TELEGRAM_NOTIFICATIONS_DIAGNOSIS.md +361 -0
  73. package/documentation/UNIFIED_ARCHITECTURE.md +231 -0
  74. package/documentation/VOTING_DEPLOYMENT_SUMMARY.md +392 -0
  75. package/documentation/WEBSOCKET_ARCHITECTURE.md +881 -0
  76. package/documentation/WHAT_WE_BUILT_TODAY.md +369 -0
  77. package/documentation/latest/LATEST_PRODUCTION_SETUP.md +865 -0
  78. package/ecosystem.config.js +65 -0
  79. package/env.template +125 -0
  80. package/middleware/apiKeyAuth.js +136 -0
  81. package/middleware/authenticate.js +214 -0
  82. package/middleware/developerUserAuth.js +76 -0
  83. package/middleware/socketAuth.js +69 -0
  84. package/package.json +49 -0
  85. package/postman/Dubs-API-v1-With-Voting.postman_collection.json +555 -0
  86. package/postman/Dubs-API-v1.postman_collection.json +205 -0
  87. package/postman/Dubs_Developer_API.postman_collection.json +662 -0
  88. package/postman/QUICKSTART.md +118 -0
  89. package/postman/QUICK_REFERENCE.md +246 -0
  90. package/postman/README.md +71 -0
  91. package/postman/VOTING_API_GUIDE.md +426 -0
  92. package/refactor/Animations.md +148 -0
  93. package/refactor/Chat.md +252 -0
  94. package/routes/actionsRoutes.js +699 -0
  95. package/routes/adminRoutes.js +370 -0
  96. package/routes/analyticsRoutes.js +1262 -0
  97. package/routes/arcadeRoutes.js +557 -0
  98. package/routes/authRoutes.js +2310 -0
  99. package/routes/avatarRoutes.js +85 -0
  100. package/routes/botRoutes.js +211 -0
  101. package/routes/chatRoutes.js +377 -0
  102. package/routes/cryptoPriceRoutes.js +105 -0
  103. package/routes/developerRoutes.js +4201 -0
  104. package/routes/deviceRoutes.js +214 -0
  105. package/routes/dmRoutes.js +167 -0
  106. package/routes/esportsRoutes.js +806 -0
  107. package/routes/exchangeRateRoutes.js +233 -0
  108. package/routes/gamesRoutes.js +3028 -0
  109. package/routes/jackpotRoutes.js +754 -0
  110. package/routes/keeperMonitoringRoutes.js +156 -0
  111. package/routes/keeperWebhookRoutes.js +466 -0
  112. package/routes/livescoresRoutes.js +31 -0
  113. package/routes/pickemAdminRoutes.js +199 -0
  114. package/routes/pickemRoutes.js +231 -0
  115. package/routes/playerStatsRoutes.js +147 -0
  116. package/routes/portfolioRoutes.js +217 -0
  117. package/routes/promoRoutes.js +418 -0
  118. package/routes/referralEarningsRoutes.js +392 -0
  119. package/routes/socialRoutes.js +459 -0
  120. package/routes/sportsRoutes.js +1271 -0
  121. package/routes/survivorAdminRoutes.js +345 -0
  122. package/routes/survivorRoutes.js +756 -0
  123. package/routes/uploadRoutes.js +256 -0
  124. package/routes/userProfileRoutes.js +244 -0
  125. package/routes/whatsNewRoutes.js +331 -0
  126. package/scripts/.claude/settings.local.json +15 -0
  127. package/scripts/README.md +170 -0
  128. package/scripts/RESTART_EVERYTHING.sh +104 -0
  129. package/scripts/add-claim-columns.sql +48 -0
  130. package/scripts/add-crypto-prices-cache.sql +27 -0
  131. package/scripts/add-exchange-rates-cache.sql +40 -0
  132. package/scripts/add-game-invite-column.sql +23 -0
  133. package/scripts/add-game-invite-notification.sql +33 -0
  134. package/scripts/add-game-invite-telegram-pref.sql +16 -0
  135. package/scripts/add-game-joined-notification.sql +16 -0
  136. package/scripts/add-game-joined-pref.js +40 -0
  137. package/scripts/add-game-joined-preference.sql +6 -0
  138. package/scripts/add-game-start-notifications.sql +41 -0
  139. package/scripts/add-notification-flags-to-games.sql +55 -0
  140. package/scripts/add-pending-game-dismissals.sql +19 -0
  141. package/scripts/add-preferred-currency.sql +34 -0
  142. package/scripts/add-winner-columns.js +61 -0
  143. package/scripts/add_mention_system.sql +53 -0
  144. package/scripts/add_payment_system.sql +96 -0
  145. package/scripts/add_sports_event_id_column.sql +22 -0
  146. package/scripts/analyze-cohort-data-heroku.js +276 -0
  147. package/scripts/analyze-cohort-data.js +295 -0
  148. package/scripts/analyze-prod-cohorts.sh +10 -0
  149. package/scripts/backfill-matchup-images.js +245 -0
  150. package/scripts/backfill-missing-signatures.js +175 -0
  151. package/scripts/backfill-referral-earnings.js +202 -0
  152. package/scripts/check-chat-schema.js +130 -0
  153. package/scripts/check-db.sh +14 -0
  154. package/scripts/check_oracle_in_game.js +54 -0
  155. package/scripts/cleanup-database.js +193 -0
  156. package/scripts/clear-notification-cache.js +85 -0
  157. package/scripts/convert-mnemonic.js +50 -0
  158. package/scripts/create-users-table.sql +44 -0
  159. package/scripts/debug-cohort-counts.js +248 -0
  160. package/scripts/debug-winner-calc.js +84 -0
  161. package/scripts/deploy-payment-system.sh +118 -0
  162. package/scripts/deploy-to-heroku.sh +63 -0
  163. package/scripts/diagnose-locked-round.js +143 -0
  164. package/scripts/dubs-cli.js +720 -0
  165. package/scripts/dump-account.js +65 -0
  166. package/scripts/find-vrf-offset.js +48 -0
  167. package/scripts/fix-chat-notifications-constraint.sql +122 -0
  168. package/scripts/fix-claim-columns.js +124 -0
  169. package/scripts/fix-constraint-now.js +44 -0
  170. package/scripts/fix-lock-timestamps.js +96 -0
  171. package/scripts/fix-locked-round.sh +126 -0
  172. package/scripts/fix-missing-badges.sql +91 -0
  173. package/scripts/fix-payment-notifications.sql +41 -0
  174. package/scripts/force-new-round.js +55 -0
  175. package/scripts/force-resolve-and-claim.js +278 -0
  176. package/scripts/important/README.md +115 -0
  177. package/scripts/important/authority-force-lock.js +197 -0
  178. package/scripts/important/authority-resolve-game.js +267 -0
  179. package/scripts/important/check-game-status.js +373 -0
  180. package/scripts/important/list-pending-games-by-version.js +270 -0
  181. package/scripts/important/reconcile-v1-v2-payouts.js +270 -0
  182. package/scripts/initialize-jackpot.js +111 -0
  183. package/scripts/jackpot/.claude/settings.local.json +10 -0
  184. package/scripts/jackpot/force-reset.js +84 -0
  185. package/scripts/jackpot/initialize-mainnet.js +100 -0
  186. package/scripts/jackpot/keeper.js +742 -0
  187. package/scripts/jackpot/status.js +107 -0
  188. package/scripts/jackpot/update-round-duration.js +143 -0
  189. package/scripts/keeper-bot.js +112 -0
  190. package/scripts/list-pending-games.js +131 -0
  191. package/scripts/migrate-chat-v2.js +127 -0
  192. package/scripts/migrate-chat-winners.js +84 -0
  193. package/scripts/migrate-chat.sh +17 -0
  194. package/scripts/migrate-game-invite.js +83 -0
  195. package/scripts/migrate-heroku-game-notifications.sh +159 -0
  196. package/scripts/migrations/001_analytics_tables.sql +422 -0
  197. package/scripts/migrations/002_add_matchup_image_url.sql +14 -0
  198. package/scripts/migrations/003_referral_earnings.sql +208 -0
  199. package/scripts/migrations/004_add_whats_new_notification_type.sql +62 -0
  200. package/scripts/migrations/005_add_connect4_your_turn_notification.sql +61 -0
  201. package/scripts/migrations/005_push_notifications.sql +55 -0
  202. package/scripts/migrations/006_add_draw_team_players.sql +28 -0
  203. package/scripts/migrations/006_add_game_cancelled_notification.sql +62 -0
  204. package/scripts/migrations/007_add_gif_url.sql +8 -0
  205. package/scripts/migrations/008_add_connect4_columns.sql +139 -0
  206. package/scripts/migrations/008_add_pool_tracking.sql +22 -0
  207. package/scripts/migrations/009_create_survivor_pool_tables.sql +174 -0
  208. package/scripts/migrations/010_add_survivor_pool_outcome.sql +28 -0
  209. package/scripts/migrations/011_create_developer_tables.sql +67 -0
  210. package/scripts/migrations/011_fix_keeper_tables.sql +85 -0
  211. package/scripts/migrations/012_create_developer_webhooks.sql +31 -0
  212. package/scripts/migrations/013_add_network_mode.sql +18 -0
  213. package/scripts/migrations/014_create_developer_app_users.sql +19 -0
  214. package/scripts/migrations/015_add_ui_config.sql +4 -0
  215. package/scripts/migrations/016_add_resolution_secret.sql +4 -0
  216. package/scripts/migrations/017_add_external_game_id.sql +3 -0
  217. package/scripts/migrations/018_create_pickem_tables.sql +115 -0
  218. package/scripts/migrations/019_expo_push_tokens.sql +19 -0
  219. package/scripts/migrations/create_whats_new_tables.sql +88 -0
  220. package/scripts/migrations/drop_live_games_tables.sql +34 -0
  221. package/scripts/open-jackpot-round.js +85 -0
  222. package/scripts/purge-all-data.sh +329 -0
  223. package/scripts/purge-all-data.sql +142 -0
  224. package/scripts/purge-heroku-data.sh +149 -0
  225. package/scripts/purge-heroku-data.sql +62 -0
  226. package/scripts/rebuild-heroku-database.sh +113 -0
  227. package/scripts/recover-funds.js +357 -0
  228. package/scripts/regenerate-epl-images.js +278 -0
  229. package/scripts/resize-s3-matchup-images.js +374 -0
  230. package/scripts/resolve-direct.js +88 -0
  231. package/scripts/resolve-mock-game.js +124 -0
  232. package/scripts/resolve-pickem-game.js +55 -0
  233. package/scripts/resolve-round-manual.js +83 -0
  234. package/scripts/resolve-stuck-game.js +382 -0
  235. package/scripts/resolve-stuck-round.js +42 -0
  236. package/scripts/run-connect4-migration.sh +16 -0
  237. package/scripts/run-mention-migration.sh +32 -0
  238. package/scripts/run-payment-migration.sh +51 -0
  239. package/scripts/run-preferred-currency-migration.sh +31 -0
  240. package/scripts/run-referral-earnings-migration.sh +32 -0
  241. package/scripts/run-survivor-outcome-migration.sh +16 -0
  242. package/scripts/seed-test-users.js +346 -0
  243. package/scripts/setup-auth-tables.js +78 -0
  244. package/scripts/setup-complete-database.sql +992 -0
  245. package/scripts/setup-database-fresh.sh +359 -0
  246. package/scripts/setup-heroku-keeper.sh +48 -0
  247. package/scripts/setup-keeper-database.js +83 -0
  248. package/scripts/setup-keeper-state-db.sql +110 -0
  249. package/scripts/setup-oracle.sh +39 -0
  250. package/scripts/setup-pnl-tracking.js +111 -0
  251. package/scripts/start-devnet.sh +14 -0
  252. package/scripts/test-arcade-devnet.sh +160 -0
  253. package/scripts/test-arcade-match.sh +109 -0
  254. package/scripts/test-automatic-mode.sh +239 -0
  255. package/scripts/test-connect4-cancel-claim.js +370 -0
  256. package/scripts/test-connect4-e2e.js +369 -0
  257. package/scripts/test-connect4-resolve.js +369 -0
  258. package/scripts/test-game-state-endpoint.js +136 -0
  259. package/scripts/test-invite-notification.js +86 -0
  260. package/scripts/test-jackpot-api.sh +71 -0
  261. package/scripts/test-poll-confirmation.js +267 -0
  262. package/scripts/test-resolve-game.js +271 -0
  263. package/scripts/test-resolve-signature.js +223 -0
  264. package/scripts/test-signature-preservation.js +124 -0
  265. package/scripts/test-state-machine.js +291 -0
  266. package/scripts/test-webhook-receiver.js +60 -0
  267. package/scripts/update-notification-constraint.js +52 -0
  268. package/scripts/verify-account-layout.js +145 -0
  269. package/scripts/verify-winner-algorithm.js +278 -0
  270. package/server.js +5259 -0
  271. package/services/arcadeMatchService.js +763 -0
  272. package/services/automaticGameOracle.js +1596 -0
  273. package/services/chatService.js +1612 -0
  274. package/services/connect4GameService.js +1049 -0
  275. package/services/connect4NotificationService.js +374 -0
  276. package/services/cryptoPriceService.js +223 -0
  277. package/services/customGameResolver.js +260 -0
  278. package/services/db.js +79 -0
  279. package/services/directMessageService.js +389 -0
  280. package/services/discordNotifications.js +160 -0
  281. package/services/exchangeRateService.js +289 -0
  282. package/services/expoPushService.js +314 -0
  283. package/services/gamesCacheService.js +539 -0
  284. package/services/jackpotHistory.js +331 -0
  285. package/services/jackpotService.js +856 -0
  286. package/services/keeperStateService.js +355 -0
  287. package/services/matchupImageService.js +591 -0
  288. package/services/notificationCacheService.js +407 -0
  289. package/services/pickemOracle.js +440 -0
  290. package/services/playerStatsService.js +389 -0
  291. package/services/portfolioService.js +555 -0
  292. package/services/promoService.js +757 -0
  293. package/services/promoTreasuryService.js +239 -0
  294. package/services/pushNotifications.js +353 -0
  295. package/services/redisService.js +422 -0
  296. package/services/referralEarningsService.js +728 -0
  297. package/services/s3Service.js +396 -0
  298. package/services/socialService.js +1202 -0
  299. package/services/survivorOracle.js +469 -0
  300. package/services/survivorSimulator.js +475 -0
  301. package/services/telegramNotifications.js +461 -0
  302. package/services/userProfileStatsService.js +1185 -0
  303. package/services/whatsNewService.js +388 -0
  304. package/utils/urlHelper.js +95 -0
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Connection, PublicKey } = require('@solana/web3.js');
4
+
5
+ const RPC_URL = 'https://api.devnet.solana.com';
6
+ const PROGRAM_ID = new PublicKey('BHidyz25KWkNPdTHgeANzMg25MM2KEiNnG4yE5F46XUz');
7
+
8
+ async function dumpAccount() {
9
+ const connection = new Connection(RPC_URL, 'confirmed');
10
+
11
+ const [roundPda] = PublicKey.findProgramAddressSync(
12
+ [Buffer.from('round'), Buffer.from([1,0,0,0,0,0,0,0])],
13
+ PROGRAM_ID
14
+ );
15
+
16
+ console.log('Round PDA:', roundPda.toString());
17
+
18
+ const account = await connection.getAccountInfo(roundPda);
19
+ if (!account) {
20
+ console.log('Account not found!');
21
+ return;
22
+ }
23
+
24
+ console.log('Account data length:', account.data.length);
25
+ console.log();
26
+
27
+ // Dump relevant sections
28
+ console.log('Bytes 0-16 (discriminator + round_id + status):');
29
+ console.log(account.data.slice(0, 17).toString('hex'));
30
+ console.log();
31
+
32
+ console.log('Bytes 49-54 (winner_index Option<u32>):');
33
+ console.log(account.data.slice(49, 54).toString('hex'));
34
+ console.log();
35
+
36
+ console.log('Bytes 54-87 (winner Option<Pubkey>):');
37
+ console.log(account.data.slice(54, 87).toString('hex'));
38
+ console.log();
39
+
40
+ console.log('Bytes 87-104 (vrf_result Option<u128>):');
41
+ console.log(account.data.slice(87, 104).toString('hex'));
42
+ console.log(' - Byte 87 (Option discriminant):', account.data[87]);
43
+ console.log(' - Bytes 88-104 (u128 if Some):', account.data.slice(88, 104).toString('hex'));
44
+ console.log();
45
+
46
+ console.log('Bytes 68-72 (entry_count u32):');
47
+ console.log(account.data.slice(68, 72).toString('hex'));
48
+ const entryCount = account.data.readUInt32LE(68);
49
+ console.log(' - Entry count:', entryCount);
50
+ console.log();
51
+
52
+ console.log('Bytes 108-140 (server_seed_hash [u8; 32]):');
53
+ console.log(account.data.slice(108, 140).toString('hex'));
54
+ console.log();
55
+
56
+ console.log('Bytes 140-173 (oracle_seed Option<[u8; 32]>):');
57
+ console.log(account.data.slice(140, 173).toString('hex'));
58
+ console.log(' - Byte 140 (Option discriminant):', account.data[140]);
59
+ if (account.data[140] === 1) {
60
+ console.log(' - Oracle seed:', account.data.slice(141, 173).toString('hex'));
61
+ }
62
+ }
63
+
64
+ dumpAccount().catch(console.error);
65
+
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Connection, PublicKey } = require('@solana/web3.js');
4
+
5
+ const RPC_URL = 'https://api.devnet.solana.com';
6
+ const PROGRAM_ID = new PublicKey('BHidyz25KWkNPdTHgeANzMg25MM2KEiNnG4yE5F46XUz');
7
+
8
+ async function findVrfOffset() {
9
+ const connection = new Connection(RPC_URL, 'confirmed');
10
+
11
+ const [roundPda] = PublicKey.findProgramAddressSync(
12
+ [Buffer.from('round'), Buffer.from([1,0,0,0,0,0,0,0])],
13
+ PROGRAM_ID
14
+ );
15
+
16
+ const account = await connection.getAccountInfo(roundPda);
17
+ if (!account) {
18
+ console.log('Account not found!');
19
+ return;
20
+ }
21
+
22
+ console.log('Account length:', account.data.length);
23
+ console.log('Full hex dump:');
24
+ console.log(account.data.toString('hex'));
25
+ console.log();
26
+
27
+ console.log('Searching for Option<u128> (discriminant = 1)...');
28
+ console.log();
29
+
30
+ for (let i = 0; i < account.data.length - 17; i++) {
31
+ if (account.data[i] === 1) {
32
+ const valueBytes = account.data.slice(i + 1, i + 17);
33
+ const value = BigInt('0x' + Buffer.from(valueBytes).reverse().toString('hex'));
34
+ console.log(`Offset ${i}: discriminant=1, value=${value.toString()}`);
35
+ console.log(` Hex: ${account.data.slice(i, i + 17).toString('hex')}`);
36
+ console.log();
37
+ }
38
+ }
39
+
40
+ console.log('Known field offsets:');
41
+ console.log(' round_id (offset 8):', account.data.readBigUInt64LE(8).toString());
42
+ console.log(' status (offset 16):', account.data[16], ['Open', 'Locked', 'Resolved'][account.data[16]]);
43
+ console.log(' total_pot (offset 33):', account.data.readBigUInt64LE(33).toString());
44
+ console.log(' total_weight (offset 41):', account.data.readBigUInt64LE(41).toString());
45
+ }
46
+
47
+ findVrfOffset().catch(console.error);
48
+
@@ -0,0 +1,122 @@
1
+ -- ============================================
2
+ -- 🔧 FIX CHAT_NOTIFICATIONS CHECK CONSTRAINT
3
+ -- ============================================
4
+ -- This script updates the notification_type CHECK constraint
5
+ -- to include all notification types used by the application.
6
+ --
7
+ -- Run with: heroku pg:psql --app YOUR_APP_NAME < scripts/fix-chat-notifications-constraint.sql
8
+ -- Or locally: psql -d dubs_db -f scripts/fix-chat-notifications-constraint.sql
9
+
10
+ -- Step 1: Show current constraint (for debugging)
11
+ \echo 'Current constraints on chat_notifications:'
12
+ SELECT conname, pg_get_constraintdef(oid)
13
+ FROM pg_constraint
14
+ WHERE conrelid = 'chat_notifications'::regclass;
15
+
16
+ -- Step 2: Drop the old CHECK constraint
17
+ DO $$
18
+ BEGIN
19
+ -- Find and drop any CHECK constraint on notification_type
20
+ PERFORM 1 FROM pg_constraint
21
+ WHERE conrelid = 'chat_notifications'::regclass
22
+ AND contype = 'c';
23
+
24
+ IF FOUND THEN
25
+ -- Drop all check constraints (there should only be one on notification_type)
26
+ EXECUTE (
27
+ SELECT string_agg('ALTER TABLE chat_notifications DROP CONSTRAINT ' || conname, '; ')
28
+ FROM pg_constraint
29
+ WHERE conrelid = 'chat_notifications'::regclass
30
+ AND contype = 'c'
31
+ );
32
+ RAISE NOTICE 'Dropped existing CHECK constraint(s)';
33
+ ELSE
34
+ RAISE NOTICE 'No CHECK constraints found to drop';
35
+ END IF;
36
+ END $$;
37
+
38
+ -- Step 3: Add the updated CHECK constraint with ALL notification types
39
+ ALTER TABLE chat_notifications
40
+ ADD CONSTRAINT chat_notifications_notification_type_check
41
+ CHECK (notification_type IN (
42
+ 'reply',
43
+ 'mention',
44
+ 'friend_message',
45
+ 'reaction',
46
+ 'friend_request',
47
+ 'friend_request_accepted',
48
+ 'friend_request_declined',
49
+ 'referral',
50
+ 'game_joined',
51
+ 'game_invite',
52
+ 'game_starting_soon',
53
+ 'game_starting_now',
54
+ 'game_won',
55
+ 'game_lost',
56
+ 'payment_received',
57
+ 'payment_sent',
58
+ 'dm'
59
+ ));
60
+
61
+ \echo 'Updated CHECK constraint. New constraints:'
62
+ SELECT conname, pg_get_constraintdef(oid)
63
+ FROM pg_constraint
64
+ WHERE conrelid = 'chat_notifications'::regclass;
65
+
66
+ -- Step 4: Ensure notification_data column exists
67
+ DO $$
68
+ BEGIN
69
+ IF NOT EXISTS (
70
+ SELECT 1 FROM information_schema.columns
71
+ WHERE table_name = 'chat_notifications' AND column_name = 'notification_data'
72
+ ) THEN
73
+ ALTER TABLE chat_notifications ADD COLUMN notification_data JSONB;
74
+ RAISE NOTICE 'Added notification_data column';
75
+ ELSE
76
+ RAISE NOTICE 'notification_data column already exists';
77
+ END IF;
78
+ END $$;
79
+
80
+ -- Step 5: Ensure user_relationships table exists
81
+ CREATE TABLE IF NOT EXISTS user_relationships (
82
+ id SERIAL PRIMARY KEY,
83
+ user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
84
+ target_user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
85
+ relationship_type VARCHAR(20) NOT NULL CHECK (relationship_type IN ('friend', 'block')),
86
+ created_at TIMESTAMP DEFAULT NOW(),
87
+ UNIQUE(user_id, target_user_id)
88
+ );
89
+
90
+ CREATE INDEX IF NOT EXISTS idx_relationships_user ON user_relationships(user_id);
91
+ CREATE INDEX IF NOT EXISTS idx_relationships_type ON user_relationships(relationship_type);
92
+
93
+ -- Step 6: Ensure friend_requests table exists with proper constraints
94
+ CREATE TABLE IF NOT EXISTS friend_requests (
95
+ id SERIAL PRIMARY KEY,
96
+ from_user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
97
+ to_user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
98
+ status VARCHAR(20) NOT NULL CHECK (status IN ('pending', 'accepted', 'rejected')) DEFAULT 'pending',
99
+ created_at TIMESTAMP DEFAULT NOW(),
100
+ updated_at TIMESTAMP DEFAULT NOW()
101
+ );
102
+
103
+ -- Add unique constraint for friend_requests if it doesn't exist
104
+ DO $$
105
+ BEGIN
106
+ IF NOT EXISTS (
107
+ SELECT 1 FROM pg_constraint
108
+ WHERE conname = 'friend_requests_from_user_id_to_user_id_key'
109
+ ) THEN
110
+ ALTER TABLE friend_requests
111
+ ADD CONSTRAINT friend_requests_from_user_id_to_user_id_key
112
+ UNIQUE (from_user_id, to_user_id);
113
+ END IF;
114
+ END $$;
115
+
116
+ CREATE INDEX IF NOT EXISTS idx_friend_requests_from ON friend_requests(from_user_id);
117
+ CREATE INDEX IF NOT EXISTS idx_friend_requests_to ON friend_requests(to_user_id);
118
+ CREATE INDEX IF NOT EXISTS idx_friend_requests_status ON friend_requests(status);
119
+
120
+ \echo '✅ Migration complete! Friend request functionality should now work.';
121
+
122
+
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Migration: Add claim columns to user_game_refs table
3
+ * Run this to fix the claim functionality
4
+ */
5
+
6
+ const { Pool } = require('pg');
7
+
8
+ const pool = new Pool({
9
+ connectionString: process.env.DATABASE_URL,
10
+ ssl: process.env.DATABASE_URL && (process.env.DATABASE_URL.includes('amazonaws') || process.env.DATABASE_URL.includes('heroku'))
11
+ ? { rejectUnauthorized: false }
12
+ : false
13
+ });
14
+
15
+ async function runMigration() {
16
+ console.log('🔧 Starting migration: Adding claim columns to user_game_refs...');
17
+
18
+ try {
19
+ // Add columns if they don't exist
20
+ await pool.query(`
21
+ DO $$
22
+ BEGIN
23
+ -- Add claimed_at column
24
+ IF NOT EXISTS (
25
+ SELECT 1 FROM information_schema.columns
26
+ WHERE table_name = 'user_game_refs' AND column_name = 'claimed_at'
27
+ ) THEN
28
+ ALTER TABLE user_game_refs ADD COLUMN claimed_at TIMESTAMP;
29
+ RAISE NOTICE 'Added claimed_at column';
30
+ ELSE
31
+ RAISE NOTICE 'claimed_at column already exists';
32
+ END IF;
33
+
34
+ -- Add claim_signature column
35
+ IF NOT EXISTS (
36
+ SELECT 1 FROM information_schema.columns
37
+ WHERE table_name = 'user_game_refs' AND column_name = 'claim_signature'
38
+ ) THEN
39
+ ALTER TABLE user_game_refs ADD COLUMN claim_signature TEXT;
40
+ RAISE NOTICE 'Added claim_signature column';
41
+ ELSE
42
+ RAISE NOTICE 'claim_signature column already exists';
43
+ END IF;
44
+
45
+ -- Add claim_explorer_url column
46
+ IF NOT EXISTS (
47
+ SELECT 1 FROM information_schema.columns
48
+ WHERE table_name = 'user_game_refs' AND column_name = 'claim_explorer_url'
49
+ ) THEN
50
+ ALTER TABLE user_game_refs ADD COLUMN claim_explorer_url TEXT;
51
+ RAISE NOTICE 'Added claim_explorer_url column';
52
+ ELSE
53
+ RAISE NOTICE 'claim_explorer_url column already exists';
54
+ END IF;
55
+
56
+ -- Add amount_claimed column
57
+ IF NOT EXISTS (
58
+ SELECT 1 FROM information_schema.columns
59
+ WHERE table_name = 'user_game_refs' AND column_name = 'amount_claimed'
60
+ ) THEN
61
+ ALTER TABLE user_game_refs ADD COLUMN amount_claimed DECIMAL(20, 9);
62
+ RAISE NOTICE 'Added amount_claimed column';
63
+ ELSE
64
+ RAISE NOTICE 'amount_claimed column already exists';
65
+ END IF;
66
+
67
+ -- Add updated_at column
68
+ IF NOT EXISTS (
69
+ SELECT 1 FROM information_schema.columns
70
+ WHERE table_name = 'user_game_refs' AND column_name = 'updated_at'
71
+ ) THEN
72
+ ALTER TABLE user_game_refs ADD COLUMN updated_at TIMESTAMP DEFAULT NOW();
73
+ RAISE NOTICE 'Added updated_at column';
74
+ ELSE
75
+ RAISE NOTICE 'updated_at column already exists';
76
+ END IF;
77
+ END $$;
78
+ `);
79
+
80
+ console.log('✅ Migration completed successfully!');
81
+
82
+ // Verify the columns exist
83
+ const result = await pool.query(`
84
+ SELECT column_name, data_type
85
+ FROM information_schema.columns
86
+ WHERE table_name = 'user_game_refs'
87
+ AND column_name IN ('claimed_at', 'claim_signature', 'claim_explorer_url', 'amount_claimed', 'updated_at')
88
+ ORDER BY column_name
89
+ `);
90
+
91
+ console.log('\n📊 Verification - Columns in user_game_refs:');
92
+ result.rows.forEach(row => {
93
+ console.log(` ✓ ${row.column_name} (${row.data_type})`);
94
+ });
95
+
96
+ console.log('\n🎉 Migration complete! Claim functionality should now work.');
97
+
98
+ } catch (error) {
99
+ console.error('❌ Migration failed:', error);
100
+ throw error;
101
+ } finally {
102
+ await pool.end();
103
+ }
104
+ }
105
+
106
+ // Run the migration
107
+ runMigration()
108
+ .then(() => {
109
+ console.log('\n✅ Done!');
110
+ process.exit(0);
111
+ })
112
+ .catch((error) => {
113
+ console.error('\n❌ Migration failed:', error);
114
+ process.exit(1);
115
+ });
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Quick Fix: Update notification constraint
3
+ * Run with: node fix-constraint-now.js
4
+ */
5
+
6
+ require('dotenv').config(); // Load .env file
7
+ const { Pool } = require('pg');
8
+
9
+ async function fix() {
10
+ const pool = new Pool({
11
+ connectionString: process.env.DATABASE_URL,
12
+ ssl: process.env.DATABASE_URL && (process.env.DATABASE_URL.includes('amazonaws') || process.env.DATABASE_URL.includes('heroku'))
13
+ ? { rejectUnauthorized: false }
14
+ : false
15
+ });
16
+
17
+ try {
18
+ console.log('🔧 Fixing constraint...');
19
+
20
+ await pool.query(`ALTER TABLE chat_notifications DROP CONSTRAINT IF EXISTS chat_notifications_notification_type_check`);
21
+ console.log('✅ Dropped old constraint');
22
+
23
+ await pool.query(`ALTER TABLE chat_notifications ADD CONSTRAINT chat_notifications_notification_type_check CHECK (notification_type IN ('reply', 'mention', 'friend_message', 'reaction', 'friend_request', 'friend_request_accepted', 'friend_request_declined', 'referral', 'game_joined', 'game_invite'))`);
24
+ console.log('✅ Added new constraint with game_invite');
25
+
26
+ console.log('🎉 Done! Try inviting a friend now.');
27
+ } catch (error) {
28
+ console.error('❌ Error:', error.message);
29
+ } finally {
30
+ await pool.end();
31
+ }
32
+ }
33
+
34
+ fix();
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Fix Lock Timestamps - Update existing games with NULL lock_timestamp
4
+ * This script calculates lock_timestamp from sportsEvent.strTimestamp
5
+ */
6
+
7
+ require('dotenv').config();
8
+ const { Pool } = require('pg');
9
+
10
+ const pool = new Pool({
11
+ connectionString: process.env.DATABASE_URL,
12
+ ssl: process.env.DATABASE_URL && (process.env.DATABASE_URL.includes('amazonaws') || process.env.DATABASE_URL.includes('heroku'))
13
+ ? { rejectUnauthorized: false }
14
+ : false
15
+ });
16
+
17
+ async function fixLockTimestamps() {
18
+ try {
19
+ console.log('🔧 Fixing lock timestamps for automatic games...\n');
20
+
21
+ // Get all automatic games with NULL lock_timestamp
22
+ const result = await pool.query(`
23
+ SELECT game_id, sports_event
24
+ FROM games
25
+ WHERE game_mode = 4
26
+ AND lock_timestamp IS NULL
27
+ AND sports_event IS NOT NULL
28
+ `);
29
+
30
+ console.log(`Found ${result.rows.length} game(s) with NULL lock_timestamp\n`);
31
+
32
+ if (result.rows.length === 0) {
33
+ console.log('✅ No games need fixing!');
34
+ process.exit(0);
35
+ }
36
+
37
+ let fixed = 0;
38
+ let failed = 0;
39
+
40
+ for (const row of result.rows) {
41
+ try {
42
+ const sportsEvent = row.sports_event;
43
+
44
+ if (!sportsEvent.strTimestamp) {
45
+ console.log(`⚠️ Game ${row.game_id}: No strTimestamp in sports event - skipping`);
46
+ failed++;
47
+ continue;
48
+ }
49
+
50
+ // Convert ISO timestamp to Unix timestamp (seconds since epoch)
51
+ const lockDate = new Date(sportsEvent.strTimestamp + 'Z');
52
+ const lockTimestamp = Math.floor(lockDate.getTime() / 1000);
53
+
54
+ // Update the game
55
+ await pool.query(`
56
+ UPDATE games
57
+ SET lock_timestamp = $1, updated_at = NOW()
58
+ WHERE game_id = $2
59
+ `, [lockTimestamp, row.game_id]);
60
+
61
+ console.log(`✅ Game ${row.game_id}: Set lock_timestamp to ${lockTimestamp} (${sportsEvent.strTimestamp})`);
62
+ fixed++;
63
+
64
+ } catch (error) {
65
+ console.error(`❌ Game ${row.game_id}: Error - ${error.message}`);
66
+ failed++;
67
+ }
68
+ }
69
+
70
+ console.log(`\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
71
+ console.log(`✅ Fixed: ${fixed}`);
72
+ console.log(`❌ Failed: ${failed}`);
73
+ console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
74
+
75
+ process.exit(0);
76
+
77
+ } catch (error) {
78
+ console.error('❌ Error:', error.message);
79
+ process.exit(1);
80
+ } finally {
81
+ await pool.end();
82
+ }
83
+ }
84
+
85
+ fixLockTimestamps();
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
@@ -0,0 +1,126 @@
1
+ #!/bin/bash
2
+
3
+ # 🔧 Fix Locked Round - Complete Recovery Script
4
+ # This script will:
5
+ # 1. Check if server is running
6
+ # 2. Check if keeper bot is running
7
+ # 3. Diagnose the locked round
8
+ # 4. Provide step-by-step fix
9
+
10
+ echo "🔧 Dubs Jackpot - Locked Round Recovery"
11
+ echo "========================================"
12
+ echo ""
13
+
14
+ # Colors
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ NC='\033[0m' # No Color
19
+
20
+ # Check if server is running
21
+ echo "1️⃣ Checking API server status..."
22
+ if curl -s http://localhost:3001/jackpot/health > /dev/null 2>&1; then
23
+ echo -e "${GREEN}✅ API server is running${NC}"
24
+ else
25
+ echo -e "${RED}❌ API server is NOT running${NC}"
26
+ echo ""
27
+ echo "To fix:"
28
+ echo " cd /Users/adamdahan/Developer/iheartsolana/solana-programs/dubs-server"
29
+ echo " SOLANA_NETWORK=https://api.devnet.solana.com node server.js"
30
+ echo ""
31
+ exit 1
32
+ fi
33
+
34
+ # Check if keeper bot is running
35
+ echo ""
36
+ echo "2️⃣ Checking keeper bot status..."
37
+ if pgrep -f "jackpot-keeper.js" > /dev/null; then
38
+ echo -e "${GREEN}✅ Keeper bot is running${NC}"
39
+ echo " Process ID: $(pgrep -f 'jackpot-keeper.js')"
40
+ else
41
+ echo -e "${RED}❌ Keeper bot is NOT running${NC}"
42
+ echo ""
43
+ echo "This is likely why your round is stuck!"
44
+ echo ""
45
+ echo "To fix:"
46
+ echo " cd /Users/adamdahan/Developer/iheartsolana/solana-programs/dubs-server"
47
+ echo " node scripts/jackpot-keeper.js"
48
+ echo ""
49
+ echo "💡 The keeper bot will automatically:"
50
+ echo " • Reveal oracle randomness"
51
+ echo " • Resolve the locked round"
52
+ echo " • Pay the winner"
53
+ echo " • Start a new round"
54
+ echo ""
55
+ exit 1
56
+ fi
57
+
58
+ # Get current round status
59
+ echo ""
60
+ echo "3️⃣ Checking round status..."
61
+ ROUND_INFO=$(curl -s http://localhost:3001/jackpot/round/current)
62
+
63
+ if echo "$ROUND_INFO" | grep -q "error"; then
64
+ echo -e "${YELLOW}⚠️ No active round found${NC}"
65
+ echo ""
66
+ echo "To fix:"
67
+ echo " The keeper bot should automatically open a new round"
68
+ echo " Or manually run: node scripts/jackpot-keeper.js"
69
+ exit 0
70
+ fi
71
+
72
+ STATUS=$(echo "$ROUND_INFO" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
73
+ ROUND_ID=$(echo "$ROUND_INFO" | grep -o '"roundId":"[^"]*"' | cut -d'"' -f4)
74
+ POT=$(echo "$ROUND_INFO" | grep -o '"totalPotLamports":"[^"]*"' | cut -d'"' -f4)
75
+
76
+ echo " Round ID: $ROUND_ID"
77
+ echo " Status: $STATUS"
78
+ echo " Pot: $(echo "scale=4; $POT / 1000000000" | bc) SOL"
79
+ echo ""
80
+
81
+ if [ "$STATUS" = "Locked" ]; then
82
+ echo -e "${YELLOW}🔒 Round IS locked${NC}"
83
+ echo ""
84
+ echo "The keeper bot should automatically:"
85
+ echo " 1. Reveal oracle randomness (consume_randomness)"
86
+ echo " 2. Resolve the round (select winner, pay out)"
87
+ echo " 3. Reset for new round"
88
+ echo ""
89
+ echo "If the keeper bot is running, wait ~10 seconds."
90
+ echo "If not, start it with:"
91
+ echo " node scripts/jackpot-keeper.js"
92
+ elif [ "$STATUS" = "Open" ]; then
93
+ echo -e "${GREEN}✅ Round is Open (not locked)${NC}"
94
+ echo ""
95
+ echo "Everything looks good! Players can enter."
96
+ elif [ "$STATUS" = "Resolved" ]; then
97
+ echo -e "${GREEN}✅ Round is Resolved${NC}"
98
+ echo ""
99
+ echo "Keeper bot should reset it soon to start a new round."
100
+ else
101
+ echo -e "${YELLOW}⚠️ Unknown status: $STATUS${NC}"
102
+ fi
103
+
104
+ echo ""
105
+ echo "4️⃣ Summary"
106
+ echo "==========="
107
+ echo ""
108
+ echo "Your jackpot system architecture (from COMPREHENSIVE_DESIGN.md):"
109
+ echo ""
110
+ echo " Round Lifecycle:"
111
+ echo " 1. OPEN → Players enter → Timer expires"
112
+ echo " 2. LOCK → Keeper commits server seed hash"
113
+ echo " 3. REVEAL → Oracle reveals random seed"
114
+ echo " 4. RESOLVE → Winner selected & paid"
115
+ echo " 5. RESET → New round starts"
116
+ echo ""
117
+ echo "If stuck at step 2 (LOCKED), you need:"
118
+ echo " • API server running (port 3001)"
119
+ echo " • Keeper bot running (jackpot-keeper.js)"
120
+ echo " • Oracle wallet configured (wallets/jackpot_oracle.json)"
121
+ echo ""
122
+ echo "✅ Quick Fix: Just run the keeper bot!"
123
+ echo " cd /Users/adamdahan/Developer/iheartsolana/solana-programs/dubs-server"
124
+ echo " node scripts/jackpot-keeper.js"
125
+ echo ""
126
+