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,720 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* š® Dubs CLI - Interactive Testing Tool
|
|
5
|
+
*
|
|
6
|
+
* Test the complete Dubs voting system with a beautiful interactive menu!
|
|
7
|
+
* No Postman, no manual curls - just select and test!
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
const https = require('https');
|
|
12
|
+
const http = require('http');
|
|
13
|
+
|
|
14
|
+
// Simple fetch wrapper for Node.js
|
|
15
|
+
async function fetch(url, options = {}) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
const urlObj = new URL(url);
|
|
18
|
+
const client = urlObj.protocol === 'https:' ? https : http;
|
|
19
|
+
|
|
20
|
+
const req = client.request(url, {
|
|
21
|
+
method: options.method || 'GET',
|
|
22
|
+
headers: options.headers || {},
|
|
23
|
+
}, (res) => {
|
|
24
|
+
let data = '';
|
|
25
|
+
res.on('data', chunk => data += chunk);
|
|
26
|
+
res.on('end', () => {
|
|
27
|
+
resolve({
|
|
28
|
+
ok: res.statusCode >= 200 && res.statusCode < 300,
|
|
29
|
+
json: async () => JSON.parse(data),
|
|
30
|
+
text: async () => data,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
req.on('error', reject);
|
|
36
|
+
|
|
37
|
+
if (options.body) {
|
|
38
|
+
req.write(options.body);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
req.end();
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Configuration
|
|
46
|
+
const BASE_URL = process.env.DUBS_URL || 'http://localhost:3001';
|
|
47
|
+
let currentGameId = null;
|
|
48
|
+
let playerAddresses = {};
|
|
49
|
+
|
|
50
|
+
// Colors for terminal
|
|
51
|
+
const colors = {
|
|
52
|
+
reset: '\x1b[0m',
|
|
53
|
+
bright: '\x1b[1m',
|
|
54
|
+
red: '\x1b[31m',
|
|
55
|
+
green: '\x1b[32m',
|
|
56
|
+
yellow: '\x1b[33m',
|
|
57
|
+
blue: '\x1b[34m',
|
|
58
|
+
magenta: '\x1b[35m',
|
|
59
|
+
cyan: '\x1b[36m',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const rl = readline.createInterface({
|
|
63
|
+
input: process.stdin,
|
|
64
|
+
output: process.stdout
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Helper to ask questions
|
|
68
|
+
function ask(question) {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
rl.question(question, resolve);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Pretty print JSON
|
|
75
|
+
function printJson(data) {
|
|
76
|
+
console.log(colors.cyan + JSON.stringify(data, null, 2) + colors.reset);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Success message
|
|
80
|
+
function success(msg) {
|
|
81
|
+
console.log(colors.green + 'ā
' + msg + colors.reset);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Error message
|
|
85
|
+
function error(msg) {
|
|
86
|
+
console.log(colors.red + 'ā ' + msg + colors.reset);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Info message
|
|
90
|
+
function info(msg) {
|
|
91
|
+
console.log(colors.blue + 'ā¹ļø ' + msg + colors.reset);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Main menu
|
|
95
|
+
async function showMenu() {
|
|
96
|
+
console.clear();
|
|
97
|
+
console.log(colors.bright + colors.magenta);
|
|
98
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
99
|
+
console.log('ā š® DUBS CLI - VOTING TESTER š® ā');
|
|
100
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
101
|
+
console.log(colors.reset);
|
|
102
|
+
console.log(colors.cyan + `š” Server: ${BASE_URL}` + colors.reset);
|
|
103
|
+
if (currentGameId) {
|
|
104
|
+
console.log(colors.yellow + `š® Current Game: ${currentGameId}` + colors.reset);
|
|
105
|
+
}
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log(colors.bright + 'āāā GAME MANAGEMENT āāā' + colors.reset);
|
|
108
|
+
console.log('1. š List Demo Wallets');
|
|
109
|
+
console.log('2. šø Airdrop SOL to Player');
|
|
110
|
+
console.log('3. š® Create New Game');
|
|
111
|
+
console.log('4. š Get Game Info');
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log(colors.bright + 'āāā GAME PLAY āāā' + colors.reset);
|
|
114
|
+
console.log('5. š„ Player Joins Game');
|
|
115
|
+
console.log('6. š³ļø Cast Vote (NEW!)');
|
|
116
|
+
console.log('7. š Distribute by Vote (NEW!)');
|
|
117
|
+
console.log('8. š° Distribute Manually');
|
|
118
|
+
console.log('');
|
|
119
|
+
console.log(colors.bright + 'āāā QUICK TESTS āāā' + colors.reset);
|
|
120
|
+
console.log('9. š Full Voting Test (Auto)');
|
|
121
|
+
console.log('10. š² 3-Way Tie Test');
|
|
122
|
+
console.log('');
|
|
123
|
+
console.log('0. ā Exit');
|
|
124
|
+
console.log('');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 1. List wallets
|
|
128
|
+
async function listWallets() {
|
|
129
|
+
try {
|
|
130
|
+
info('Fetching demo wallets...');
|
|
131
|
+
const response = await fetch(`${BASE_URL}/api/v1/demo/wallets`);
|
|
132
|
+
const data = await response.json();
|
|
133
|
+
|
|
134
|
+
console.log('');
|
|
135
|
+
console.log(colors.bright + 'š„ Demo Wallets:' + colors.reset);
|
|
136
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
137
|
+
data.wallets.forEach(wallet => {
|
|
138
|
+
console.log(`${colors.yellow}${wallet.name.padEnd(12)}${colors.reset} ${wallet.address} ${colors.green}(${wallet.balance} SOL)${colors.reset}`);
|
|
139
|
+
playerAddresses[wallet.name] = wallet.address;
|
|
140
|
+
});
|
|
141
|
+
console.log('');
|
|
142
|
+
} catch (err) {
|
|
143
|
+
error('Failed to fetch wallets: ' + err.message);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 2. Airdrop
|
|
148
|
+
async function airdrop() {
|
|
149
|
+
const player = await ask('Enter player name (alice/bob/charlie): ');
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
info(`Airdropping 2 SOL to ${player}...`);
|
|
153
|
+
const response = await fetch(`${BASE_URL}/api/v1/demo/airdrop`, {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: { 'Content-Type': 'application/json' },
|
|
156
|
+
body: JSON.stringify({ player })
|
|
157
|
+
});
|
|
158
|
+
const data = await response.json();
|
|
159
|
+
|
|
160
|
+
if (data.success) {
|
|
161
|
+
success(data.message);
|
|
162
|
+
console.log(` Balance: ${data.balance} SOL`);
|
|
163
|
+
} else {
|
|
164
|
+
error(data.error || 'Airdrop failed');
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
167
|
+
error('Failed: ' + err.message);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 3. Create game
|
|
172
|
+
async function createGame() {
|
|
173
|
+
console.log('');
|
|
174
|
+
const player = await ask('Creator name (default: creator): ') || 'creator';
|
|
175
|
+
const buyIn = await ask('Buy-in amount (default: 0.5 SOL): ') || '0.5';
|
|
176
|
+
const maxPlayers = await ask('Max players (default: 3): ') || '3';
|
|
177
|
+
const operatorFee = await ask('Operator fee % (default: 10): ') || '10';
|
|
178
|
+
const operatorPlayer = await ask('Operator player (default: jelli): ') || 'jelli';
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
info('Creating game...');
|
|
182
|
+
const response = await fetch(`${BASE_URL}/api/v1/demo/game/create`, {
|
|
183
|
+
method: 'POST',
|
|
184
|
+
headers: { 'Content-Type': 'application/json' },
|
|
185
|
+
body: JSON.stringify({
|
|
186
|
+
player,
|
|
187
|
+
buyIn: parseFloat(buyIn),
|
|
188
|
+
maxPlayers: parseInt(maxPlayers),
|
|
189
|
+
operatorFee: parseInt(operatorFee),
|
|
190
|
+
operatorPlayer
|
|
191
|
+
})
|
|
192
|
+
});
|
|
193
|
+
const data = await response.json();
|
|
194
|
+
|
|
195
|
+
if (data.success) {
|
|
196
|
+
success('Game created!');
|
|
197
|
+
console.log(` Game ID: ${colors.yellow}${data.gameId}${colors.reset}`);
|
|
198
|
+
console.log(` Transaction: ${data.transaction}`);
|
|
199
|
+
currentGameId = data.gameId;
|
|
200
|
+
} else {
|
|
201
|
+
error(data.error || 'Create failed');
|
|
202
|
+
}
|
|
203
|
+
} catch (err) {
|
|
204
|
+
error('Failed: ' + err.message);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 4. Get game info
|
|
209
|
+
async function getGameInfo() {
|
|
210
|
+
const gameId = await ask(`Game ID (current: ${currentGameId || 'none'}): `) || currentGameId;
|
|
211
|
+
|
|
212
|
+
if (!gameId) {
|
|
213
|
+
error('No game ID provided');
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
info('Fetching game info...');
|
|
219
|
+
const response = await fetch(`${BASE_URL}/api/v1/demo/game/${gameId}`);
|
|
220
|
+
const data = await response.json();
|
|
221
|
+
|
|
222
|
+
if (data.exists) {
|
|
223
|
+
console.log('');
|
|
224
|
+
printJson(data);
|
|
225
|
+
|
|
226
|
+
// Save player addresses
|
|
227
|
+
if (data.game.players) {
|
|
228
|
+
data.game.players.forEach((addr, i) => {
|
|
229
|
+
playerAddresses[`player${i}`] = addr;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Show voting status
|
|
234
|
+
if (data.game.votingEnabled) {
|
|
235
|
+
console.log('');
|
|
236
|
+
info(`Voting: ${data.game.votes?.length || 0} votes cast`);
|
|
237
|
+
const majority = Math.floor(data.game.players.length / 2) + 1;
|
|
238
|
+
console.log(` Majority needed: ${majority}`);
|
|
239
|
+
if (data.game.votes?.length >= majority) {
|
|
240
|
+
success('Majority reached! Can distribute by vote!');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
error('Game not found');
|
|
245
|
+
}
|
|
246
|
+
} catch (err) {
|
|
247
|
+
error('Failed: ' + err.message);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// 5. Join game
|
|
252
|
+
async function joinGame() {
|
|
253
|
+
const gameId = await ask(`Game ID (current: ${currentGameId || 'none'}): `) || currentGameId;
|
|
254
|
+
const player = await ask('Player name (alice/bob/charlie): ');
|
|
255
|
+
|
|
256
|
+
if (!gameId || !player) {
|
|
257
|
+
error('Game ID and player name required');
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
info(`${player} joining game...`);
|
|
263
|
+
const response = await fetch(`${BASE_URL}/api/v1/demo/game/join`, {
|
|
264
|
+
method: 'POST',
|
|
265
|
+
headers: { 'Content-Type': 'application/json' },
|
|
266
|
+
body: JSON.stringify({ player, gameId })
|
|
267
|
+
});
|
|
268
|
+
const data = await response.json();
|
|
269
|
+
|
|
270
|
+
if (data.success) {
|
|
271
|
+
success(data.message);
|
|
272
|
+
console.log(` Players: ${data.playersCount}`);
|
|
273
|
+
console.log(` Transaction: ${data.transaction}`);
|
|
274
|
+
} else {
|
|
275
|
+
error(data.error || 'Join failed');
|
|
276
|
+
}
|
|
277
|
+
} catch (err) {
|
|
278
|
+
error('Failed: ' + err.message);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// 6. Cast vote
|
|
283
|
+
async function castVote() {
|
|
284
|
+
const gameId = await ask(`Game ID (current: ${currentGameId || 'none'}): `) || currentGameId;
|
|
285
|
+
const player = await ask('Voter name (creator/alice/bob): ');
|
|
286
|
+
|
|
287
|
+
console.log('');
|
|
288
|
+
console.log('Available addresses:');
|
|
289
|
+
Object.keys(playerAddresses).forEach(name => {
|
|
290
|
+
console.log(` ${name}: ${playerAddresses[name]}`);
|
|
291
|
+
});
|
|
292
|
+
console.log('');
|
|
293
|
+
|
|
294
|
+
const votedFor = await ask('Vote for address (paste from above): ');
|
|
295
|
+
|
|
296
|
+
if (!gameId || !player || !votedFor) {
|
|
297
|
+
error('All fields required');
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
info(`${player} casting vote...`);
|
|
303
|
+
const response = await fetch(`${BASE_URL}/api/v1/demo/vote/cast`, {
|
|
304
|
+
method: 'POST',
|
|
305
|
+
headers: { 'Content-Type': 'application/json' },
|
|
306
|
+
body: JSON.stringify({ player, gameId, votedFor })
|
|
307
|
+
});
|
|
308
|
+
const data = await response.json();
|
|
309
|
+
|
|
310
|
+
if (data.success) {
|
|
311
|
+
success(data.message);
|
|
312
|
+
console.log(` Votes: ${data.votingProgress}`);
|
|
313
|
+
console.log(` Transaction: ${data.transaction}`);
|
|
314
|
+
} else {
|
|
315
|
+
error(data.error || 'Vote failed');
|
|
316
|
+
}
|
|
317
|
+
} catch (err) {
|
|
318
|
+
error('Failed: ' + err.message);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// 7. Distribute by vote
|
|
323
|
+
async function distributeByVote() {
|
|
324
|
+
const gameId = await ask(`Game ID (current: ${currentGameId || 'none'}): `) || currentGameId;
|
|
325
|
+
|
|
326
|
+
if (!gameId) {
|
|
327
|
+
error('Game ID required');
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
try {
|
|
332
|
+
info('Distributing by vote...');
|
|
333
|
+
const response = await fetch(`${BASE_URL}/api/v1/demo/vote/distribute`, {
|
|
334
|
+
method: 'POST',
|
|
335
|
+
headers: { 'Content-Type': 'application/json' },
|
|
336
|
+
body: JSON.stringify({ gameId })
|
|
337
|
+
});
|
|
338
|
+
const data = await response.json();
|
|
339
|
+
|
|
340
|
+
if (data.success) {
|
|
341
|
+
success(data.message);
|
|
342
|
+
console.log('');
|
|
343
|
+
console.log(colors.bright + 'š Winners:' + colors.reset);
|
|
344
|
+
data.winners.forEach(w => console.log(` ${w}`));
|
|
345
|
+
console.log('');
|
|
346
|
+
console.log(colors.bright + 'š Vote Counts:' + colors.reset);
|
|
347
|
+
Object.entries(data.voteCounts).forEach(([addr, count]) => {
|
|
348
|
+
console.log(` ${addr.slice(0, 8)}... : ${count} votes`);
|
|
349
|
+
});
|
|
350
|
+
console.log('');
|
|
351
|
+
console.log(` Transaction: ${data.transaction}`);
|
|
352
|
+
} else {
|
|
353
|
+
error(data.error || 'Distribution failed');
|
|
354
|
+
}
|
|
355
|
+
} catch (err) {
|
|
356
|
+
error('Failed: ' + err.message);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// 8. Distribute manually
|
|
361
|
+
async function distributeManually() {
|
|
362
|
+
const gameId = await ask(`Game ID (current: ${currentGameId || 'none'}): `) || currentGameId;
|
|
363
|
+
|
|
364
|
+
console.log('');
|
|
365
|
+
console.log('Available addresses:');
|
|
366
|
+
Object.keys(playerAddresses).forEach(name => {
|
|
367
|
+
console.log(` ${name}: ${playerAddresses[name]}`);
|
|
368
|
+
});
|
|
369
|
+
console.log('');
|
|
370
|
+
|
|
371
|
+
const winners = await ask('Winner addresses (comma-separated): ');
|
|
372
|
+
|
|
373
|
+
if (!gameId || !winners) {
|
|
374
|
+
error('Game ID and winners required');
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const winnerArray = winners.split(',').map(w => w.trim());
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
info('Distributing winnings...');
|
|
382
|
+
const response = await fetch(`${BASE_URL}/api/v1/demo/game/distribute`, {
|
|
383
|
+
method: 'POST',
|
|
384
|
+
headers: { 'Content-Type': 'application/json' },
|
|
385
|
+
body: JSON.stringify({ gameId, winners: winnerArray })
|
|
386
|
+
});
|
|
387
|
+
const data = await response.json();
|
|
388
|
+
|
|
389
|
+
if (data.success) {
|
|
390
|
+
success(data.message);
|
|
391
|
+
printJson(data);
|
|
392
|
+
} else {
|
|
393
|
+
error(data.error || 'Distribution failed');
|
|
394
|
+
}
|
|
395
|
+
} catch (err) {
|
|
396
|
+
error('Failed: ' + err.message);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// 9. Full voting test (automated)
|
|
401
|
+
async function fullVotingTest() {
|
|
402
|
+
console.log('');
|
|
403
|
+
console.log(colors.bright + 'š Running Full Voting Test...' + colors.reset);
|
|
404
|
+
console.log('');
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
// Create game
|
|
408
|
+
info('1/7 Creating game...');
|
|
409
|
+
let response = await fetch(`${BASE_URL}/api/v1/demo/game/create`, {
|
|
410
|
+
method: 'POST',
|
|
411
|
+
headers: { 'Content-Type': 'application/json' },
|
|
412
|
+
body: JSON.stringify({
|
|
413
|
+
player: 'creator',
|
|
414
|
+
buyIn: 0.5,
|
|
415
|
+
maxPlayers: 3,
|
|
416
|
+
operatorFee: 10,
|
|
417
|
+
operatorPlayer: 'jelli'
|
|
418
|
+
})
|
|
419
|
+
});
|
|
420
|
+
let data = await response.json();
|
|
421
|
+
const gameId = data.gameId;
|
|
422
|
+
currentGameId = gameId;
|
|
423
|
+
success(`Game created: ${gameId}`);
|
|
424
|
+
|
|
425
|
+
// Creator joins (must join to play!)
|
|
426
|
+
info('2/7 Creator joining...');
|
|
427
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/game/join`, {
|
|
428
|
+
method: 'POST',
|
|
429
|
+
headers: { 'Content-Type': 'application/json' },
|
|
430
|
+
body: JSON.stringify({ player: 'creator', gameId })
|
|
431
|
+
});
|
|
432
|
+
data = await response.json();
|
|
433
|
+
if (!data.success) {
|
|
434
|
+
error(`Creator join failed: ${data.error}`);
|
|
435
|
+
throw new Error('Creator failed to join');
|
|
436
|
+
}
|
|
437
|
+
success(data.message);
|
|
438
|
+
|
|
439
|
+
// Alice joins
|
|
440
|
+
info('3/7 Alice joining...');
|
|
441
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/game/join`, {
|
|
442
|
+
method: 'POST',
|
|
443
|
+
headers: { 'Content-Type': 'application/json' },
|
|
444
|
+
body: JSON.stringify({ player: 'alice', gameId })
|
|
445
|
+
});
|
|
446
|
+
data = await response.json();
|
|
447
|
+
if (!data.success) {
|
|
448
|
+
error(`Alice join failed: ${data.error}`);
|
|
449
|
+
throw new Error('Alice failed to join');
|
|
450
|
+
}
|
|
451
|
+
success(data.message);
|
|
452
|
+
|
|
453
|
+
// Bob joins
|
|
454
|
+
info('4/7 Bob joining...');
|
|
455
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/game/join`, {
|
|
456
|
+
method: 'POST',
|
|
457
|
+
headers: { 'Content-Type': 'application/json' },
|
|
458
|
+
body: JSON.stringify({ player: 'bob', gameId })
|
|
459
|
+
});
|
|
460
|
+
data = await response.json();
|
|
461
|
+
if (!data.success) {
|
|
462
|
+
error(`Bob join failed: ${data.error}`);
|
|
463
|
+
throw new Error('Bob failed to join');
|
|
464
|
+
}
|
|
465
|
+
success(data.message);
|
|
466
|
+
|
|
467
|
+
// Get game info to get addresses
|
|
468
|
+
info('5/8 Getting player addresses...');
|
|
469
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/game/${gameId}`);
|
|
470
|
+
data = await response.json();
|
|
471
|
+
|
|
472
|
+
if (!data.game || !data.game.players || data.game.players.length < 3) {
|
|
473
|
+
error(`Expected 3 players, got ${data.game?.players?.length || 0}`);
|
|
474
|
+
console.log('Players:', data.game?.players);
|
|
475
|
+
throw new Error(`Expected 3 players, got ${data.game?.players?.length || 0}`);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const creatorAddr = data.game.players[0]; // Creator is 1st
|
|
479
|
+
const aliceAddr = data.game.players[1]; // Alice is 2nd
|
|
480
|
+
const bobAddr = data.game.players[2]; // Bob is 3rd
|
|
481
|
+
|
|
482
|
+
success(`Creator: ${creatorAddr.slice(0, 8)}...`);
|
|
483
|
+
success(`Alice: ${aliceAddr.slice(0, 8)}...`);
|
|
484
|
+
success(`Bob: ${bobAddr.slice(0, 8)}...`);
|
|
485
|
+
info(`Total players: ${data.game.players.length}`);
|
|
486
|
+
|
|
487
|
+
// Creator votes for Alice
|
|
488
|
+
info('6/8 Creator voting for Alice...');
|
|
489
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/vote/cast`, {
|
|
490
|
+
method: 'POST',
|
|
491
|
+
headers: { 'Content-Type': 'application/json' },
|
|
492
|
+
body: JSON.stringify({ player: 'creator', gameId, votedFor: aliceAddr })
|
|
493
|
+
});
|
|
494
|
+
data = await response.json();
|
|
495
|
+
|
|
496
|
+
if (!data.success) {
|
|
497
|
+
error(`Creator vote failed: ${data.error || 'Unknown error'}`);
|
|
498
|
+
throw new Error('Creator vote failed');
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
success(`${data.message} (${data.votingProgress})`);
|
|
502
|
+
|
|
503
|
+
// Alice votes for herself
|
|
504
|
+
info('7/8 Alice voting for herself...');
|
|
505
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/vote/cast`, {
|
|
506
|
+
method: 'POST',
|
|
507
|
+
headers: { 'Content-Type': 'application/json' },
|
|
508
|
+
body: JSON.stringify({ player: 'alice', gameId, votedFor: aliceAddr })
|
|
509
|
+
});
|
|
510
|
+
data = await response.json();
|
|
511
|
+
|
|
512
|
+
if (!data.success) {
|
|
513
|
+
error(`Alice vote failed: ${data.error || 'Unknown error'}`);
|
|
514
|
+
throw new Error('Alice vote failed');
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const votesNeeded = Math.floor(3 / 2) + 1; // 3 players = need 2 votes
|
|
518
|
+
const hasMajority = data.votesCount >= votesNeeded;
|
|
519
|
+
success(`${data.message} (${data.votingProgress})${hasMajority ? ' - MAJORITY REACHED!' : ''}`);
|
|
520
|
+
|
|
521
|
+
// Distribute by vote
|
|
522
|
+
info('8/8 Distributing by vote...');
|
|
523
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/vote/distribute`, {
|
|
524
|
+
method: 'POST',
|
|
525
|
+
headers: { 'Content-Type': 'application/json' },
|
|
526
|
+
body: JSON.stringify({ gameId })
|
|
527
|
+
});
|
|
528
|
+
data = await response.json();
|
|
529
|
+
|
|
530
|
+
if (data.success) {
|
|
531
|
+
console.log('');
|
|
532
|
+
success('š DEMOCRACY WINS!');
|
|
533
|
+
console.log('');
|
|
534
|
+
console.log(colors.bright + 'š Winners:' + colors.reset);
|
|
535
|
+
data.winners.forEach(w => console.log(` ${w}`));
|
|
536
|
+
console.log('');
|
|
537
|
+
console.log(colors.bright + 'š Vote Results:' + colors.reset);
|
|
538
|
+
Object.entries(data.voteCounts).forEach(([addr, count]) => {
|
|
539
|
+
console.log(` ${addr.slice(0, 8)}... : ${colors.green}${count} votes${colors.reset}`);
|
|
540
|
+
});
|
|
541
|
+
console.log('');
|
|
542
|
+
console.log(` Transaction: ${data.transaction}`);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
} catch (err) {
|
|
546
|
+
error('Test failed: ' + err.message);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// 10. Three-way tie test
|
|
551
|
+
async function threeWayTieTest() {
|
|
552
|
+
console.log('');
|
|
553
|
+
console.log(colors.bright + 'š² Running 3-Way Tie Test...' + colors.reset);
|
|
554
|
+
console.log('');
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
// Create game
|
|
558
|
+
info('Creating game...');
|
|
559
|
+
let response = await fetch(`${BASE_URL}/api/v1/demo/game/create`, {
|
|
560
|
+
method: 'POST',
|
|
561
|
+
headers: { 'Content-Type': 'application/json' },
|
|
562
|
+
body: JSON.stringify({
|
|
563
|
+
player: 'creator',
|
|
564
|
+
buyIn: 0.5,
|
|
565
|
+
maxPlayers: 3,
|
|
566
|
+
operatorFee: 10,
|
|
567
|
+
operatorPlayer: 'jelli'
|
|
568
|
+
})
|
|
569
|
+
});
|
|
570
|
+
let data = await response.json();
|
|
571
|
+
const gameId = data.gameId;
|
|
572
|
+
currentGameId = gameId;
|
|
573
|
+
success(`Game created: ${gameId}`);
|
|
574
|
+
|
|
575
|
+
// Players join
|
|
576
|
+
info('Players joining...');
|
|
577
|
+
await fetch(`${BASE_URL}/api/v1/demo/game/join`, {
|
|
578
|
+
method: 'POST',
|
|
579
|
+
headers: { 'Content-Type': 'application/json' },
|
|
580
|
+
body: JSON.stringify({ player: 'alice', gameId })
|
|
581
|
+
});
|
|
582
|
+
await fetch(`${BASE_URL}/api/v1/demo/game/join`, {
|
|
583
|
+
method: 'POST',
|
|
584
|
+
headers: { 'Content-Type': 'application/json' },
|
|
585
|
+
body: JSON.stringify({ player: 'bob', gameId })
|
|
586
|
+
});
|
|
587
|
+
success('All players joined');
|
|
588
|
+
|
|
589
|
+
// Get addresses
|
|
590
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/game/${gameId}`);
|
|
591
|
+
data = await response.json();
|
|
592
|
+
const [creatorAddr, aliceAddr, bobAddr] = data.game.players;
|
|
593
|
+
|
|
594
|
+
// Each votes for themselves (3-way tie!)
|
|
595
|
+
info('Each player votes for themselves (3-way tie)...');
|
|
596
|
+
await fetch(`${BASE_URL}/api/v1/demo/vote/cast`, {
|
|
597
|
+
method: 'POST',
|
|
598
|
+
headers: { 'Content-Type': 'application/json' },
|
|
599
|
+
body: JSON.stringify({ player: 'creator', gameId, votedFor: creatorAddr })
|
|
600
|
+
});
|
|
601
|
+
await fetch(`${BASE_URL}/api/v1/demo/vote/cast`, {
|
|
602
|
+
method: 'POST',
|
|
603
|
+
headers: { 'Content-Type': 'application/json' },
|
|
604
|
+
body: JSON.stringify({ player: 'alice', gameId, votedFor: aliceAddr })
|
|
605
|
+
});
|
|
606
|
+
await fetch(`${BASE_URL}/api/v1/demo/vote/cast`, {
|
|
607
|
+
method: 'POST',
|
|
608
|
+
headers: { 'Content-Type': 'application/json' },
|
|
609
|
+
body: JSON.stringify({ player: 'bob', gameId, votedFor: bobAddr })
|
|
610
|
+
});
|
|
611
|
+
success('All votes cast - each player has 1 vote (TIE!)');
|
|
612
|
+
|
|
613
|
+
// Distribute
|
|
614
|
+
info('Distributing (should split 3 ways)...');
|
|
615
|
+
response = await fetch(`${BASE_URL}/api/v1/demo/vote/distribute`, {
|
|
616
|
+
method: 'POST',
|
|
617
|
+
headers: { 'Content-Type': 'application/json' },
|
|
618
|
+
body: JSON.stringify({ gameId })
|
|
619
|
+
});
|
|
620
|
+
data = await response.json();
|
|
621
|
+
|
|
622
|
+
if (data.success) {
|
|
623
|
+
console.log('');
|
|
624
|
+
success('š 3-WAY TIE HANDLED!');
|
|
625
|
+
console.log(` Winners: ${data.winnersCount} (all 3!)`);
|
|
626
|
+
console.log(` Each gets: 33.33% of prize pool`);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
} catch (err) {
|
|
630
|
+
error('Test failed: ' + err.message);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Main loop
|
|
635
|
+
async function main() {
|
|
636
|
+
console.log(colors.bright + colors.green);
|
|
637
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
638
|
+
console.log('ā š® Welcome to Dubs CLI Testing Tool š® ā');
|
|
639
|
+
console.log('ā ā');
|
|
640
|
+
console.log('ā Test democratic voting without Postman! ā');
|
|
641
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
642
|
+
console.log(colors.reset);
|
|
643
|
+
console.log('');
|
|
644
|
+
|
|
645
|
+
// Test connection
|
|
646
|
+
try {
|
|
647
|
+
const response = await fetch(`${BASE_URL}/health`);
|
|
648
|
+
const data = await response.json();
|
|
649
|
+
success(`Connected to server: ${data.message}`);
|
|
650
|
+
} catch (err) {
|
|
651
|
+
error(`Cannot connect to server at ${BASE_URL}`);
|
|
652
|
+
console.log('');
|
|
653
|
+
console.log('Make sure the server is running:');
|
|
654
|
+
console.log(' cd dubs-server && node server.js');
|
|
655
|
+
process.exit(1);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
console.log('');
|
|
659
|
+
await ask('Press Enter to continue...');
|
|
660
|
+
|
|
661
|
+
while (true) {
|
|
662
|
+
await showMenu();
|
|
663
|
+
const choice = await ask('Select option: ');
|
|
664
|
+
console.log('');
|
|
665
|
+
|
|
666
|
+
switch (choice) {
|
|
667
|
+
case '1':
|
|
668
|
+
await listWallets();
|
|
669
|
+
break;
|
|
670
|
+
case '2':
|
|
671
|
+
await airdrop();
|
|
672
|
+
break;
|
|
673
|
+
case '3':
|
|
674
|
+
await createGame();
|
|
675
|
+
break;
|
|
676
|
+
case '4':
|
|
677
|
+
await getGameInfo();
|
|
678
|
+
break;
|
|
679
|
+
case '5':
|
|
680
|
+
await joinGame();
|
|
681
|
+
break;
|
|
682
|
+
case '6':
|
|
683
|
+
await castVote();
|
|
684
|
+
break;
|
|
685
|
+
case '7':
|
|
686
|
+
await distributeByVote();
|
|
687
|
+
break;
|
|
688
|
+
case '8':
|
|
689
|
+
await distributeManually();
|
|
690
|
+
break;
|
|
691
|
+
case '9':
|
|
692
|
+
await fullVotingTest();
|
|
693
|
+
break;
|
|
694
|
+
case '10':
|
|
695
|
+
await threeWayTieTest();
|
|
696
|
+
break;
|
|
697
|
+
case '0':
|
|
698
|
+
console.log(colors.green + '\nš Goodbye! Happy gaming! š®\n' + colors.reset);
|
|
699
|
+
rl.close();
|
|
700
|
+
process.exit(0);
|
|
701
|
+
default:
|
|
702
|
+
error('Invalid option');
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
console.log('');
|
|
706
|
+
await ask('Press Enter to continue...');
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Handle exit
|
|
711
|
+
rl.on('close', () => {
|
|
712
|
+
process.exit(0);
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
// Run
|
|
716
|
+
main().catch(err => {
|
|
717
|
+
console.error('Fatal error:', err);
|
|
718
|
+
process.exit(1);
|
|
719
|
+
});
|
|
720
|
+
|