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,113 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# ============================================
|
|
4
|
+
# š® REBUILD HEROKU DATABASE FROM SCRATCH
|
|
5
|
+
# ============================================
|
|
6
|
+
# This script completely nukes and rebuilds the Heroku database
|
|
7
|
+
# with the complete new schema
|
|
8
|
+
|
|
9
|
+
set -e
|
|
10
|
+
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
GREEN='\033[0;32m'
|
|
13
|
+
YELLOW='\033[1;33m'
|
|
14
|
+
BLUE='\033[0;34m'
|
|
15
|
+
NC='\033[0m'
|
|
16
|
+
|
|
17
|
+
# Get DATABASE_URL from Heroku
|
|
18
|
+
echo "š” Getting Heroku database URL..."
|
|
19
|
+
DB_URL=$(heroku config:get DATABASE_URL 2>&1 | grep -v "Warning" | grep -v "Error ID" | grep "postgres://")
|
|
20
|
+
|
|
21
|
+
if [ -z "$DB_URL" ]; then
|
|
22
|
+
echo -e "${RED}ā Could not get DATABASE_URL from Heroku${NC}"
|
|
23
|
+
echo "Make sure you're in the right directory with Heroku app configured"
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
echo -e "${GREEN}ā
Found Heroku database${NC}"
|
|
28
|
+
echo ""
|
|
29
|
+
|
|
30
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
31
|
+
echo "ā ā ļø NUKE HEROKU PRODUCTION DATABASE ā ļø ā"
|
|
32
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
33
|
+
echo ""
|
|
34
|
+
echo -e "${RED}This will DELETE EVERYTHING and rebuild from scratch!${NC}"
|
|
35
|
+
echo ""
|
|
36
|
+
echo "Database: $(echo $DB_URL | sed 's/postgres:\/\/.*@/postgres:\/\/*****@/')"
|
|
37
|
+
echo ""
|
|
38
|
+
|
|
39
|
+
read -p "Type 'NUKE' to confirm: " -r
|
|
40
|
+
echo ""
|
|
41
|
+
|
|
42
|
+
if [[ ! $REPLY == "NUKE" ]]; then
|
|
43
|
+
echo -e "${GREEN}ā
Cancelled${NC}"
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
echo ""
|
|
48
|
+
echo "šļø Step 1: Dropping all tables..."
|
|
49
|
+
echo ""
|
|
50
|
+
|
|
51
|
+
psql "$DB_URL" << 'DROPSQL'
|
|
52
|
+
-- Drop all views first
|
|
53
|
+
DROP VIEW IF EXISTS keeper_health_summary CASCADE;
|
|
54
|
+
DROP VIEW IF EXISTS stuck_rounds CASCADE;
|
|
55
|
+
|
|
56
|
+
-- Drop all tables
|
|
57
|
+
DROP TABLE IF EXISTS chat_notifications CASCADE;
|
|
58
|
+
DROP TABLE IF EXISTS chat_reactions CASCADE;
|
|
59
|
+
DROP TABLE IF EXISTS chat_messages CASCADE;
|
|
60
|
+
DROP TABLE IF EXISTS user_relationships CASCADE;
|
|
61
|
+
DROP TABLE IF EXISTS friend_requests CASCADE;
|
|
62
|
+
DROP TABLE IF EXISTS friends CASCADE;
|
|
63
|
+
DROP TABLE IF EXISTS group_members CASCADE;
|
|
64
|
+
DROP TABLE IF EXISTS groups CASCADE;
|
|
65
|
+
DROP TABLE IF EXISTS player_history CASCADE;
|
|
66
|
+
DROP TABLE IF EXISTS player_stats CASCADE;
|
|
67
|
+
DROP TABLE IF EXISTS user_badges CASCADE;
|
|
68
|
+
DROP TABLE IF EXISTS auth_nonces CASCADE;
|
|
69
|
+
DROP TABLE IF EXISTS user_sessions CASCADE;
|
|
70
|
+
DROP TABLE IF EXISTS keeper_actions CASCADE;
|
|
71
|
+
DROP TABLE IF EXISTS keeper_health CASCADE;
|
|
72
|
+
DROP TABLE IF EXISTS keeper_rounds CASCADE;
|
|
73
|
+
DROP TABLE IF EXISTS jackpot_rounds CASCADE;
|
|
74
|
+
DROP TABLE IF EXISTS users CASCADE;
|
|
75
|
+
|
|
76
|
+
SELECT 'All tables dropped' as status;
|
|
77
|
+
DROPSQL
|
|
78
|
+
|
|
79
|
+
echo -e "${GREEN}ā
All tables dropped${NC}"
|
|
80
|
+
echo ""
|
|
81
|
+
echo "šļø Step 2: Creating complete schema..."
|
|
82
|
+
echo ""
|
|
83
|
+
|
|
84
|
+
# Run the complete schema setup
|
|
85
|
+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
86
|
+
psql "$DB_URL" < "$SCRIPT_DIR/setup-complete-database.sql"
|
|
87
|
+
|
|
88
|
+
echo ""
|
|
89
|
+
echo -e "${GREEN}ā
Schema created${NC}"
|
|
90
|
+
echo ""
|
|
91
|
+
echo "š Step 3: Verifying setup..."
|
|
92
|
+
echo ""
|
|
93
|
+
|
|
94
|
+
# Count tables
|
|
95
|
+
TABLE_COUNT=$(psql "$DB_URL" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE';" | xargs)
|
|
96
|
+
|
|
97
|
+
echo "Tables created: $TABLE_COUNT"
|
|
98
|
+
echo ""
|
|
99
|
+
|
|
100
|
+
# List tables
|
|
101
|
+
psql "$DB_URL" -c "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE' ORDER BY table_name;"
|
|
102
|
+
|
|
103
|
+
echo ""
|
|
104
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
105
|
+
echo "ā ā
HEROKU DATABASE REBUILT! ā
ā"
|
|
106
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
107
|
+
echo ""
|
|
108
|
+
echo -e "${GREEN}ā
Complete schema with $TABLE_COUNT tables${NC}"
|
|
109
|
+
echo -e "${GREEN}ā
All indexes and views created${NC}"
|
|
110
|
+
echo -e "${GREEN}ā
Ready for production use${NC}"
|
|
111
|
+
echo ""
|
|
112
|
+
echo "š Your Heroku database is now fresh and ready!"
|
|
113
|
+
echo ""
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Fund Recovery Script
|
|
4
|
+
* Check game PDAs and help recover stuck funds
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node recover-funds.js <pda1> <pda2> ...
|
|
8
|
+
* node recover-funds.js --claim <gameId> <playerAddress>
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
require('dotenv').config();
|
|
12
|
+
const { Connection, PublicKey, Keypair, Transaction, TransactionInstruction, LAMPORTS_PER_SOL } = require('@solana/web3.js');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
// Program ID (mainnet)
|
|
17
|
+
const PROGRAM_ID = new PublicKey('85wJGp9uc8w2FeKX9CEHsudTo1UVCrmuRFy37oCcaoG1');
|
|
18
|
+
|
|
19
|
+
// Instruction discriminators
|
|
20
|
+
const CLAIM_AUTO = Buffer.from([8, 125, 228, 42, 245, 90, 82, 17]); // claim_automatic_winnings
|
|
21
|
+
const EMERGENCY_REFUND = Buffer.from([/* need to calculate */]); // emergency_refund_automatic
|
|
22
|
+
|
|
23
|
+
// RPC endpoint
|
|
24
|
+
const RPC_URL = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com';
|
|
25
|
+
|
|
26
|
+
console.log('š° Fund Recovery Tool');
|
|
27
|
+
console.log('=====================');
|
|
28
|
+
console.log(`RPC: ${RPC_URL}`);
|
|
29
|
+
console.log(`Program: ${PROGRAM_ID.toString()}`);
|
|
30
|
+
console.log('');
|
|
31
|
+
|
|
32
|
+
const connection = new Connection(RPC_URL, 'confirmed');
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Decode game account data
|
|
36
|
+
*/
|
|
37
|
+
function decodeGameAccount(data) {
|
|
38
|
+
try {
|
|
39
|
+
// Skip 8 byte discriminator
|
|
40
|
+
let offset = 8;
|
|
41
|
+
|
|
42
|
+
// game_id: u64
|
|
43
|
+
const gameId = data.readBigUInt64LE(offset);
|
|
44
|
+
offset += 8;
|
|
45
|
+
|
|
46
|
+
// authority: Pubkey (32 bytes)
|
|
47
|
+
const authority = new PublicKey(data.slice(offset, offset + 32));
|
|
48
|
+
offset += 32;
|
|
49
|
+
|
|
50
|
+
// buy_in: u64
|
|
51
|
+
const buyIn = data.readBigUInt64LE(offset);
|
|
52
|
+
offset += 8;
|
|
53
|
+
|
|
54
|
+
// max_players: u8
|
|
55
|
+
const maxPlayers = data.readUInt8(offset);
|
|
56
|
+
offset += 1;
|
|
57
|
+
|
|
58
|
+
// operator_wallet: Pubkey (32 bytes)
|
|
59
|
+
const operatorWallet = new PublicKey(data.slice(offset, offset + 32));
|
|
60
|
+
offset += 32;
|
|
61
|
+
|
|
62
|
+
// operator_fee_percentage: u8
|
|
63
|
+
const operatorFee = data.readUInt8(offset);
|
|
64
|
+
offset += 1;
|
|
65
|
+
|
|
66
|
+
// players vec: 4 bytes length + 32 bytes * length
|
|
67
|
+
const playersLen = data.readUInt32LE(offset);
|
|
68
|
+
offset += 4;
|
|
69
|
+
const players = [];
|
|
70
|
+
for (let i = 0; i < playersLen; i++) {
|
|
71
|
+
players.push(new PublicKey(data.slice(offset, offset + 32)));
|
|
72
|
+
offset += 32;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// total_pot: u64
|
|
76
|
+
const totalPot = data.readBigUInt64LE(offset);
|
|
77
|
+
offset += 8;
|
|
78
|
+
|
|
79
|
+
// is_active: bool
|
|
80
|
+
const isActive = data.readUInt8(offset) === 1;
|
|
81
|
+
offset += 1;
|
|
82
|
+
|
|
83
|
+
// votes vec: skip for now (4 bytes length + entries)
|
|
84
|
+
const votesLen = data.readUInt32LE(offset);
|
|
85
|
+
offset += 4;
|
|
86
|
+
offset += votesLen * (32 + 32); // voter + voted_for
|
|
87
|
+
|
|
88
|
+
// voting_enabled: bool
|
|
89
|
+
const votingEnabled = data.readUInt8(offset) === 1;
|
|
90
|
+
offset += 1;
|
|
91
|
+
|
|
92
|
+
// game_mode: u8
|
|
93
|
+
const gameMode = data.readUInt8(offset);
|
|
94
|
+
offset += 1;
|
|
95
|
+
|
|
96
|
+
// referee: Option<Pubkey> - 1 byte tag + 32 bytes if Some
|
|
97
|
+
const hasReferee = data.readUInt8(offset) === 1;
|
|
98
|
+
offset += 1;
|
|
99
|
+
if (hasReferee) {
|
|
100
|
+
offset += 32;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// referee_commission: u8
|
|
104
|
+
const refereeCommission = data.readUInt8(offset);
|
|
105
|
+
offset += 1;
|
|
106
|
+
|
|
107
|
+
// player_picks vec: 4 bytes length + (32 + 1) bytes * length
|
|
108
|
+
const picksLen = data.readUInt32LE(offset);
|
|
109
|
+
offset += 4;
|
|
110
|
+
const playerPicks = [];
|
|
111
|
+
for (let i = 0; i < picksLen; i++) {
|
|
112
|
+
const player = new PublicKey(data.slice(offset, offset + 32));
|
|
113
|
+
offset += 32;
|
|
114
|
+
const teamChoice = data.readUInt8(offset); // 0 = Home, 1 = Away
|
|
115
|
+
offset += 1;
|
|
116
|
+
playerPicks.push({ player: player.toString(), teamChoice: teamChoice === 0 ? 'Home' : 'Away' });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// lock_timestamp: i64
|
|
120
|
+
const lockTimestamp = Number(data.readBigInt64LE(offset));
|
|
121
|
+
offset += 8;
|
|
122
|
+
|
|
123
|
+
// is_locked: bool
|
|
124
|
+
const isLocked = data.readUInt8(offset) === 1;
|
|
125
|
+
offset += 1;
|
|
126
|
+
|
|
127
|
+
// is_resolved: bool
|
|
128
|
+
const isResolved = data.readUInt8(offset) === 1;
|
|
129
|
+
offset += 1;
|
|
130
|
+
|
|
131
|
+
// winning_team: Option<TeamChoice>
|
|
132
|
+
const hasWinner = data.readUInt8(offset) === 1;
|
|
133
|
+
offset += 1;
|
|
134
|
+
let winningTeam = null;
|
|
135
|
+
if (hasWinner) {
|
|
136
|
+
winningTeam = data.readUInt8(offset) === 0 ? 'Home' : 'Away';
|
|
137
|
+
offset += 1;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// sports_event_id: String (4 bytes length + chars)
|
|
141
|
+
const eventIdLen = data.readUInt32LE(offset);
|
|
142
|
+
offset += 4;
|
|
143
|
+
const sportsEventId = data.slice(offset, offset + eventIdLen).toString('utf8');
|
|
144
|
+
offset += eventIdLen;
|
|
145
|
+
|
|
146
|
+
// oracle: Pubkey
|
|
147
|
+
const oracle = new PublicKey(data.slice(offset, offset + 32));
|
|
148
|
+
offset += 32;
|
|
149
|
+
|
|
150
|
+
// claimed_players vec
|
|
151
|
+
const claimedLen = data.readUInt32LE(offset);
|
|
152
|
+
offset += 4;
|
|
153
|
+
const claimedPlayers = [];
|
|
154
|
+
for (let i = 0; i < claimedLen; i++) {
|
|
155
|
+
claimedPlayers.push(new PublicKey(data.slice(offset, offset + 32)).toString());
|
|
156
|
+
offset += 32;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// operator_fee_claimed: bool
|
|
160
|
+
const operatorFeeClaimed = data.readUInt8(offset) === 1;
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
gameId: gameId.toString(),
|
|
164
|
+
authority: authority.toString(),
|
|
165
|
+
buyIn: Number(buyIn) / LAMPORTS_PER_SOL,
|
|
166
|
+
maxPlayers,
|
|
167
|
+
operatorWallet: operatorWallet.toString(),
|
|
168
|
+
operatorFee,
|
|
169
|
+
players: players.map(p => p.toString()),
|
|
170
|
+
totalPot: Number(totalPot) / LAMPORTS_PER_SOL,
|
|
171
|
+
isActive,
|
|
172
|
+
votingEnabled,
|
|
173
|
+
gameMode: ['Manual', 'Democratic', 'Referee', 'Automatic'][gameMode],
|
|
174
|
+
playerPicks,
|
|
175
|
+
lockTimestamp: new Date(lockTimestamp * 1000).toISOString(),
|
|
176
|
+
isLocked,
|
|
177
|
+
isResolved,
|
|
178
|
+
winningTeam,
|
|
179
|
+
sportsEventId,
|
|
180
|
+
oracle: oracle.toString(),
|
|
181
|
+
claimedPlayers,
|
|
182
|
+
operatorFeeClaimed,
|
|
183
|
+
};
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error('Decode error:', error.message);
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Check a single game PDA
|
|
192
|
+
*/
|
|
193
|
+
async function checkGamePDA(pdaAddress) {
|
|
194
|
+
console.log(`\nš Checking PDA: ${pdaAddress}`);
|
|
195
|
+
console.log('ā'.repeat(60));
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const pda = new PublicKey(pdaAddress);
|
|
199
|
+
const accountInfo = await connection.getAccountInfo(pda);
|
|
200
|
+
|
|
201
|
+
if (!accountInfo) {
|
|
202
|
+
console.log(' ā Account does not exist (funds may have been withdrawn)');
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
console.log(` š° Balance: ${accountInfo.lamports / LAMPORTS_PER_SOL} SOL`);
|
|
207
|
+
console.log(` š¦ Data size: ${accountInfo.data.length} bytes`);
|
|
208
|
+
console.log(` š¤ Owner: ${accountInfo.owner.toString()}`);
|
|
209
|
+
|
|
210
|
+
if (!accountInfo.owner.equals(PROGRAM_ID)) {
|
|
211
|
+
console.log(' ā ļø Not owned by Dubs program!');
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const game = decodeGameAccount(accountInfo.data);
|
|
216
|
+
|
|
217
|
+
if (!game) {
|
|
218
|
+
console.log(' ā ļø Could not decode game data');
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log(`\n š Game State:`);
|
|
223
|
+
console.log(` Game ID: ${game.gameId}`);
|
|
224
|
+
console.log(` Mode: ${game.gameMode}`);
|
|
225
|
+
console.log(` Buy-in: ${game.buyIn} SOL`);
|
|
226
|
+
console.log(` Prize Pool: ${game.totalPot} SOL`);
|
|
227
|
+
console.log(` Active: ${game.isActive}`);
|
|
228
|
+
console.log(` Locked: ${game.isLocked}`);
|
|
229
|
+
console.log(` Resolved: ${game.isResolved}`);
|
|
230
|
+
console.log(` Winner: ${game.winningTeam || 'None (refund all)'}`);
|
|
231
|
+
console.log(` Lock Time: ${game.lockTimestamp}`);
|
|
232
|
+
console.log(` Sports Event: ${game.sportsEventId || 'N/A'}`);
|
|
233
|
+
|
|
234
|
+
console.log(`\n š„ Player Picks (${game.playerPicks.length}):`);
|
|
235
|
+
game.playerPicks.forEach((pick, i) => {
|
|
236
|
+
const claimed = game.claimedPlayers.includes(pick.player) ? 'ā
CLAIMED' : 'ā³ Unclaimed';
|
|
237
|
+
console.log(` ${i + 1}. ${pick.player.slice(0, 8)}... ā ${pick.teamChoice} ${claimed}`);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
if (game.claimedPlayers.length > 0) {
|
|
241
|
+
console.log(`\n ā
Claimed Players (${game.claimedPlayers.length}):`);
|
|
242
|
+
game.claimedPlayers.forEach((p, i) => {
|
|
243
|
+
console.log(` ${i + 1}. ${p.slice(0, 8)}...`);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Determine recovery action
|
|
248
|
+
console.log(`\n š§ Recovery Status:`);
|
|
249
|
+
|
|
250
|
+
if (game.isResolved) {
|
|
251
|
+
if (game.winningTeam === null) {
|
|
252
|
+
console.log(` ā
Game resolved as TIE/REFUND - all players can claim!`);
|
|
253
|
+
} else {
|
|
254
|
+
console.log(` ā
Game resolved - ${game.winningTeam} team won`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const unclaimedPlayers = game.playerPicks
|
|
258
|
+
.filter(p => !game.claimedPlayers.includes(p.player))
|
|
259
|
+
.map(p => p.player);
|
|
260
|
+
|
|
261
|
+
if (unclaimedPlayers.length > 0) {
|
|
262
|
+
console.log(` š¢ ${unclaimedPlayers.length} player(s) can still claim!`);
|
|
263
|
+
console.log(` š” Use: node recover-funds.js --claim ${game.gameId} <yourWalletAddress>`);
|
|
264
|
+
} else {
|
|
265
|
+
console.log(` ā
All players have claimed`);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
const now = Date.now();
|
|
269
|
+
const lockTime = new Date(game.lockTimestamp).getTime();
|
|
270
|
+
const sevenDays = 7 * 24 * 60 * 60 * 1000;
|
|
271
|
+
|
|
272
|
+
if (now > lockTime + sevenDays) {
|
|
273
|
+
console.log(` ā ļø NOT resolved but 7 days have passed!`);
|
|
274
|
+
console.log(` š” Emergency refund is available!`);
|
|
275
|
+
console.log(` š” Oracle or anyone can trigger emergency_refund_automatic`);
|
|
276
|
+
} else {
|
|
277
|
+
const daysUntil = Math.ceil((lockTime + sevenDays - now) / (24 * 60 * 60 * 1000));
|
|
278
|
+
console.log(` ā³ NOT resolved yet`);
|
|
279
|
+
console.log(` ā³ Emergency refund available in ${daysUntil} days`);
|
|
280
|
+
console.log(` š” Oracle needs to resolve this game first`);
|
|
281
|
+
console.log(` š” Or wait for emergency refund window`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return game;
|
|
286
|
+
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.log(` ā Error: ${error.message}`);
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Build claim transaction
|
|
295
|
+
*/
|
|
296
|
+
async function buildClaimTransaction(gameId, playerAddress) {
|
|
297
|
+
console.log(`\nšØ Building claim transaction...`);
|
|
298
|
+
console.log(` Game ID: ${gameId}`);
|
|
299
|
+
console.log(` Player: ${playerAddress}`);
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
// Convert gameId to buffer
|
|
303
|
+
// The gameId in the account is a u64, but we store it as a hash of the string gameId
|
|
304
|
+
// We need to figure out the PDA derivation
|
|
305
|
+
|
|
306
|
+
// For now, output instructions for manual claim via API
|
|
307
|
+
console.log(`\n š” To claim, use the API endpoint:`);
|
|
308
|
+
console.log(` POST /api/v1/prod/transaction/build/claim-automatic`);
|
|
309
|
+
console.log(` Body: { "playerAddress": "${playerAddress}", "gameId": "${gameId}" }`);
|
|
310
|
+
console.log(`\n Or use the frontend claim button in My Games`);
|
|
311
|
+
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.error(` ā Error: ${error.message}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Main execution
|
|
319
|
+
*/
|
|
320
|
+
async function main() {
|
|
321
|
+
const args = process.argv.slice(2);
|
|
322
|
+
|
|
323
|
+
if (args.length === 0) {
|
|
324
|
+
console.log('Usage:');
|
|
325
|
+
console.log(' node recover-funds.js <pda1> [pda2] [pda3] ... # Check game PDAs');
|
|
326
|
+
console.log(' node recover-funds.js --claim <gameId> <wallet> # Build claim tx');
|
|
327
|
+
console.log('');
|
|
328
|
+
console.log('Examples:');
|
|
329
|
+
console.log(' node recover-funds.js FrggqLKgxdiTLybXK3fU8qpFG7YPtyh6fP2Y5onYWGhq');
|
|
330
|
+
console.log(' node recover-funds.js --claim sport-123456-abc 7D47yF4qKdQGkT9xNWon...');
|
|
331
|
+
process.exit(0);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (args[0] === '--claim') {
|
|
335
|
+
if (args.length < 3) {
|
|
336
|
+
console.error('ā Usage: node recover-funds.js --claim <gameId> <playerAddress>');
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
await buildClaimTransaction(args[1], args[2]);
|
|
340
|
+
} else {
|
|
341
|
+
// Check each PDA
|
|
342
|
+
const pdas = args.filter(a => !a.startsWith('--'));
|
|
343
|
+
|
|
344
|
+
console.log(`\nš Checking ${pdas.length} game PDA(s)...\n`);
|
|
345
|
+
|
|
346
|
+
for (const pda of pdas) {
|
|
347
|
+
await checkGamePDA(pda);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
console.log('\n' + 'ā'.repeat(60));
|
|
351
|
+
console.log('⨠Done!\n');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
main().catch(console.error);
|
|
356
|
+
|
|
357
|
+
|