Skip to content

Architecture ​

Jua Markets is a Bun + Turborepo monorepo: three web apps and a Telegram Mini App over shared packages, one Postgres database on Supabase, and contracts on two chains. This page is the map; the rest of this manual says what to do.

The model in one paragraph ​

Jua is non-custodial. Customers trade from their own wallets: on the website, orders are signed in the wallet and settle through Polymarket's CTF Exchange V2 over Gnosis's Conditional Tokens on BNB Smart Chain; in the Telegram Mini App, each trade is the customer's own USDT transfer to JuaTonExchange on TON. Jua's servers run the order book, match orders, send each match to the chain from an operator key, propose and record results from a resolver, and pay referrers' commissions out of a fee vault per chain (JuaVault on BNB Smart Chain, JuaTonVault on TON). There are no deposits, withdrawals or customer balances for real money; play money and Demo are virtual balances in the database.

Apps ​

AppPort (dev)StackWhat it is
apps/web3000TanStack Start (Vite + Nitro), React 19The customer site, juamarkets.com. Relays /api/* to the API; serves the Mini App's static build at /tg/
apps/api3001Hono on Node (run from source with tsx)The trading API: the only HTTP surface, some 150 paths under /api. Runs housekeeping and the workers
apps/admin3002TanStack StartThe staff portal, admin.juamarkets.com. Holds no database credentials; reads everything through /api/admin/*
apps/telegram3003Vite + React, staticThe Telegram Mini App: Telegram sign-in, TON Connect, trading USDT on TON
apps/mobileExpoThe iOS and Android app (ships through EAS, not the server)
apps/docs3400VitePressThis site, docs.juamarkets.com

In production each of web, admin and api is a Docker container from one infra/docker/Dockerfile, run by docker compose on one VM, behind a TLS edge (nginx on the host today; infra/deploy/Caddyfile for the compose edge profile). Supabase hosts Postgres, Auth, Realtime and Storage (Setting up Supabase).

Packages ​

PackageWhat it holds
packages/coreFramework-free domain code shared by every app: countries, categories, wallet and exchange order building (@jua/core/exchange), types
packages/moneyInteger money (micro-dollars and micro-shares, whole-cent prices), the fee formula (buyFee), FX for display
packages/i18nThe eleven message catalogues
packages/dbThe Drizzle schema (source of truth), migrations, the migration runner, the connection
packages/dataServer-side domain code: the CLOB engine, resolution and settlement, the exchange and TON workers, services, auth. Never reaches a browser
packages/ui-webShared React primitives for web and admin
packages/contractsCTF Exchange V2 (vendored, BUSL-1.1) over Conditional Tokens, NoWalletFactory, JuaVault; ABIs; deploy scripts; an in-process EVM harness
packages/ton-contractsJuaTonExchange, ShareMinter, ShareWallet, JuaTonVault in Tact; the committed build; @ton/sandbox tests; a development chain
packages/configShared TypeScript bases and the Biome plugin for the money rules

Two lint rules shape the architecture: apps/admin may never import @jua/data or @jua/db (the portal holds no credentials), and packages/data and packages/db stay framework-free (their dependency graph is the blast radius of the database credentials).

Workers ​

All run inside the API process, from the one-minute housekeeping pass (or an external scheduler calling the cron route), each under a database lease so any number of API instances share the work safely:

WorkerEveryDoes
Market housekeeping1 minExpires orders, closes markets whose time is up, finalises undisputed proposals, renews recurring events
Settlement (exchange) worker1 min, and after each tradeSends matches to CTF Exchange, confirms them, undoes refused ones, prepares conditions, reports results, pays EVM commissions
TON worker5 s (and each pass)Reads JuaTonExchange's transactions into the books, sends matches, closes, refunds, new markets, results and fee claims; pays TON commissions
Listing translations1 minTranslates queued listings with Claude
Demo housekeeping1 minFills demo orders, settles demo positions, advances simulated payments
House market maker1 minPlay money only: re-quotes every open market
Crypto housekeeping1 minThe vault model's watcher, payout queue, hourly reconciliation and custody alerts; runs only with CRYPTO_PROVIDER set

Details: Housekeeping and The workers.

Chains and contracts ​

ChainContractRole
BNB Smart Chain (56; test 97)ConditionalTokens (Gnosis)Holds the USDT behind every pair of shares; splits, merges, pays redemptions after the oracle reports
CTFExchange (Polymarket V2, BUSL-1.1)Settles the operator's matches of signed orders; admin = the owner Safe, operator = the API's key
NoWalletFactory (Jua)Stands in for Polymarket's wallet factories so proxy/Safe-signed orders can never move anything
JuaVault (the fee vault)Receives every fee; the operator pays referrers' collections out of it within limits; the Safe sweeps Jua's share
TON (mainnet; testnet)JuaTonExchange, ShareMinter, ShareWalletThe Mini App's exchange: holds each order's USDT or shares until it fills or ends; one share jetton per outcome per market
JuaTonVault (the fee vault)Receives claimed fees; pays referrers' collections within limits; the owner multisig sweeps

The contracts has the deploy order and commands; Keys and roles who holds what.

Data ​

Postgres on Supabase, owned by Drizzle (packages/db/src/schema.ts), migrated by bun run db:migrate from the deploy and never by the containers. Row-level security on every table; clients never write business tables directly. Tables the operator reads most: settlements (matches, per venue), chain_markets and chain_results (conditions and results on CTF), commission_payouts and affiliate_commissions, the ton_* tables (ton_cursor, ton_messages, ton_markets, ton_results, ton_refunds), job_heartbeats and job_leases, provider_events (durable alerts), and the audit log.

Where the design is written down ​

The repository's docs/ folder holds the designs this manual summarises: non-custodial.md (the model), ctf-exchange.md (orders, fees, results on BNB Smart Chain), ton-exchange.md (the TON exchange), telegram-mini-app.md, deployment.md, database.md, security-review.md, jurisdictions.md, listing-translations.md; packages/contracts/README.md for the contracts. The API's OpenAPI document is at /api/openapi.json on the API (served in production only with API_DOCS=true, through an SSH tunnel to the API's loopback port).

Jua Markets · Africa's prediction market.