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,369 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* End-to-End Test: Connect4 Create -> Cancel -> Claim
|
|
4
|
+
*
|
|
5
|
+
* This test validates the full flow with the polling confirmation fix.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node test-connect4-e2e.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
require('dotenv').config();
|
|
12
|
+
const { Connection, Keypair, Transaction, PublicKey, LAMPORTS_PER_SOL } = require('@solana/web3.js');
|
|
13
|
+
const { pool } = require('../services/db');
|
|
14
|
+
const axios = require('axios');
|
|
15
|
+
const jwt = require('jsonwebtoken');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
// Configuration
|
|
20
|
+
const RPC_URL = process.env.SOLANA_RPC_URL || process.env.SOLANA_NETWORK || 'https://api.devnet.solana.com';
|
|
21
|
+
const SERVER_URL = process.env.TEST_SERVER_URL || 'http://localhost:3001';
|
|
22
|
+
const JWT_SECRET = process.env.JWT_SECRET || 'fallback-secret-change-in-production';
|
|
23
|
+
|
|
24
|
+
console.log('š§Ŗ Connect4 End-to-End Test');
|
|
25
|
+
console.log('===========================');
|
|
26
|
+
console.log(`RPC URL: ${RPC_URL}`);
|
|
27
|
+
console.log(`Server URL: ${SERVER_URL}`);
|
|
28
|
+
console.log('');
|
|
29
|
+
|
|
30
|
+
const connection = new Connection(RPC_URL, 'confirmed');
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Load or create test wallet
|
|
34
|
+
*/
|
|
35
|
+
function getTestWallet() {
|
|
36
|
+
const testWalletPath = path.join(__dirname, '../wallets/test-wallet.json');
|
|
37
|
+
|
|
38
|
+
// Try to load existing test wallet
|
|
39
|
+
if (fs.existsSync(testWalletPath)) {
|
|
40
|
+
console.log('š Loading existing test wallet...');
|
|
41
|
+
const secretKey = JSON.parse(fs.readFileSync(testWalletPath, 'utf-8'));
|
|
42
|
+
return Keypair.fromSecretKey(Uint8Array.from(secretKey));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Try oracle wallet for testing
|
|
46
|
+
if (process.env.ORACLE_WALLET_JSON) {
|
|
47
|
+
console.log('š Using oracle wallet for testing...');
|
|
48
|
+
const secretKey = JSON.parse(process.env.ORACLE_WALLET_JSON);
|
|
49
|
+
return Keypair.fromSecretKey(Uint8Array.from(secretKey));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Try operator wallet
|
|
53
|
+
if (process.env.OPERATOR_WALLET_JSON) {
|
|
54
|
+
console.log('š Using operator wallet for testing...');
|
|
55
|
+
const secretKey = JSON.parse(process.env.OPERATOR_WALLET_JSON);
|
|
56
|
+
return Keypair.fromSecretKey(Uint8Array.from(secretKey));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
throw new Error('No test wallet found. Create one at wallets/test-wallet.json');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Ensure user exists in database
|
|
64
|
+
*/
|
|
65
|
+
async function ensureUserExists(walletAddress) {
|
|
66
|
+
const existing = await pool.query(
|
|
67
|
+
'SELECT wallet_address FROM users WHERE wallet_address = $1',
|
|
68
|
+
[walletAddress]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (existing.rows.length === 0) {
|
|
72
|
+
console.log(` Creating user in database: ${walletAddress.slice(0, 16)}...`);
|
|
73
|
+
await pool.query(
|
|
74
|
+
'INSERT INTO users (wallet_address, username) VALUES ($1, $2)',
|
|
75
|
+
[walletAddress, `test-${walletAddress.slice(0, 8)}`]
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Generate JWT token for testing
|
|
82
|
+
*/
|
|
83
|
+
function generateTestToken(walletAddress) {
|
|
84
|
+
return jwt.sign(
|
|
85
|
+
{ walletAddress, type: 'auth' },
|
|
86
|
+
JWT_SECRET,
|
|
87
|
+
{ expiresIn: '1h' }
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check wallet balance
|
|
93
|
+
*/
|
|
94
|
+
async function checkBalance(walletAddress) {
|
|
95
|
+
const balance = await connection.getBalance(new PublicKey(walletAddress));
|
|
96
|
+
const solBalance = balance / LAMPORTS_PER_SOL;
|
|
97
|
+
console.log(` Balance: ${solBalance.toFixed(4)} SOL`);
|
|
98
|
+
return solBalance;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Step 1: Create Connect4 game
|
|
103
|
+
*/
|
|
104
|
+
async function createGame(wallet, authToken) {
|
|
105
|
+
console.log('\nš Step 1: Create Connect4 Game');
|
|
106
|
+
console.log('--------------------------------');
|
|
107
|
+
|
|
108
|
+
const walletAddress = wallet.publicKey.toString();
|
|
109
|
+
console.log(` Creator: ${walletAddress.slice(0, 16)}...`);
|
|
110
|
+
|
|
111
|
+
// Build the game transaction
|
|
112
|
+
const response = await axios.post(
|
|
113
|
+
`${SERVER_URL}/api/v1/prod/transaction/build/create-connect4-game`,
|
|
114
|
+
{
|
|
115
|
+
creatorAddress: walletAddress,
|
|
116
|
+
buyIn: 0.01, // Small amount for testing
|
|
117
|
+
},
|
|
118
|
+
{ headers: { 'Content-Type': 'application/json' } }
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (!response.data.success) {
|
|
122
|
+
throw new Error(`Failed to build game: ${response.data.error}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const { gameId, gameAddress, transaction: txBase64 } = response.data;
|
|
126
|
+
console.log(` Game ID: ${gameId}`);
|
|
127
|
+
console.log(` Game PDA: ${gameAddress}`);
|
|
128
|
+
|
|
129
|
+
// Deserialize and sign the transaction
|
|
130
|
+
const txBuffer = Buffer.from(txBase64, 'base64');
|
|
131
|
+
const tx = Transaction.from(txBuffer);
|
|
132
|
+
tx.sign(wallet);
|
|
133
|
+
|
|
134
|
+
// Send the signed transaction
|
|
135
|
+
console.log(` Sending transaction...`);
|
|
136
|
+
const signature = await connection.sendRawTransaction(tx.serialize(), {
|
|
137
|
+
skipPreflight: false,
|
|
138
|
+
preflightCommitment: 'confirmed',
|
|
139
|
+
});
|
|
140
|
+
console.log(` Signature: ${signature}`);
|
|
141
|
+
|
|
142
|
+
// Wait for confirmation using polling
|
|
143
|
+
console.log(` Waiting for confirmation (polling)...`);
|
|
144
|
+
await pollConfirmation(signature);
|
|
145
|
+
|
|
146
|
+
// Record the game in the database
|
|
147
|
+
await pool.query(`
|
|
148
|
+
INSERT INTO games (game_id, game_address, game_type, created_by, buy_in, game_status, max_players, game_mode)
|
|
149
|
+
VALUES ($1, $2, 'connect4', $3, $4, 'waiting', 2, 1)
|
|
150
|
+
ON CONFLICT (game_id) DO UPDATE SET game_status = 'waiting'
|
|
151
|
+
`, [gameId, gameAddress, walletAddress, 0.01]);
|
|
152
|
+
|
|
153
|
+
// Record user_game_ref
|
|
154
|
+
await pool.query(`
|
|
155
|
+
INSERT INTO user_game_refs (wallet_address, game_id, role, team_choice, my_signature)
|
|
156
|
+
VALUES ($1, $2, 'creator', 'home', $3)
|
|
157
|
+
ON CONFLICT (wallet_address, game_id) DO NOTHING
|
|
158
|
+
`, [walletAddress, gameId, signature]);
|
|
159
|
+
|
|
160
|
+
console.log(` ā
Game created successfully!`);
|
|
161
|
+
return { gameId, gameAddress, signature };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Step 2: Cancel the game
|
|
166
|
+
*/
|
|
167
|
+
async function cancelGame(gameId, authToken) {
|
|
168
|
+
console.log('\nš Step 2: Cancel Game');
|
|
169
|
+
console.log('-----------------------');
|
|
170
|
+
console.log(` Game ID: ${gameId}`);
|
|
171
|
+
|
|
172
|
+
const response = await axios.post(
|
|
173
|
+
`${SERVER_URL}/api/connect4/cancel`,
|
|
174
|
+
{ gameId },
|
|
175
|
+
{
|
|
176
|
+
headers: {
|
|
177
|
+
'Authorization': `Bearer ${authToken}`,
|
|
178
|
+
'Content-Type': 'application/json'
|
|
179
|
+
},
|
|
180
|
+
timeout: 60000
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
console.log(` Response: ${JSON.stringify(response.data)}`);
|
|
185
|
+
|
|
186
|
+
if (response.data.success) {
|
|
187
|
+
console.log(` ā
Game cancelled successfully!`);
|
|
188
|
+
if (response.data.signature) {
|
|
189
|
+
console.log(` Signature: ${response.data.signature}`);
|
|
190
|
+
}
|
|
191
|
+
return response.data;
|
|
192
|
+
} else {
|
|
193
|
+
throw new Error(`Cancel failed: ${response.data.error}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Step 3: Claim the refund
|
|
199
|
+
*/
|
|
200
|
+
async function claimRefund(gameId, authToken) {
|
|
201
|
+
console.log('\nš Step 3: Claim Refund');
|
|
202
|
+
console.log('------------------------');
|
|
203
|
+
console.log(` Game ID: ${gameId}`);
|
|
204
|
+
|
|
205
|
+
const response = await axios.post(
|
|
206
|
+
`${SERVER_URL}/api/connect4/claim`,
|
|
207
|
+
{ gameId },
|
|
208
|
+
{
|
|
209
|
+
headers: {
|
|
210
|
+
'Authorization': `Bearer ${authToken}`,
|
|
211
|
+
'Content-Type': 'application/json'
|
|
212
|
+
},
|
|
213
|
+
timeout: 60000
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
console.log(` Response status: ${response.status}`);
|
|
218
|
+
|
|
219
|
+
if (response.data.transaction) {
|
|
220
|
+
console.log(` ā
Claim transaction built successfully!`);
|
|
221
|
+
console.log(` Transaction ready for user to sign`);
|
|
222
|
+
return { success: true, transaction: response.data.transaction };
|
|
223
|
+
} else if (response.data.success) {
|
|
224
|
+
console.log(` ā
Claim processed!`);
|
|
225
|
+
return response.data;
|
|
226
|
+
} else {
|
|
227
|
+
console.log(` Response: ${JSON.stringify(response.data)}`);
|
|
228
|
+
throw new Error(`Claim failed: ${response.data.error || 'Unknown error'}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Poll for transaction confirmation (Alchemy-compatible)
|
|
234
|
+
*/
|
|
235
|
+
async function pollConfirmation(signature, timeout = 30000) {
|
|
236
|
+
const start = Date.now();
|
|
237
|
+
|
|
238
|
+
while (Date.now() - start < timeout) {
|
|
239
|
+
const response = await connection.getSignatureStatuses([signature], {
|
|
240
|
+
searchTransactionHistory: true
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
const status = response?.value?.[0];
|
|
244
|
+
if (status) {
|
|
245
|
+
if (status.err) {
|
|
246
|
+
throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
|
|
247
|
+
}
|
|
248
|
+
if (status.confirmationStatus === 'confirmed' || status.confirmationStatus === 'finalized') {
|
|
249
|
+
return status;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
throw new Error('Transaction confirmation timeout');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Verify final game state
|
|
261
|
+
*/
|
|
262
|
+
async function verifyFinalState(gameId) {
|
|
263
|
+
console.log('\nš Verifying Final State');
|
|
264
|
+
console.log('-------------------------');
|
|
265
|
+
|
|
266
|
+
const result = await pool.query(`
|
|
267
|
+
SELECT g.game_id, g.game_status, g.is_resolved, g.connect4_winner, g.claim_signature,
|
|
268
|
+
u.wallet_address, u.claimed_at, u.claim_signature as user_claim_sig
|
|
269
|
+
FROM games g
|
|
270
|
+
LEFT JOIN user_game_refs u ON g.game_id = u.game_id AND u.role = 'creator'
|
|
271
|
+
WHERE g.game_id = $1
|
|
272
|
+
`, [gameId]);
|
|
273
|
+
|
|
274
|
+
if (result.rows.length === 0) {
|
|
275
|
+
console.log(` ā Game not found`);
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const game = result.rows[0];
|
|
280
|
+
console.log(` game_status: ${game.game_status}`);
|
|
281
|
+
console.log(` is_resolved: ${game.is_resolved}`);
|
|
282
|
+
console.log(` connect4_winner: ${game.connect4_winner || 'null'}`);
|
|
283
|
+
console.log(` claim_signature: ${game.claim_signature || 'null'}`);
|
|
284
|
+
|
|
285
|
+
const passed = game.game_status === 'cancelled' && game.is_resolved === true;
|
|
286
|
+
if (passed) {
|
|
287
|
+
console.log(` ā
Game state is correct!`);
|
|
288
|
+
} else {
|
|
289
|
+
console.log(` ā Game state is incorrect`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return passed;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Main test execution
|
|
297
|
+
*/
|
|
298
|
+
async function main() {
|
|
299
|
+
let passed = 0;
|
|
300
|
+
let failed = 0;
|
|
301
|
+
let gameId = null;
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
// Setup
|
|
305
|
+
const wallet = getTestWallet();
|
|
306
|
+
const walletAddress = wallet.publicKey.toString();
|
|
307
|
+
console.log(`š Test wallet: ${walletAddress}`);
|
|
308
|
+
|
|
309
|
+
// Check balance
|
|
310
|
+
const balance = await checkBalance(walletAddress);
|
|
311
|
+
if (balance < 0.02) {
|
|
312
|
+
console.log(`\nā ļø Wallet balance too low for testing.`);
|
|
313
|
+
console.log(` Need at least 0.02 SOL, have ${balance.toFixed(4)} SOL`);
|
|
314
|
+
console.log(` Airdrop: solana airdrop 1 ${walletAddress} --url devnet`);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Ensure user exists
|
|
319
|
+
await ensureUserExists(walletAddress);
|
|
320
|
+
|
|
321
|
+
// Generate auth token
|
|
322
|
+
const authToken = generateTestToken(walletAddress);
|
|
323
|
+
console.log(`š Auth token generated`);
|
|
324
|
+
|
|
325
|
+
// Step 1: Create game
|
|
326
|
+
const createResult = await createGame(wallet, authToken);
|
|
327
|
+
gameId = createResult.gameId;
|
|
328
|
+
passed++;
|
|
329
|
+
|
|
330
|
+
// Step 2: Cancel game
|
|
331
|
+
await cancelGame(gameId, authToken);
|
|
332
|
+
passed++;
|
|
333
|
+
|
|
334
|
+
// Step 3: Claim refund
|
|
335
|
+
await claimRefund(gameId, authToken);
|
|
336
|
+
passed++;
|
|
337
|
+
|
|
338
|
+
// Verify final state
|
|
339
|
+
const stateOk = await verifyFinalState(gameId);
|
|
340
|
+
if (stateOk) passed++; else failed++;
|
|
341
|
+
|
|
342
|
+
} catch (error) {
|
|
343
|
+
console.error(`\nā Error: ${error.message}`);
|
|
344
|
+
if (error.response?.data) {
|
|
345
|
+
console.error(` Response: ${JSON.stringify(error.response.data)}`);
|
|
346
|
+
}
|
|
347
|
+
failed++;
|
|
348
|
+
} finally {
|
|
349
|
+
await pool.end();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Summary
|
|
353
|
+
console.log('\n===========================');
|
|
354
|
+
console.log('š Test Summary');
|
|
355
|
+
console.log('===========================');
|
|
356
|
+
console.log(` Passed: ${passed}`);
|
|
357
|
+
console.log(` Failed: ${failed}`);
|
|
358
|
+
console.log('');
|
|
359
|
+
|
|
360
|
+
if (failed === 0) {
|
|
361
|
+
console.log('ā
All tests passed! The polling confirmation fix works.');
|
|
362
|
+
} else {
|
|
363
|
+
console.log('ā Some tests failed. Check the output above.');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
main();
|