Betting Production Deploy (Cloudflare + Railway)
This is the recommended production topology for the betting stack in this repo:- Frontend (
/packages/gold-betting-demo/app): Cloudflare Pages - Betting API (
/packages/gold-betting-demo/keeper): Railway - Live duel/stream source (
/packages/serveror Vast duel stack): separate upstream that the keeper polls - DDoS/WAF/edge cache: Cloudflare proxy in front of the betting API
- Contracts/state: Solana + EVM (configured by env vars below, proxied server-side)
Deployment Metadata
Centralized Contract Addresses: All contract addresses and program IDs are now managed in a single source of truth:packages/gold-betting-demo/deployments/contracts.json- Shared deployment manifestpackages/gold-betting-demo/deployments/index.ts- Typed deployment configuration with runtime validation
- Frontend app defaults
- Keeper API defaults
- Local development scripts
- EVM deploy receipt syncing
- Preflight validation checks
packages/evm-contracts/deployments/<network>.json containing:
- Network name and chain ID
- Deployer address
- Contract addresses (GoldClob, GOLD token)
- Treasury and market maker addresses
- Deployment transaction hash
- Deployment timestamp
contracts.json manifest after successful deployment.
0) Preflight Checks
Before deploying to any network, run preflight validation to ensure all deployment metadata is consistent:- Solana program keypairs match deployment manifest addresses
- Anchor IDL files match deployment manifest addresses
- App and keeper IDL files are in sync with Anchor build output
- EVM deployment environment variables are configured
- EVM RPC URLs are available (either configured or using Hardhat fallbacks)
- Contract addresses are present in deployment manifest
1) Deploy Solana Programs
Deploy all three Solana betting programs using the checked-in program keypairs:fight_oracle- Match lifecycle and winner postinggold_clob_market- GOLD CLOB market for binary prediction tradinggold_perps_market- Perpetual futures market for agent skill ratings
- Solana CLI installed (
solana --version) - Deployer wallet with sufficient SOL (~4+ SOL for all three programs)
- Wallet path:
$ANCHOR_WALLET,~/.config/solana/hyperscape-keys/deployer.json, or~/.config/solana/id.json
- Builds Anchor workspace (unless
SKIP_BUILD=1) - Verifies program keypairs and binaries exist
- Deploys each program using
solana program deploy - Verifies deployment with
solana program show
2) Deploy EVM Contracts
Deploy GoldClob contracts to EVM networks:PRIVATE_KEY- Deployer private key (required)TREASURY_ADDRESS- Treasury address for fee collection (required for mainnet)MARKET_MAKER_ADDRESS- Market maker address for fee collection (required for mainnet)GOLD_TOKEN_ADDRESS- GOLD token address (optional, recorded in deployment receipt)BSC_RPC_URL/BASE_RPC_URL- RPC endpoints (optional, uses Hardhat fallbacks if not set)
- Mainnet deployments (BSC, Base) require explicit
TREASURY_ADDRESSandMARKET_MAKER_ADDRESS - Deployment fails if these are not set (prevents accidental use of deployer address)
- Validates treasury and market maker addresses
- Deploys GoldClob contract
- Writes deployment receipt to
packages/evm-contracts/deployments/<network>.json - Updates central manifest at
packages/gold-betting-demo/deployments/contracts.json
typed-contracts.ts:
3) Deploy the betting keeper to Railway
From repo root, deploy the keeper service path:packages/gold-betting-demo/keeper/railway.json.
Set these Railway variables at minimum:
NODE_ENV=productionPORT=8080(or let Railway inject its port if you proxy through the service domain)STREAM_STATE_SOURCE_URL=https://your-stream-source.example/api/streaming/stateSTREAM_STATE_SOURCE_BEARER_TOKEN=...if the upstream streaming state is protectedARENA_EXTERNAL_BET_WRITE_KEY=...STREAM_PUBLISH_KEY=...if you use/api/streaming/state/publishSOLANA_CLUSTER=mainnet-betaSOLANA_RPC_URL=...BSC_RPC_URL=...BSC_GOLD_CLOB_ADDRESS=...BASE_RPC_URL=...BASE_GOLD_CLOB_ADDRESS=...BIRDEYE_API_KEY=...if token-price proxying is enabled
- The keeper defaults to a local SQLite file (
KEEPER_DB_PATH=./keeper.sqlite). - On Railway that file is ephemeral unless you attach a persistent volume or move the keeper state to an external database.
- Do not treat points history, referrals, or oracle history as durable unless persistence is configured explicitly.
- The keeper serves the Pages app’s read/write betting APIs. It is not the same process as the Hyperscape duel server.
- The keeper also proxies Solana and EVM JSON-RPC for the public app. Keep provider-keyed RPC URLs on Railway, not in Cloudflare Pages build vars.
- The keeper will return boot fallback duel data until
STREAM_STATE_SOURCE_URLis set and the upstream duel server responds. - The autonomous keeper bot also needs a funded signer wallet on Solana to create/resolve markets in production.
4) Deploy the live duel server / stream source
This can be the Railwayhyperscape service or the Vast.ai duel stack. It must expose:
/api/streaming/state/api/streaming/duel-context/api/streaming/rtmp/status/live/stream.m3u8
5) Put the betting API behind Cloudflare
- Create
api.yourdomain.comin Cloudflare DNS and point it to the keeper Railway target. - Enable Cloudflare proxy (orange cloud) for
api.yourdomain.com. - Add WAF rate-limit rules:
POST /api/arena/bet/record-externalPOST /api/arena/deposit/ingest/api/arena/points/*
- Keep the direct Railway URL private if you introduce a public API domain.
6) Deploy betting frontend to Cloudflare Pages
Project root:packages/gold-betting-demo/app
- Build command:
bun install && bun run build --mode mainnet-beta - Output directory:
dist
VITE_GAME_API_URL=https://api.yourdomain.comVITE_GAME_WS_URL=wss://api.yourdomain.com/wsif the keeper exposes websocket features you useVITE_SOLANA_CLUSTER=mainnet-beta(or testnet/devnet)VITE_USE_GAME_RPC_PROXY=trueVITE_USE_GAME_EVM_RPC_PROXY=trueVITE_BSC_GOLD_CLOB_ADDRESS/VITE_BASE_GOLD_CLOB_ADDRESSVITE_BSC_GOLD_TOKEN_ADDRESS/VITE_BASE_GOLD_TOKEN_ADDRESSVITE_STREAM_SOURCES=https://your-hls-or-embed-source,...
VITE_*RPC_URL variable for production builds. The betting app build fails intentionally if a public RPC URL looks like a Helius / Alchemy / Infura / QuickNode / dRPC secret endpoint.
Cloudflare Pages headers/SPA rules are already added in:
packages/gold-betting-demo/app/public/_headerspackages/gold-betting-demo/app/public/_redirects
build-info.jsonis emitted intodist/on every build and should be served withCache-Control: no-store.
7) Verify production
Health:https://api.yourdomain.com/statushttps://bet.yourdomain.comhttps://api.yourdomain.com/api/streaming/statehttps://api.yourdomain.com/api/streaming/duel-contexthttps://api.yourdomain.com/api/perps/marketshttps://api.yourdomain.com/api/proxy/evm/rpc?chain=bsc(POST JSON-RPC smoke test)https://bet.yourdomain.com/build-info.json
8) Security notes
- Do not expose
ARENA_EXTERNAL_BET_WRITE_KEYin public frontend env vars. - Do not ship provider-keyed RPC URLs in public frontend env vars. Keep them on Railway and let the keeper proxy them.
- Rotate all secrets before production if they were ever committed/shared.
- Keep
DISABLE_RATE_LIMITunset in production.
CI/CD Workflows
Betting CI (betting-ci.yml)
Runs on every push to betting stack packages:
- Type checking (TypeScript)
- Linting (ESLint)
- Unit tests (Vitest)
- Keeper smoke test (verifies keeper boots and serves health endpoint)
- Environment sanitization (checks for leaked secrets in env files)
- Production build verification (ensures build succeeds with production config)
Keeper Deployment (deploy-betting-keeper.yml)
Automated deployment workflow:
- Run full test suite
- Keeper smoke test (verify service boots)
- Deploy to Railway via
railway up - Endpoint verification (health check on deployed service)
- Removed Railway status probe for improved reliability
- Simplified deployment flow (removed redundant health checks)
Pages Deployment (deploy-betting-pages.yml)
Automated frontend deployment:
- Build production bundle (
--mode mainnet-beta) - Dist hygiene checks (verify no leaked secrets in build output)
- Deploy to Cloudflare Pages
- Verify
build-info.jsonis accessible
Perps Market Lifecycle Management
Market States (commits 43911165, 8322b3f, 1043f0a): The perpetual futures markets support three lifecycle states:-
ACTIVE: Normal trading with live oracle updates
- New positions allowed
- Position increases/decreases allowed
- Requires fresh oracle updates (within
max_oracle_staleness_seconds) - Funding rate drifts based on market skew
-
CLOSE_ONLY: Model deprecated, reduce-only mode
- New positions blocked
- Position increases blocked
- Position reductions and closes allowed
- Settlement price frozen (no oracle updates required)
- Funding rate frozen
-
ARCHIVED: Market fully wound down
- All trading blocked
- Requires zero open interest and zero open positions
- Can be reactivated to ACTIVE if model returns
- Trade fees: Split between treasury and market maker (configurable BPS)
- Claim fees: Route to market maker
- Fee recycling: Market maker can recycle fees into isolated insurance reserves
- Fee withdrawal: Treasury and market maker can withdraw their fee balances
modify_position instruction now accepts an acceptable_price parameter:
- Longs: execution price must be ≤ acceptable price
- Shorts: execution price must be ≥ acceptable price
- Set to 0 to disable slippage check
Security Hardening
Build-Time Secret Detection (commit 43911165): The build process fails if provider-keyed RPC URLs are detected in public environment variables:- Helius (
helius-rpc.com) - Alchemy (
alchemy.com) - Infura (
infura.io) - QuickNode (
quiknode.pro) - dRPC (
drpc.org)
https://api.yourdomain.com/api/proxy/solana/rpc(Solana)https://api.yourdomain.com/api/proxy/evm/rpc?chain=bsc(EVM)
- Environment files (
.env,.env.example,.env.mainnet, etc.) - Production build output (
dist/) - Fails build if secrets detected
Deployment Process Improvements
Keeper Workflow Stabilization (commits 46cd28e, 66a7b23):- Removed Railway status probe (was causing false failures)
- Simplified health check flow
- Improved deployment reliability
- Fixed Solana compatibility issues with noble ed25519 imports
- Ensures consistent cryptographic library usage across betting stack
- Added polyfill shims for betting stack tests in CI
- Prevents test failures in headless environments
Troubleshooting
Keeper fails to deploy: Check Railway logs for:- Missing environment variables (SOLANA_RPC_URL, BSC_RPC_URL, etc.)
- Database connection errors
- Port binding issues
VITE_* environment variables. Use RPC proxying instead:
STREAM_STATE_SOURCE_URL is set and the upstream duel server is responding:
- Attach Railway persistent volume and set
KEEPER_DB_PATH=/mnt/data/keeper.sqlite - Or migrate to external database (PostgreSQL, MySQL, etc.)