Trust and technology
Architecture
Program, orchestrator, sim, stream and web.
The big picture
FlySports has five moving parts. The Solana program holds the money and the rules. The orchestrator drives each race through its lifecycle. The simulation works out what happens in a race. The stream broadcasts it. The web app is what you use. A moderated chat runs as a small separate service next to them.
You
Browser + wallet
Phantom or Solflare signs your bets and claims. Betting goes straight to the program.
Viewers
Twitch and the Live page
The same broadcast, with no odds or money on screen.
Web
Next.js app
Pages, bet panel, brain panel, replay and verify. Hosted on Vercel.
Stream
Streamer
Headless Chromium captures the broadcast page, ffmpeg encodes it for HLS and Twitch.
Chat
Chat service
Anonymous, rate limited, filtered. Separate from betting.
Backend
Orchestrator
Creates, locks, settles, expires and closes races. Serves the public race API, stats and leaderboard.
Backend
Simulation
Python, deterministic. Turns a seed and a race card into a full race trace and a result hash.
Solana devnet
fly_racing program
Holds the stakes in per-race vaults. Enforces betting windows, the commit-reveal seed, pari-mutuel payouts, the rake and refunds.
Solana program
An Anchor program (Rust) called fly_racing. On devnet its address is CDV7VxAXMHfVQ3rD9VEviJZgjqkWu9GxM8EmmHE2ho6D. It stores each race in a Race account with a separate token vault, and each bettor's stakes in a Bet account.
| Instruction | What it does |
|---|---|
| create_race | Opens a race: commit hash, race card, sport, lock slot, number of breeds. |
| place_bet | Moves your USDC into the race vault, only before the lock slot. |
| seed_race | Adds the rollover bonus to the pool, only before lock. |
| lock_race | Permissionless. Stores the lock slot's hash once the slot has passed. |
| settle_race | Oracle reveals the salt. The program verifies it, derives the seed and records the winner and result hash. |
| cancel_race / expire_race | Cancel is admin-only and only before lock. Expire is permissionless and only after a settle timeout. |
| claim_payout | You claim your winnings or refund. Closes your bet account and returns its rent. |
| sweep_rake | Splits the rake between treasury and rollover vault, and returns any bonus not paid out. |
| close_race | Reclaims the rent of a finished race once its vault is empty. |
The admin key can create races, rotate keys, pause new races and sweep rake, but cannot move bettor funds. Funds only leave a vault to a bettor's own claim or to the configured treasury and rollover accounts. See what is not guaranteed.
Orchestrator
A standalone Node and TypeScript worker. It runs the race loop: create a race, wait for the betting window, lock, ask the simulation for the result, settle, then sweep the rake and close the race about ten minutes later. It also publishes the public API the web app reads (current race, traces, stats, leaderboard, bet history), and, during the beta, runs the house bettor bots. It is built to fail safe: calls are time-bounded, it takes a single-instance lock, and a race it cannot settle in time expires into refunds rather than sitting stuck.
Simulation
A Python package with a small web service. Given a seed and a race card it generates the course, runs every fly's spiking brain tick by tick, applies physics, hazards and conditions, and returns a trace (every position, event and spike) plus a result hash. It is deterministic and is tested against golden hashes so it reproduces identically across machines. It also offers the endpoints for race results, verification and win-chance tables.
Stream
The /broadcast page is a chrome-free view of the live race, shared on a schedule so everyone sees the same race at the same moment. A streamer process opens it in headless Chromium, captures frames, and uses ffmpeg to make an HLS stream and optionally push to Twitch. The stream shows no odds, pools or betting language, so it is safe to put on Twitch. Betting happens only on the website. A result is never shown to a bettor before it has aired.
Web app
A Next.js app. It reads race state from the orchestrator and sends bets and claims straight to the program from your wallet. It never runs the simulation itself. It replays the recorded trace in 3D, including the brain panel, and calls the simulation's verify endpoint for the Verify button. A built-in devnet faucet mints test USDC and a little SOL.
- The web app is hosted on Vercel; the backend (orchestrator, simulation, chat) runs in Docker containers on a server.
- Everything is on Solana devnet during the beta.
Life of a race
- The orchestrator picks a race card and commits a salt, then calls
create_race. - The betting window opens (about a minute). Bettors call
place_bet; the rollover bonus is seeded. - The lock slot passes.
lock_racestores the slot hash. - The orchestrator asks the simulation to run the race for the chain-derived seed.
settle_racereveals the salt, the program records the seed, winner and result hash.- The race airs on the broadcast. The bet panel then shows the result.
- Winners press Claim (
claim_payout). The rake is swept, and the finished race is closed.