Skip to content

Go-live checklist ​

Everything that must be true before real money moves, gathered from the design documents (docs/non-custodial.md, docs/ctf-exchange.md, docs/ton-exchange.md), the security reviews (docs/security-review.md) and the deployment guide. In order.

  • [x] Polymarket's licence for CTF Exchange V2. The contract is BUSL-1.1: production use (real money) needs a commercial licence from Blockratize Inc. until 27 March 2030. Jua holds it (the owner confirmed it on 31 October 2026); keep the licence agreement with the company's legal records. Set EXCHANGE_LICENSED_FOR_PRODUCTION=true when deploying to BNB Smart Chain: the deploy script refuses a main network without it.
  • [ ] A licence or legal opinion for every country served: prediction markets are regulated as gaming or financial products in most African jurisdictions, and some central banks restrict virtual-asset transfers.
  • [ ] The per-country affiliate terms set in Settings as counsel advises (Fee and affiliate settings).
  • [ ] Telegram's Mini App guidelines read, and the Mini App's Terms and Privacy pages current.

2. Contracts and keys ​

  • [ ] The owner Safe on BNB Smart Chain: 2-of-3 or more, hardware wallets, different people, none a server key. The signers briefed: pausing, removing an operator, setMaxFeeRate, sweeping, PayStranded.
  • [ ] A resolver Safe (or a key, with the plan to move to a Safe).
  • [ ] JuaVault (the fee vault) deployed with low limits to start; ConditionalTokens + NoWalletFactory + CTFExchange deployed with EXCHANGE_FEE_RECIPIENT the vault and EXCHANGE_MAX_FEE_RATE_BPS equal to the platform's fee rate; sources verified on BscScan; isAdmin(Safe), isOperator(operator), getMaxFeeRate() checked (The contracts).
  • [ ] The same on BSC testnet first, with the test USDT, and a full rehearsal there: approve, sign, rest and take an order from two wallets; a match settles from both; a result reported; Collect winnings; a referrer's Collect. bun run e2e:exchange passes.
  • [ ] The EVM operator key in a remote signer (KMS/HSM), not in the environment.
  • [ ] TON: the owner multisig; JuaTonVault and JuaTonExchange deployed with bun run deploy:ton and rehearsed on the TON testnet with the test jetton (every order kind, cancels, expiries, every match kind, a result, redemption, bounces, a referrer's Collect, the market maker; the indexers' answers checked against the code); an external audit of the three contracts and the settlement worker; only then mainnet, the same script with TON_ALLOW_MAINNET=true, Tether's USDT and low vault limits (The contracts).
  • [ ] An independent audit of what has not had one (the security reviews were in-house), and a testnet soak.

3. The deployment ​

  • [ ] Two DNS names in a domain you control for the site and the portal (plus docs.juamarkets.com), TLS in front, SITE_URL and ADMIN_URL set, BIND_ADDRESS=127.0.0.1. Never a shared wildcard-DNS name.
  • [ ] NEXT_PUBLIC_MONEY_MODE=real on an empty database: the API records the mode at its first start and never lets a play-money database turn real. A play-money demo and a real-money deployment are two databases.
  • [ ] Supabase Auth with Confirm email on, TOTP multi-factor on, the service-role key on the API, Web3 Wallet providers (Ethereum, Solana) on with the site's domains listed; the site's URL among the redirect URLs; email sent through Jua's own SMTP server (Setting up Supabase).
  • [ ] One staff account per person (bun run db:staff), each with an authenticator app; crypto.requireMfa on.
  • [ ] Every EXCHANGE_*, TON_* and TELEGRAM_* variable and secret set (Deploying); two RPC providers and two TON indexers from different companies.
  • [ ] ALERT_WEBHOOK_URL routed so urgent alerts page a person; HOUSEKEEPING_HEARTBEAT_URL on a dead man's switch; both tested by stopping housekeeping for ten minutes.
  • [ ] A way to deliver or watch the TON worker's alerts (Monitoring).
  • [ ] The operator balances watched (BNB, TON) and funded.
  • [ ] bun run db:migrate run by the deploy; bun run verify green before the push to prod.
  • [ ] Before the deploy that carries migration 0036 or 0039, their indexes built by hand with CREATE INDEX CONCURRENTLY under the same names and definitions (the migrations say IF NOT EXISTS and then find them; a build inside the migration would lock orders and affiliate_commissions for the duration). Then bun run db:status clean: it refuses while a hand build that failed has left an INVALID index behind, and names the REINDEX INDEX CONCURRENTLY that repairs it (docs/database.md, "A hand-built index that failed").
  • [ ] Supabase point-in-time recovery on; a restore rehearsed.
  • [ ] The Telegram bot created in BotFather with the Mini App's URL (https://juamarkets.com/tg/), and Register the bot done on the Telegram page.

4. The platform's settings ​

  • [ ] fee.tradeBps equal to the exchange's maxFeeRateBps (the rule).
  • [ ] resolution.disputeWindowMinutes set to what holders need (two hours by default; longer for markets with many holders).
  • [ ] The affiliate programme's share, split and per-country rules as decided.
  • [ ] Demo mode on or off as intended; the house market maker off with real money (it never runs there anyway).
  • [ ] The site banner and the Mini App banner ready for launch notices.

5. The first day ​

  • [ ] Run the live checks against the deployed site after the first deploy, and flip the repository variable LIVE_PROFILE from preprod to production (Actions → Live checks → Run workflow, or wait for the nightly run). Every check passes, or each remaining one is understood.
  • [ ] Start with low fee-vault limits and raise them as collections reconcile cleanly.
  • [ ] Watch the first matches confirm on BscScan and the first TON orders book; watch settlements and ton_cursor.
  • [ ] Keep the vault model (CRYPTO_PROVIDER=vault) running only if any balance from before the switch is still to go back to its wallet; otherwise leave it off.
  • [ ] A person on call with the Safe signers reachable, for the first week.

What stays true after launch ​

  • Jua never holds a customer's money; staff can never move the coin behind a share.
  • A result is final once recorded on chain; disputes happen before, in the open.
  • Every staff action is in the audit log; every key is bounded and revocable by the owners.
  • The recurring tasks in Recurring tasks keep it that way.

Jua Markets · Africa's prediction market.