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,67 @@
|
|
|
1
|
+
-- Migration 011: Developer API Platform Tables
|
|
2
|
+
-- Supports public developer API with API key auth and commission attribution
|
|
3
|
+
|
|
4
|
+
-- Developer accounts (linked to Solana wallet)
|
|
5
|
+
CREATE TABLE developer_accounts (
|
|
6
|
+
id SERIAL PRIMARY KEY,
|
|
7
|
+
wallet_address VARCHAR(44) UNIQUE NOT NULL,
|
|
8
|
+
display_name VARCHAR(100),
|
|
9
|
+
email VARCHAR(255),
|
|
10
|
+
commission_wallet VARCHAR(44) NOT NULL, -- wallet that receives 1% commission
|
|
11
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
12
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
-- Developer apps (each gets API keys)
|
|
16
|
+
CREATE TABLE developer_apps (
|
|
17
|
+
id SERIAL PRIMARY KEY,
|
|
18
|
+
developer_id INTEGER REFERENCES developer_accounts(id),
|
|
19
|
+
app_name VARCHAR(100) NOT NULL,
|
|
20
|
+
description TEXT,
|
|
21
|
+
website_url VARCHAR(500),
|
|
22
|
+
environment VARCHAR(10) DEFAULT 'sandbox', -- 'sandbox' or 'production'
|
|
23
|
+
status VARCHAR(20) DEFAULT 'active', -- 'active', 'suspended', 'deleted'
|
|
24
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
25
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
-- API keys (sandbox + production per app)
|
|
29
|
+
CREATE TABLE developer_api_keys (
|
|
30
|
+
id SERIAL PRIMARY KEY,
|
|
31
|
+
app_id INTEGER REFERENCES developer_apps(id),
|
|
32
|
+
key_prefix VARCHAR(20) NOT NULL, -- 'dubs_test_' or 'dubs_live_'
|
|
33
|
+
key_hash VARCHAR(64) NOT NULL, -- SHA-256 hash of full key
|
|
34
|
+
key_hint VARCHAR(8) NOT NULL, -- last 4 chars for display
|
|
35
|
+
environment VARCHAR(10) NOT NULL, -- 'sandbox' or 'production'
|
|
36
|
+
is_active BOOLEAN DEFAULT TRUE,
|
|
37
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
38
|
+
last_used_at TIMESTAMPTZ
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
-- Track which games came from which developer app
|
|
42
|
+
CREATE TABLE developer_game_attributions (
|
|
43
|
+
id SERIAL PRIMARY KEY,
|
|
44
|
+
game_id VARCHAR(100) NOT NULL, -- matches games.game_id
|
|
45
|
+
app_id INTEGER REFERENCES developer_apps(id),
|
|
46
|
+
developer_id INTEGER REFERENCES developer_accounts(id),
|
|
47
|
+
commission_wallet VARCHAR(44) NOT NULL,
|
|
48
|
+
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
-- API usage logs for rate limiting and analytics
|
|
52
|
+
CREATE TABLE developer_api_logs (
|
|
53
|
+
id SERIAL PRIMARY KEY,
|
|
54
|
+
app_id INTEGER REFERENCES developer_apps(id),
|
|
55
|
+
endpoint VARCHAR(200) NOT NULL,
|
|
56
|
+
method VARCHAR(10) NOT NULL,
|
|
57
|
+
status_code INTEGER,
|
|
58
|
+
response_time_ms INTEGER,
|
|
59
|
+
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
-- Indexes
|
|
63
|
+
CREATE INDEX idx_api_keys_hash ON developer_api_keys(key_hash);
|
|
64
|
+
CREATE INDEX idx_game_attributions_game ON developer_game_attributions(game_id);
|
|
65
|
+
CREATE INDEX idx_game_attributions_app ON developer_game_attributions(app_id);
|
|
66
|
+
CREATE INDEX idx_api_logs_app ON developer_api_logs(app_id, created_at);
|
|
67
|
+
CREATE INDEX idx_developer_accounts_wallet ON developer_accounts(wallet_address);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
-- Migration 011: Fix keeper tables schema
|
|
2
|
+
-- The tables were created with an older schema that doesn't match keeperStateService.js
|
|
3
|
+
-- These tables only store keeper monitoring data (no user data), safe to recreate.
|
|
4
|
+
|
|
5
|
+
-- Drop old tables
|
|
6
|
+
DROP TABLE IF EXISTS keeper_actions CASCADE;
|
|
7
|
+
DROP TABLE IF EXISTS keeper_health CASCADE;
|
|
8
|
+
DROP TABLE IF EXISTS keeper_rounds CASCADE;
|
|
9
|
+
|
|
10
|
+
-- Drop old views if they exist
|
|
11
|
+
DROP VIEW IF EXISTS stuck_rounds CASCADE;
|
|
12
|
+
DROP VIEW IF EXISTS keeper_health_summary CASCADE;
|
|
13
|
+
|
|
14
|
+
-- keeper_rounds: tracks round lifecycle
|
|
15
|
+
CREATE TABLE keeper_rounds (
|
|
16
|
+
id SERIAL PRIMARY KEY,
|
|
17
|
+
round_id INTEGER NOT NULL UNIQUE,
|
|
18
|
+
status VARCHAR(50) NOT NULL DEFAULT 'open',
|
|
19
|
+
entry_count INTEGER DEFAULT 0,
|
|
20
|
+
total_pot VARCHAR(50) DEFAULT '0',
|
|
21
|
+
winner_pubkey VARCHAR(100),
|
|
22
|
+
win_amount VARCHAR(50),
|
|
23
|
+
locked_at TIMESTAMP,
|
|
24
|
+
revealed_at TIMESTAMP,
|
|
25
|
+
resolved_at TIMESTAMP,
|
|
26
|
+
reset_at TIMESTAMP,
|
|
27
|
+
retry_count INTEGER DEFAULT 0,
|
|
28
|
+
last_error TEXT,
|
|
29
|
+
last_attempt_at TIMESTAMP,
|
|
30
|
+
lock_signature VARCHAR(120),
|
|
31
|
+
reveal_signature VARCHAR(120),
|
|
32
|
+
resolve_signature VARCHAR(120),
|
|
33
|
+
reset_signature VARCHAR(120),
|
|
34
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
35
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
CREATE INDEX idx_keeper_rounds_status ON keeper_rounds(status);
|
|
39
|
+
|
|
40
|
+
-- keeper_actions: action log for debugging
|
|
41
|
+
CREATE TABLE keeper_actions (
|
|
42
|
+
id SERIAL PRIMARY KEY,
|
|
43
|
+
round_id INTEGER,
|
|
44
|
+
action VARCHAR(50) NOT NULL,
|
|
45
|
+
success BOOLEAN NOT NULL DEFAULT false,
|
|
46
|
+
error_message TEXT,
|
|
47
|
+
signature VARCHAR(120),
|
|
48
|
+
duration_ms INTEGER,
|
|
49
|
+
timestamp TIMESTAMP DEFAULT NOW()
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
CREATE INDEX idx_keeper_actions_round ON keeper_actions(round_id);
|
|
53
|
+
CREATE INDEX idx_keeper_actions_timestamp ON keeper_actions(timestamp);
|
|
54
|
+
|
|
55
|
+
-- keeper_health: periodic health snapshots
|
|
56
|
+
CREATE TABLE keeper_health (
|
|
57
|
+
id SERIAL PRIMARY KEY,
|
|
58
|
+
rounds_completed INTEGER DEFAULT 0,
|
|
59
|
+
consecutive_failures INTEGER DEFAULT 0,
|
|
60
|
+
last_success_round INTEGER DEFAULT 0,
|
|
61
|
+
last_error TEXT,
|
|
62
|
+
uptime_seconds INTEGER DEFAULT 0,
|
|
63
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
-- View: stuck_rounds (used by recoverStuckRounds)
|
|
67
|
+
CREATE VIEW stuck_rounds AS
|
|
68
|
+
SELECT
|
|
69
|
+
round_id,
|
|
70
|
+
status,
|
|
71
|
+
retry_count,
|
|
72
|
+
last_error,
|
|
73
|
+
EXTRACT(EPOCH FROM (NOW() - COALESCE(last_attempt_at, created_at))) AS seconds_stuck
|
|
74
|
+
FROM keeper_rounds
|
|
75
|
+
WHERE status IN ('locking', 'locked', 'revealing', 'revealed', 'resolving', 'resetting')
|
|
76
|
+
AND COALESCE(last_attempt_at, created_at) < NOW() - INTERVAL '5 minutes';
|
|
77
|
+
|
|
78
|
+
-- View: keeper_health_summary (used by getHealthSummary)
|
|
79
|
+
CREATE VIEW keeper_health_summary AS
|
|
80
|
+
SELECT
|
|
81
|
+
(SELECT COUNT(*) FROM keeper_rounds WHERE status = 'resolved') AS total_rounds_completed,
|
|
82
|
+
(SELECT MAX(round_id) FROM keeper_rounds WHERE status = 'resolved') AS last_resolved_round,
|
|
83
|
+
(SELECT COUNT(*) FROM keeper_rounds WHERE status NOT IN ('resolved', 'open')) AS stuck_rounds_count,
|
|
84
|
+
(SELECT created_at FROM keeper_health ORDER BY id DESC LIMIT 1) AS last_health_check,
|
|
85
|
+
(SELECT uptime_seconds FROM keeper_health ORDER BY id DESC LIMIT 1) AS uptime_seconds;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- Migration 012: Developer Webhooks
|
|
2
|
+
-- Outbound webhook system for notifying developers when game events occur
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS developer_webhooks (
|
|
5
|
+
id SERIAL PRIMARY KEY,
|
|
6
|
+
app_id INTEGER NOT NULL REFERENCES developer_apps(id) ON DELETE CASCADE,
|
|
7
|
+
url VARCHAR(500) NOT NULL,
|
|
8
|
+
secret VARCHAR(64) NOT NULL,
|
|
9
|
+
events TEXT[] NOT NULL DEFAULT '{}',
|
|
10
|
+
is_active BOOLEAN DEFAULT TRUE,
|
|
11
|
+
description VARCHAR(200),
|
|
12
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
13
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_webhooks_app ON developer_webhooks(app_id);
|
|
17
|
+
|
|
18
|
+
CREATE TABLE IF NOT EXISTS developer_webhook_logs (
|
|
19
|
+
id SERIAL PRIMARY KEY,
|
|
20
|
+
webhook_id INTEGER NOT NULL REFERENCES developer_webhooks(id) ON DELETE CASCADE,
|
|
21
|
+
event VARCHAR(50) NOT NULL,
|
|
22
|
+
payload JSONB NOT NULL,
|
|
23
|
+
status_code INTEGER,
|
|
24
|
+
response_body TEXT,
|
|
25
|
+
attempts INTEGER DEFAULT 1,
|
|
26
|
+
success BOOLEAN DEFAULT FALSE,
|
|
27
|
+
error TEXT,
|
|
28
|
+
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_webhook_logs_webhook ON developer_webhook_logs(webhook_id, created_at DESC);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Migration 013: Add network_mode to developer_apps
|
|
2
|
+
-- Controls game visibility: 'open' (shared pool) or 'private' (app-scoped)
|
|
3
|
+
-- Open apps share games across the Dubs network; private apps are closed-loop.
|
|
4
|
+
|
|
5
|
+
ALTER TABLE developer_apps
|
|
6
|
+
ADD COLUMN IF NOT EXISTS network_mode VARCHAR(10) DEFAULT 'open';
|
|
7
|
+
|
|
8
|
+
-- Add check constraint separately (IF NOT EXISTS not supported for constraints)
|
|
9
|
+
DO $$
|
|
10
|
+
BEGIN
|
|
11
|
+
IF NOT EXISTS (
|
|
12
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'developer_apps_network_mode_check'
|
|
13
|
+
) THEN
|
|
14
|
+
ALTER TABLE developer_apps
|
|
15
|
+
ADD CONSTRAINT developer_apps_network_mode_check
|
|
16
|
+
CHECK (network_mode IN ('open', 'private'));
|
|
17
|
+
END IF;
|
|
18
|
+
END $$;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- Migration 014: Developer App Users Junction Table
|
|
2
|
+
-- Tracks which users authenticated through which developer app.
|
|
3
|
+
-- Enables developers to query their app's users via GET /v1/users.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS developer_app_users (
|
|
6
|
+
developer_app_id INTEGER NOT NULL REFERENCES developer_apps(id) ON DELETE CASCADE,
|
|
7
|
+
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
8
|
+
first_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
9
|
+
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
10
|
+
PRIMARY KEY (developer_app_id, user_id)
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE INDEX IF NOT EXISTS idx_developer_app_users_app ON developer_app_users(developer_app_id);
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_developer_app_users_user ON developer_app_users(user_id);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_developer_app_users_last_seen ON developer_app_users(developer_app_id, last_seen_at DESC);
|
|
16
|
+
|
|
17
|
+
COMMENT ON TABLE developer_app_users IS 'Junction table tracking which users authenticated through which developer app';
|
|
18
|
+
COMMENT ON COLUMN developer_app_users.first_seen_at IS 'When the user first authenticated via this app';
|
|
19
|
+
COMMENT ON COLUMN developer_app_users.last_seen_at IS 'Updated on every authentication through this app';
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
-- ============================================
|
|
2
|
+
-- Migration 018: Create Pick'em Tables
|
|
3
|
+
-- UFC Pick'em: Pick winners for every fight on a card
|
|
4
|
+
-- Winner-takes-all: top scorer(s) split the pool equally
|
|
5
|
+
-- ============================================
|
|
6
|
+
-- Run with: psql -d dubs_db -f scripts/migrations/018_create_pickem_tables.sql
|
|
7
|
+
|
|
8
|
+
-- ============================================
|
|
9
|
+
-- 1. PICKEM POOLS (one per UFC event/card)
|
|
10
|
+
-- ============================================
|
|
11
|
+
CREATE TABLE IF NOT EXISTS pickem_pools (
|
|
12
|
+
id SERIAL PRIMARY KEY,
|
|
13
|
+
name VARCHAR(255) NOT NULL,
|
|
14
|
+
espn_event_id VARCHAR(100),
|
|
15
|
+
event_date DATE NOT NULL,
|
|
16
|
+
buy_in_lamports BIGINT NOT NULL DEFAULT 100000000,
|
|
17
|
+
lock_time TIMESTAMP NOT NULL,
|
|
18
|
+
status VARCHAR(20) DEFAULT 'open'
|
|
19
|
+
CHECK (status IN ('open', 'locked', 'resolving', 'complete', 'cancelled')),
|
|
20
|
+
solana_game_id VARCHAR(100),
|
|
21
|
+
solana_game_address VARCHAR(44),
|
|
22
|
+
total_entries INTEGER DEFAULT 0,
|
|
23
|
+
created_by VARCHAR(44),
|
|
24
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
25
|
+
updated_at TIMESTAMP DEFAULT NOW()
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_pools_status ON pickem_pools(status);
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_pools_event_date ON pickem_pools(event_date);
|
|
30
|
+
|
|
31
|
+
-- ============================================
|
|
32
|
+
-- 2. PICKEM FIGHTS (fights within a pool/card)
|
|
33
|
+
-- ============================================
|
|
34
|
+
CREATE TABLE IF NOT EXISTS pickem_fights (
|
|
35
|
+
id SERIAL PRIMARY KEY,
|
|
36
|
+
pool_id INTEGER NOT NULL REFERENCES pickem_pools(id) ON DELETE CASCADE,
|
|
37
|
+
espn_competition_id VARCHAR(100) NOT NULL,
|
|
38
|
+
fight_order INTEGER NOT NULL,
|
|
39
|
+
fighter_a_name VARCHAR(100) NOT NULL,
|
|
40
|
+
fighter_a_headshot TEXT,
|
|
41
|
+
fighter_a_country VARCHAR(100),
|
|
42
|
+
fighter_a_record VARCHAR(20),
|
|
43
|
+
fighter_b_name VARCHAR(100) NOT NULL,
|
|
44
|
+
fighter_b_headshot TEXT,
|
|
45
|
+
fighter_b_country VARCHAR(100),
|
|
46
|
+
fighter_b_record VARCHAR(20),
|
|
47
|
+
weight_class VARCHAR(50),
|
|
48
|
+
winner VARCHAR(1) CHECK (winner IN ('a', 'b')),
|
|
49
|
+
method VARCHAR(100),
|
|
50
|
+
status VARCHAR(20) DEFAULT 'scheduled'
|
|
51
|
+
CHECK (status IN ('scheduled', 'live', 'final', 'cancelled', 'no_contest')),
|
|
52
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
53
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
54
|
+
UNIQUE(pool_id, espn_competition_id)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_fights_pool ON pickem_fights(pool_id);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_fights_status ON pickem_fights(status);
|
|
59
|
+
|
|
60
|
+
-- ============================================
|
|
61
|
+
-- 3. PICKEM ENTRIES (user participation)
|
|
62
|
+
-- ============================================
|
|
63
|
+
CREATE TABLE IF NOT EXISTS pickem_entries (
|
|
64
|
+
id SERIAL PRIMARY KEY,
|
|
65
|
+
pool_id INTEGER NOT NULL REFERENCES pickem_pools(id) ON DELETE CASCADE,
|
|
66
|
+
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
67
|
+
wallet_address VARCHAR(44) NOT NULL,
|
|
68
|
+
entry_tx_signature VARCHAR(100),
|
|
69
|
+
score INTEGER DEFAULT 0,
|
|
70
|
+
rank INTEGER,
|
|
71
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
72
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
73
|
+
UNIQUE(pool_id, user_id)
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_entries_pool ON pickem_entries(pool_id);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_entries_wallet ON pickem_entries(wallet_address);
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_entries_score ON pickem_entries(pool_id, score DESC);
|
|
79
|
+
|
|
80
|
+
-- ============================================
|
|
81
|
+
-- 4. PICKEM PICKS (user selections per fight)
|
|
82
|
+
-- ============================================
|
|
83
|
+
CREATE TABLE IF NOT EXISTS pickem_picks (
|
|
84
|
+
id SERIAL PRIMARY KEY,
|
|
85
|
+
entry_id INTEGER NOT NULL REFERENCES pickem_entries(id) ON DELETE CASCADE,
|
|
86
|
+
fight_id INTEGER NOT NULL REFERENCES pickem_fights(id) ON DELETE CASCADE,
|
|
87
|
+
pick VARCHAR(1) NOT NULL CHECK (pick IN ('a', 'b')),
|
|
88
|
+
is_correct BOOLEAN,
|
|
89
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
90
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
91
|
+
UNIQUE(entry_id, fight_id)
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_picks_entry ON pickem_picks(entry_id);
|
|
95
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_picks_fight ON pickem_picks(fight_id);
|
|
96
|
+
|
|
97
|
+
-- ============================================
|
|
98
|
+
-- 5. PICKEM PAYOUTS (winnings tracking)
|
|
99
|
+
-- ============================================
|
|
100
|
+
CREATE TABLE IF NOT EXISTS pickem_payouts (
|
|
101
|
+
id SERIAL PRIMARY KEY,
|
|
102
|
+
pool_id INTEGER NOT NULL REFERENCES pickem_pools(id) ON DELETE CASCADE,
|
|
103
|
+
entry_id INTEGER NOT NULL REFERENCES pickem_entries(id) ON DELETE CASCADE,
|
|
104
|
+
wallet_address VARCHAR(44) NOT NULL,
|
|
105
|
+
amount_lamports BIGINT NOT NULL,
|
|
106
|
+
payout_tx_signature VARCHAR(100),
|
|
107
|
+
status VARCHAR(20) DEFAULT 'pending'
|
|
108
|
+
CHECK (status IN ('pending', 'processing', 'completed', 'failed')),
|
|
109
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
110
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
111
|
+
UNIQUE(pool_id, entry_id)
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_payouts_pool ON pickem_payouts(pool_id);
|
|
115
|
+
CREATE INDEX IF NOT EXISTS idx_pickem_payouts_status ON pickem_payouts(status);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- Expo push notification tokens for mobile apps
|
|
2
|
+
CREATE TABLE IF NOT EXISTS expo_push_tokens (
|
|
3
|
+
id SERIAL PRIMARY KEY,
|
|
4
|
+
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
5
|
+
token TEXT NOT NULL,
|
|
6
|
+
developer_app_id INTEGER REFERENCES developer_apps(id) ON DELETE CASCADE,
|
|
7
|
+
platform VARCHAR(10) NOT NULL,
|
|
8
|
+
device_name VARCHAR(255),
|
|
9
|
+
active BOOLEAN DEFAULT true,
|
|
10
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
11
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
12
|
+
UNIQUE(user_id, token)
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_expo_push_tokens_user_active
|
|
16
|
+
ON expo_push_tokens(user_id, active) WHERE active = true;
|
|
17
|
+
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_expo_push_tokens_app
|
|
19
|
+
ON expo_push_tokens(developer_app_id) WHERE active = true;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
-- =====================================================
|
|
2
|
+
-- š¢ What's New Feature - Database Schema
|
|
3
|
+
--
|
|
4
|
+
-- Allows admin to post feature updates with GIFs
|
|
5
|
+
-- Users can see/dismiss posts (similar to notifications)
|
|
6
|
+
-- =====================================================
|
|
7
|
+
|
|
8
|
+
-- Table for storing What's New posts
|
|
9
|
+
CREATE TABLE IF NOT EXISTS whats_new_posts (
|
|
10
|
+
id SERIAL PRIMARY KEY,
|
|
11
|
+
|
|
12
|
+
-- Post content
|
|
13
|
+
title VARCHAR(200) NOT NULL,
|
|
14
|
+
content TEXT NOT NULL, -- Markdown-style content
|
|
15
|
+
gif_url TEXT, -- Optional GIF URL to showcase feature
|
|
16
|
+
|
|
17
|
+
-- Categorization
|
|
18
|
+
category VARCHAR(50) DEFAULT 'feature', -- feature, improvement, bugfix, announcement
|
|
19
|
+
|
|
20
|
+
-- Versioning
|
|
21
|
+
version VARCHAR(20), -- Optional app version (e.g., "1.2.0")
|
|
22
|
+
|
|
23
|
+
-- Targeting (future use - could target specific user segments)
|
|
24
|
+
target_all BOOLEAN DEFAULT TRUE,
|
|
25
|
+
|
|
26
|
+
-- Status
|
|
27
|
+
is_published BOOLEAN DEFAULT TRUE,
|
|
28
|
+
is_pinned BOOLEAN DEFAULT FALSE, -- Pinned posts show at top
|
|
29
|
+
|
|
30
|
+
-- Audit
|
|
31
|
+
created_by VARCHAR(64) NOT NULL, -- Admin wallet address
|
|
32
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
33
|
+
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
-- Table for tracking which users have seen/dismissed which posts
|
|
37
|
+
CREATE TABLE IF NOT EXISTS user_whats_new_reads (
|
|
38
|
+
id SERIAL PRIMARY KEY,
|
|
39
|
+
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
40
|
+
post_id INTEGER NOT NULL REFERENCES whats_new_posts(id) ON DELETE CASCADE,
|
|
41
|
+
read_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
42
|
+
|
|
43
|
+
-- Prevent duplicates
|
|
44
|
+
UNIQUE(user_id, post_id)
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
-- Indexes for performance
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_whats_new_posts_published
|
|
49
|
+
ON whats_new_posts(is_published, created_at DESC);
|
|
50
|
+
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_whats_new_posts_pinned
|
|
52
|
+
ON whats_new_posts(is_pinned, created_at DESC);
|
|
53
|
+
|
|
54
|
+
CREATE INDEX IF NOT EXISTS idx_user_whats_new_reads_user
|
|
55
|
+
ON user_whats_new_reads(user_id);
|
|
56
|
+
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_user_whats_new_reads_post
|
|
58
|
+
ON user_whats_new_reads(post_id);
|
|
59
|
+
|
|
60
|
+
-- Function to update updated_at timestamp
|
|
61
|
+
CREATE OR REPLACE FUNCTION update_whats_new_updated_at()
|
|
62
|
+
RETURNS TRIGGER AS $$
|
|
63
|
+
BEGIN
|
|
64
|
+
NEW.updated_at = NOW();
|
|
65
|
+
RETURN NEW;
|
|
66
|
+
END;
|
|
67
|
+
$$ LANGUAGE plpgsql;
|
|
68
|
+
|
|
69
|
+
-- Trigger to auto-update updated_at
|
|
70
|
+
DROP TRIGGER IF EXISTS whats_new_posts_updated_at ON whats_new_posts;
|
|
71
|
+
CREATE TRIGGER whats_new_posts_updated_at
|
|
72
|
+
BEFORE UPDATE ON whats_new_posts
|
|
73
|
+
FOR EACH ROW
|
|
74
|
+
EXECUTE FUNCTION update_whats_new_updated_at();
|
|
75
|
+
|
|
76
|
+
-- =====================================================
|
|
77
|
+
-- Sample data (optional - comment out in production)
|
|
78
|
+
-- =====================================================
|
|
79
|
+
-- INSERT INTO whats_new_posts (title, content, gif_url, category, created_by)
|
|
80
|
+
-- VALUES (
|
|
81
|
+
-- 'š Welcome to What''s New!',
|
|
82
|
+
-- 'We''ll keep you updated on new features, improvements, and announcements here. Check back often!',
|
|
83
|
+
-- NULL,
|
|
84
|
+
-- 'announcement',
|
|
85
|
+
-- 'DU4CHEHUJ2EeezAXyfyi8vLB7dmXKq41myKnA5DZ9Mru'
|
|
86
|
+
-- );
|
|
87
|
+
|
|
88
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
-- =====================================================
|
|
2
|
+
-- Drop Live Games Tables Migration
|
|
3
|
+
-- =====================================================
|
|
4
|
+
--
|
|
5
|
+
-- This migration removes the LiveGameIngestion system tables
|
|
6
|
+
-- that are no longer used.
|
|
7
|
+
--
|
|
8
|
+
-- Run this on production with:
|
|
9
|
+
-- heroku pg:psql -a dubs-server-prod < scripts/migrations/drop_live_games_tables.sql
|
|
10
|
+
--
|
|
11
|
+
|
|
12
|
+
-- Drop views first
|
|
13
|
+
DROP VIEW IF EXISTS v_live_games_with_stats CASCADE;
|
|
14
|
+
DROP VIEW IF EXISTS v_recent_plays CASCADE;
|
|
15
|
+
|
|
16
|
+
-- Drop functions
|
|
17
|
+
DROP FUNCTION IF EXISTS get_live_games_count() CASCADE;
|
|
18
|
+
DROP FUNCTION IF EXISTS get_game_progress_percent(INTEGER) CASCADE;
|
|
19
|
+
DROP FUNCTION IF EXISTS archive_old_games() CASCADE;
|
|
20
|
+
DROP FUNCTION IF EXISTS cleanup_inactive_subscriptions() CASCADE;
|
|
21
|
+
DROP FUNCTION IF EXISTS update_live_games_updated_at() CASCADE;
|
|
22
|
+
|
|
23
|
+
-- Drop tables (in dependency order)
|
|
24
|
+
DROP TABLE IF EXISTS live_game_polling_log CASCADE;
|
|
25
|
+
DROP TABLE IF EXISTS live_game_subscriptions CASCADE;
|
|
26
|
+
DROP TABLE IF EXISTS live_game_stats CASCADE;
|
|
27
|
+
DROP TABLE IF EXISTS live_game_plays CASCADE;
|
|
28
|
+
DROP TABLE IF EXISTS live_games CASCADE;
|
|
29
|
+
|
|
30
|
+
-- Verify tables are dropped
|
|
31
|
+
SELECT 'Remaining live_game tables:' AS status;
|
|
32
|
+
SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND tablename LIKE 'live_game%';
|
|
33
|
+
|
|
34
|
+
SELECT 'Migration complete - LiveGameIngestion tables dropped' AS status;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* š° Open New Jackpot Round
|
|
5
|
+
*
|
|
6
|
+
* Starts a new round (anyone can do this - permissionless keeper)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { Connection, Keypair, Transaction } = require('@solana/web3.js');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const axios = require('axios');
|
|
13
|
+
|
|
14
|
+
const RPC_URL = process.env.SOLANA_NETWORK || 'https://api.devnet.solana.com';
|
|
15
|
+
const API_BASE = 'http://localhost:3001';
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
console.log('š° Opening New Jackpot Round\n');
|
|
19
|
+
|
|
20
|
+
// Load keeper wallet (oracle wallet or main wallet)
|
|
21
|
+
const oracleKeyPath = path.join(__dirname, '..', 'wallets', 'jackpot_oracle.json');
|
|
22
|
+
let keeperWallet;
|
|
23
|
+
|
|
24
|
+
if (fs.existsSync(oracleKeyPath)) {
|
|
25
|
+
const secretKey = JSON.parse(fs.readFileSync(oracleKeyPath, 'utf-8'));
|
|
26
|
+
keeperWallet = Keypair.fromSecretKey(Uint8Array.from(secretKey));
|
|
27
|
+
} else {
|
|
28
|
+
const mainWalletPath = path.join(require('os').homedir(), '.config/solana/id.json');
|
|
29
|
+
const secretKey = JSON.parse(fs.readFileSync(mainWalletPath, 'utf-8'));
|
|
30
|
+
keeperWallet = Keypair.fromSecretKey(Uint8Array.from(secretKey));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log('š¤ Keeper:', keeperWallet.publicKey.toString());
|
|
34
|
+
|
|
35
|
+
const connection = new Connection(RPC_URL, 'confirmed');
|
|
36
|
+
|
|
37
|
+
// Check balance
|
|
38
|
+
const balance = await connection.getBalance(keeperWallet.publicKey);
|
|
39
|
+
console.log('š° Balance:', (balance / 1e9).toFixed(4), 'SOL');
|
|
40
|
+
|
|
41
|
+
// Build transaction
|
|
42
|
+
console.log('\nšØ Building open round transaction...');
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const { data } = await axios.post(`${API_BASE}/jackpot/build/open-round`, {
|
|
46
|
+
keeperAddress: keeperWallet.publicKey.toString(),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
console.log('ā
Transaction built');
|
|
50
|
+
console.log(' Round ID:', data.roundId);
|
|
51
|
+
console.log(' Round PDA:', data.roundPda);
|
|
52
|
+
|
|
53
|
+
// Get fresh blockhash and sign
|
|
54
|
+
const tx = Transaction.from(Buffer.from(data.transaction, 'base64'));
|
|
55
|
+
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
|
|
56
|
+
tx.feePayer = keeperWallet.publicKey;
|
|
57
|
+
tx.sign(keeperWallet);
|
|
58
|
+
|
|
59
|
+
console.log('\nš¤ Opening round...');
|
|
60
|
+
const signature = await connection.sendRawTransaction(tx.serialize(), {
|
|
61
|
+
skipPreflight: true, // Skip simulation - send directly
|
|
62
|
+
maxRetries: 3,
|
|
63
|
+
});
|
|
64
|
+
console.log(' Signature:', signature);
|
|
65
|
+
|
|
66
|
+
console.log('\nā³ Confirming...');
|
|
67
|
+
await connection.confirmTransaction(signature);
|
|
68
|
+
|
|
69
|
+
console.log('\nš ROUND OPENED!');
|
|
70
|
+
console.log('\nā
Round', data.roundId, 'is now active!');
|
|
71
|
+
console.log('ā±ļø Duration: ~1 minute');
|
|
72
|
+
console.log('š® Players can now place bets!');
|
|
73
|
+
console.log('š» Frontend: http://localhost:3000');
|
|
74
|
+
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error('\nā Error:', error.message);
|
|
77
|
+
if (error.response) {
|
|
78
|
+
console.error(' API Error:', error.response.data);
|
|
79
|
+
}
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
main().catch(console.error);
|
|
85
|
+
|