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,88 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * šŸ”§ Direct resolve using the fixed JackpotService (bypasses API server)
5
+ */
6
+
7
+ const { Connection, Keypair, Transaction } = require('@solana/web3.js');
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const JackpotService = require('../services/jackpotService');
11
+
12
+ const RPC_URL = 'https://api.devnet.solana.com';
13
+
14
+ async function resolveRound() {
15
+ console.log('šŸ”§ Direct Round Resolution (using fixed code)\n');
16
+
17
+ // Load keeper wallet
18
+ const mainWalletPath = path.join(require('os').homedir(), '.config/solana/id.json');
19
+ const secretKey = JSON.parse(fs.readFileSync(mainWalletPath, 'utf-8'));
20
+ const wallet = Keypair.fromSecretKey(Uint8Array.from(secretKey));
21
+
22
+ console.log('Keeper wallet:', wallet.publicKey.toString());
23
+ console.log();
24
+
25
+ // Initialize service
26
+ const jackpotService = new JackpotService({
27
+ rpcUrl: RPC_URL,
28
+ programId: 'BHidyz25KWkNPdTHgeANzMg25MM2KEiNnG4yE5F46XUz',
29
+ });
30
+
31
+ // Get round info
32
+ const round = await jackpotService.getCurrentRound();
33
+ console.log(`Round ${round.roundId} - Status: ${round.status}`);
34
+ console.log(`Pot: ${Number(round.totalPotLamports) / 1e9} SOL`);
35
+ console.log();
36
+
37
+ if (round.status !== 'Locked') {
38
+ console.log(`āš ļø Round is not locked (status: ${round.status})`);
39
+ return;
40
+ }
41
+
42
+ try {
43
+ // Build resolve transaction using FIXED code
44
+ console.log('šŸ“ Building resolve transaction with FIXED winner calculation...');
45
+ const result = await jackpotService.buildResolveRoundTransaction({
46
+ keeperAddress: wallet.publicKey.toString(),
47
+ roundId: round.roundId,
48
+ });
49
+
50
+ console.log(`āœ… Winner: ${result.winner}`);
51
+ console.log();
52
+
53
+ // Sign and send
54
+ console.log('āœļø Signing and sending transaction...');
55
+ const connection = new Connection(RPC_URL, 'confirmed');
56
+ const tx = Transaction.from(Buffer.from(result.transaction, 'base64'));
57
+ tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
58
+ tx.feePayer = wallet.publicKey;
59
+ tx.sign(wallet);
60
+
61
+ const signature = await connection.sendRawTransaction(tx.serialize(), {
62
+ skipPreflight: false,
63
+ });
64
+
65
+ console.log(`šŸ“” Transaction sent: ${signature}`);
66
+ console.log('ā³ Confirming...');
67
+
68
+ await connection.confirmTransaction(signature);
69
+
70
+ console.log();
71
+ console.log('šŸŽ‰šŸŽ‰šŸŽ‰ SUCCESS! Round resolved!');
72
+ console.log(` Winner: ${result.winner}`);
73
+ console.log(` Prize: ${(Number(round.totalPotLamports) * 0.95 / 1e9).toFixed(4)} SOL`);
74
+ console.log(` Transaction: https://explorer.solana.com/tx/${signature}?cluster=devnet`);
75
+ console.log();
76
+ console.log('āœ… YOUR ROUND IS NOW UNLOCKED!');
77
+ console.log(' The keeper bot will reset it and start Round 51.');
78
+
79
+ } catch (error) {
80
+ console.error('āŒ Error:', error.message);
81
+ if (error.logs) {
82
+ console.error('Logs:', error.logs);
83
+ }
84
+ }
85
+ }
86
+
87
+ resolveRound().catch(console.error);
88
+
@@ -0,0 +1,124 @@
1
+ // Manually resolve a mock game for testing
2
+ const { Connection, Keypair, PublicKey, Transaction, TransactionInstruction } = require('@solana/web3.js');
3
+ const fs = require('fs');
4
+ const crypto = require('crypto');
5
+
6
+ const PROGRAM_ID = new PublicKey('8DJTkgk6MDr6tPtw4v2VzYAz9WWvmCg6786vZrEK3o5q');
7
+ const OPERATOR_WALLET = new PublicKey('BVZXwZpfgyzTBdRFHohkHZppPHnAyqyctRsKy3vWfQib');
8
+ const RPC_URL = 'https://api.devnet.solana.com';
9
+
10
+ // Load oracle keypair
11
+ const oracleKeypairData = JSON.parse(fs.readFileSync('./wallets/oracle.json', 'utf-8'));
12
+ const oracleKeypair = Keypair.fromSecretKey(Uint8Array.from(oracleKeypairData));
13
+
14
+ console.log('šŸ¤– Manual Game Resolution Script');
15
+ console.log('=================================\n');
16
+ console.log('Oracle wallet:', oracleKeypair.publicKey.toString());
17
+ console.log('Operator wallet:', OPERATOR_WALLET.toString());
18
+ console.log('');
19
+
20
+ const gameId = process.argv[2]; // Get from command line
21
+ const winner = process.argv[3]; // 'home', 'away', or 'tie'
22
+
23
+ if (!gameId || !winner) {
24
+ console.log('Usage: node resolve-mock-game.js <gameId> <winner>');
25
+ console.log('');
26
+ console.log('Example:');
27
+ console.log(' node resolve-mock-game.js sport-1761927514471-308lnavgp home');
28
+ console.log(' node resolve-mock-game.js sport-1761927514471-308lnavgp away');
29
+ console.log(' node resolve-mock-game.js sport-1761927514471-308lnavgp tie');
30
+ console.log('');
31
+ process.exit(1);
32
+ }
33
+
34
+ async function resolveGame() {
35
+ const connection = new Connection(RPC_URL, 'confirmed');
36
+
37
+ console.log(`Resolving game: ${gameId}`);
38
+ console.log(`Winner: ${winner}\n`);
39
+
40
+ // Get game PDA
41
+ const hash = crypto.createHash('sha256').update(gameId).digest();
42
+ const gameIdNum = hash.readBigUInt64LE(0);
43
+ const gameIdBuf = Buffer.alloc(8);
44
+ gameIdBuf.writeBigUInt64LE(gameIdNum);
45
+
46
+ const [gamePDA] = PublicKey.findProgramAddressSync(
47
+ [Buffer.from("game"), gameIdBuf],
48
+ PROGRAM_ID
49
+ );
50
+
51
+ console.log('Game PDA:', gamePDA.toString());
52
+
53
+ // Encode winning team
54
+ let winningTeamBytes;
55
+ if (winner === 'tie') {
56
+ winningTeamBytes = Buffer.from([0]); // None
57
+ console.log('Encoding: None (tie - refund all)');
58
+ } else if (winner === 'home') {
59
+ winningTeamBytes = Buffer.from([1, 0]); // Some(Home)
60
+ console.log('Encoding: Some(Home)');
61
+ } else if (winner === 'away') {
62
+ winningTeamBytes = Buffer.from([1, 1]); // Some(Away)
63
+ console.log('Encoding: Some(Away)');
64
+ } else {
65
+ console.log('āŒ Invalid winner! Use: home, away, or tie');
66
+ process.exit(1);
67
+ }
68
+
69
+ // Build resolve transaction
70
+ const RESOLVE_AUTO = Buffer.from([245, 33, 115, 150, 82, 150, 28, 193]);
71
+
72
+ const data = Buffer.concat([
73
+ RESOLVE_AUTO,
74
+ gameIdBuf,
75
+ winningTeamBytes
76
+ ]);
77
+
78
+ const ix = new TransactionInstruction({
79
+ keys: [
80
+ { pubkey: gamePDA, isSigner: false, isWritable: true },
81
+ { pubkey: oracleKeypair.publicKey, isSigner: true, isWritable: false },
82
+ // šŸ” Operator wallet receives fee
83
+ { pubkey: OPERATOR_WALLET, isSigner: false, isWritable: true },
84
+ ],
85
+ programId: PROGRAM_ID,
86
+ data,
87
+ });
88
+
89
+ console.log('\nšŸ“¤ Submitting resolution transaction...');
90
+
91
+ const tx = new Transaction().add(ix);
92
+ tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
93
+ tx.feePayer = oracleKeypair.publicKey;
94
+
95
+ tx.sign(oracleKeypair);
96
+
97
+ try {
98
+ const signature = await connection.sendRawTransaction(tx.serialize());
99
+ console.log('āœ… Transaction sent:', signature);
100
+
101
+ console.log('\nā³ Waiting for confirmation...');
102
+ await connection.confirmTransaction(signature);
103
+
104
+ console.log('āœ… Transaction confirmed!');
105
+ console.log('\nšŸŽ‰ Game resolved successfully!');
106
+ console.log(`\nView on explorer:`);
107
+ console.log(`https://explorer.solana.com/tx/${signature}?cluster=devnet`);
108
+ console.log('');
109
+ console.log('šŸ’° Check operator wallet balance:');
110
+ console.log(`solana balance ${OPERATOR_WALLET.toString()} --url devnet`);
111
+ console.log('');
112
+ console.log('Players can now use /claim to get their prizes!');
113
+
114
+ } catch (error) {
115
+ console.log('āŒ Error resolving game:', error.message);
116
+ if (error.logs) {
117
+ console.log('\nProgram logs:');
118
+ error.logs.forEach(log => console.log(' ', log));
119
+ }
120
+ }
121
+ }
122
+
123
+ resolveGame().catch(console.error);
124
+
@@ -0,0 +1,55 @@
1
+ /**
2
+ * One-off script to resolve a pickem game via the Dubs SDK.
3
+ * Usage: node scripts/resolve-pickem-game.js <gameId> <winnerTeam>
4
+ * Example: node scripts/resolve-pickem-game.js df2f0746-b3f8-46ad-9187-e5b7d9fbca8f home
5
+ */
6
+
7
+ require('dotenv').config();
8
+ const { Dubs } = require('@dubsdotapp/node');
9
+
10
+ const gameId = process.argv[2];
11
+ const winnerTeam = process.argv[3] || 'home';
12
+
13
+ if (!gameId) {
14
+ console.error('Usage: node scripts/resolve-pickem-game.js <gameId> <winnerTeam>');
15
+ process.exit(1);
16
+ }
17
+
18
+ const apiKey = process.env.DUBS_API_KEY;
19
+ const resolutionSecret = process.env.DUBS_RESOLUTION_SECRET;
20
+ const baseUrl = process.env.DUBS_SDK_BASE_URL;
21
+
22
+ if (!apiKey || !resolutionSecret) {
23
+ console.error('Missing DUBS_API_KEY or DUBS_RESOLUTION_SECRET');
24
+ process.exit(1);
25
+ }
26
+
27
+ async function main() {
28
+ const dubs = new Dubs({ apiKey, resolutionSecret, baseUrl });
29
+
30
+ console.log(`Fetching game ${gameId}...`);
31
+ const { game } = await dubs.games.get(gameId);
32
+ console.log(`Game: ${game.title}`);
33
+ console.log(`Status: ${game.status}, isResolved: ${game.isResolved}`);
34
+ console.log(`Bettors: ${game.bettors?.length ?? 0}`);
35
+ for (const b of game.bettors || []) {
36
+ console.log(` ${b.wallet} — team: ${b.team}, amount: ${b.amount}`);
37
+ }
38
+
39
+ if (game.isResolved) {
40
+ console.log('Game already resolved. Nothing to do.');
41
+ return;
42
+ }
43
+
44
+ console.log(`\nResolving with winner: '${winnerTeam}'...`);
45
+ const result = await dubs.resolveGame(gameId, {
46
+ winner: winnerTeam,
47
+ metadata: { source: 'manual_pickem_resolve' },
48
+ });
49
+ console.log('Resolved!', JSON.stringify(result, null, 2));
50
+ }
51
+
52
+ main().catch(err => {
53
+ console.error('Error:', err.message);
54
+ process.exit(1);
55
+ });
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Connection, Keypair, PublicKey, Transaction, TransactionInstruction } = require('@solana/web3.js');
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const PROGRAM_ID = new PublicKey('BHidyz25KWkNPdTHgeANzMg25MM2KEiNnG4yE5F46XUz');
9
+ const RPC_URL = 'https://api.devnet.solana.com';
10
+
11
+ async function main() {
12
+ const connection = new Connection(RPC_URL, 'confirmed');
13
+
14
+ // Load oracle wallet
15
+ const oracleKeyPath = path.join(__dirname, '..', 'wallets', 'jackpot_oracle.json');
16
+ const secretKey = JSON.parse(fs.readFileSync(oracleKeyPath, 'utf-8'));
17
+ const oracle = Keypair.fromSecretKey(Uint8Array.from(secretKey));
18
+
19
+ console.log('šŸŽ² Manual Round Resolution');
20
+ console.log('Oracle:', oracle.publicKey.toString());
21
+
22
+ // Get config
23
+ const [configPda] = PublicKey.findProgramAddressSync([Buffer.from('config')], PROGRAM_ID);
24
+ const configData = await connection.getAccountInfo(configPda);
25
+ const currentRoundId = configData.data.readBigUInt64LE(82);
26
+
27
+ console.log('Current Round ID:', currentRoundId.toString());
28
+
29
+ // Get round PDA
30
+ const roundIdBuf = Buffer.alloc(8);
31
+ roundIdBuf.writeBigUInt64LE(currentRoundId);
32
+ const [roundPda] = PublicKey.findProgramAddressSync([Buffer.from('round'), roundIdBuf], PROGRAM_ID);
33
+
34
+ console.log('Round PDA:', roundPda.toString());
35
+
36
+ // Check round status
37
+ const roundData = await connection.getAccountInfo(roundPda);
38
+ if (!roundData) {
39
+ console.log('āŒ Round account not found');
40
+ return;
41
+ }
42
+
43
+ const status = roundData.data[16]; // 0=Open, 1=Locked, 2=Resolved
44
+ console.log('Status:', ['Open', 'Locked', 'Resolved'][status]);
45
+
46
+ if (status !== 1) {
47
+ console.log('āŒ Round is not locked');
48
+ return;
49
+ }
50
+
51
+ // Submit oracle randomness
52
+ console.log('\nšŸŽ² Submitting oracle randomness...');
53
+ const oracleSeed = crypto.randomBytes(32);
54
+
55
+ const CONSUME_RANDOMNESS_DISC = Buffer.from([190, 217, 49, 162, 99, 26, 73, 234]);
56
+ const data = Buffer.concat([CONSUME_RANDOMNESS_DISC, oracleSeed]);
57
+
58
+ const keys = [
59
+ { pubkey: configPda, isSigner: false, isWritable: true },
60
+ { pubkey: roundPda, isSigner: false, isWritable: true },
61
+ { pubkey: oracle.publicKey, isSigner: true, isWritable: false },
62
+ ];
63
+
64
+ const instruction = new TransactionInstruction({ keys, programId: PROGRAM_ID, data });
65
+ const tx = new Transaction().add(instruction);
66
+ tx.feePayer = oracle.publicKey;
67
+ tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
68
+ tx.sign(oracle);
69
+
70
+ const sig = await connection.sendRawTransaction(tx.serialize(), { skipPreflight: true });
71
+ await connection.confirmTransaction(sig);
72
+
73
+ console.log('āœ… Randomness submitted! Sig:', sig.slice(0, 8) + '...');
74
+ console.log('\nšŸ’” Now run: node scripts/open-jackpot-round.js to resolve and open next round');
75
+ }
76
+
77
+ main().catch(console.error);
78
+
79
+
80
+
81
+
82
+
83
+