Why randomness is WarmUp's foundation
In games of chance, the random number is the result, and the result is money. Whoever can predict or steer the randomness can steadily take money from the other side.
For WarmUp, whether the randomness can be trusted decides three things:
- Players' funds: once results can be manipulated, fair odds and a deep bankroll mean nothing.
- The platform's credibility: the platform is both the house and the operator. What it has to show is not "I promise not to cheat" but "I couldn't cheat if I wanted to, and if I tried, you'd see it".
- The point of the chain: WarmUp Chain exists so every bet and every draw is public. If the randomness itself can't be trusted, the chain is only a public record of a rigged game.
Where common approaches fall short
| Approach | Shortcoming |
|---|---|
| Server-side random numbers (classic online games) | Results come out of a black box; players can only trust the operator |
| Block hashes or timestamps as randomness | The block producer sees them first and can even choose them. WarmUp's blocks are currently produced by a validator the platform runs, so these sources are fully visible to the platform; we don't use them |
| A seed committed by the platform alone | The platform can't change the seed, but it can choose which bets to accept and turn away the ones it would lose |
| Third-party randomness oracles | Wait for an external callback: slow, paid, and dependent on another chain's infrastructure |
Design goals and threat model
We design for the worst case: we don't assume the platform is honest; we assume it will do whatever it can to profit.
Assume the platform is the adversary
| Party | What it can do | How the design answers |
|---|---|---|
| Platform (operator and house) | Runs the validator, relays players' transactions, holds its own seeds | Seeds are committed on chain in advance; the player's randomness stays hidden from the platform until the bet is placed; no draw means the player wins; no void function in the contract; receipts the platform signed can be claimed on chain; refusing a reveal is visible to the player at once |
| Player | Modifies their own browser code, refuses to cooperate | The player can't see the platform's seed before revealing; not revealing hands the result to drand and gains nothing |
| Validator clock | Chain time comes from the validator | Independent observers compare block times (in progress) |
| drand network | Produced jointly by many independent organisations; no single one controls it | Signatures are verified on chain against its public key and can't be forged; used only as fallback and in multiplayer rounds |
Three principles
- Many contributors: the result is decided by parties that don't trust each other, and one of them is the player's own browser.
- Commit first, reveal later: every piece of randomness is fixed before it is used, revealed when used, and checked on chain.
- No cooperation means you lose; no way to void: no party can get a better result by walking away.
Three sources of randomness
Taking the coin flip as the example (single player, results in seconds):
| Source | When it's fixed | Who knows it early | What it's for |
|---|---|---|---|
| Your browser | When you bet, it generates a 32-byte secret locally with the system's cryptographic RNG and puts only its hash on chain | Only you | The platform can't compute the result when you bet, so it can't pick bets |
| Platform | Hashes of a batch of seeds go on chain before play; each bet is assigned the next one automatically | Only the platform, revealed at the draw | You can't compute the result either; the platform can't swap seeds later |
| drand (fallback only) | Produced jointly by organisations worldwide, one round every 3 s, signatures verifiable on chain | Nobody | Used instead if your secret isn't revealed within 10 s |
1 = heads, 0 = tails · a correct call pays 1.98×
The formula lives in the contract and the contract computes it; no party can change it.
How one bet runs
Normally about 2 seconds. Two steps matter most: the platform must sign you a receipt first, and your browser independently recomputes every round.
- 1Platform → contractCommits hashes of a batch of seeds
- 2Your browserGenerates secret s locally
- 3Browser → contractBet: amount, side, hash(s)
- 4Browser → platformHands over secret s
- 5Platform → browserSigned receipt: bet, hash(s), time received
- 6Platform → contractReveals seed and s; the contract checks both hashes, computes the result and pays winners at once (~2 s)
- 7Your browserRecomputes independently: should have won → claim with the receipt
- If something goes wrong
- !No reveal within 10 s → drand decides
- !No draw within 10 min → anyone calls
forfeitand you win
Why the platform can't change the result
- The seed is on chain before your bet: each bet is assigned the next unused seed. At the draw the contract checks the seed against its earlier commitment and rejects any mismatch.
- The platform can't see your secret: when you bet, only its hash is on chain, so the platform can't accept only the bets it would win.
- The contract computes the result: the seed and the secret must both match their hashes, and the formula is fixed.
- No draw means you win: if the platform doesn't draw within 10 minutes, anyone can call
forfeitand settle the bet as your win. - Payouts are always covered: the moment you bet, the amount the bankroll might owe you is locked.
Your browser: a trusted terminal on your side
In classic online games the result is computed on a server and you can only trust it. On WarmUp, your browser is an independent referee: it doesn't take orders from the platform, only from you and the contract on chain.
- It makes its own randomness: your secret is generated on your device, and the platform can't get it before you bet. Every round includes randomness of your own.
- A signed receipt for every reveal: the platform signs a receipt saying which bet, which secret and when it was received. Your browser verifies the signature against the chain on the spot, counts it only if valid, and keeps it.
- It recomputes every round: the platform must reveal its seed at the draw. Your browser combines that seed with your secret to work out what the result should have been, and whether your reveal was held back.
- Game pages run in a sandbox: they can act only within that game and can't touch your balance or withdrawals.
So you don't need to trust the platform; only two things: your own browser, and contract code anyone can read.
From the player's seat: spotting it and proving it
| What the platform might try | What you see | What you can do |
|---|---|---|
| Takes your secret and signs a receipt, but never puts it on chain, waits for the drand draw, and you should have won | The page flags in red "You should have won: the platform withheld your reveal" and shows a "Claim with receipt" button | Press it. The contract checks the receipt's signature, the time received and your secret, confirms you should have won, and pays you from the bankroll (once per bet). The platform's own signed receipt is its confession |
| Takes your secret but doesn't sign a receipt, waits for the drand draw, and you should have won | The page flags in red "The platform didn't acknowledge your reveal, and you should have won", with a count since you opened the page | Note the bet id and the settlement transaction. Once may be a network glitch; again and again is a cheating signal you can report publicly. For now this can be detected but not enforced on chain (see honest limits) |
| Never draws | The bet stays at "waiting for draw" | After 10 minutes press "Win by timeout"; it settles as your win |
| Tries to swap the seed | Can't happen | The contract rejects seeds that don't match; nothing for you to do |
| Slows the validator's clock (affects the drand fallback and multiplayer rounds) | Observer nodes raise an alarm (in progress) | Check the public observer dashboard |
Check a bet yourself, without the page
Open the coin-flip contract 0xE7F619E13AB088Ed5565F5870A59917d4DAdFA37 in the explorer:
- Find your
BetPlacedevent and note the bet id, the seed index (commitIndex) and your secret's hash. - Confirm that seed's hash was put on chain by a
HouseCommittedevent before your bet. - Take the revealed house seed and the settlement mode from the
BetSettledevent. In a normal draw, the last bit of keccak256(seed, your secret, bet id) is the result. - If drand decided, the round used is the one given by the contract's
drandRoundOf(betId). That round's public signature is available from the official drand API and matches the one used on chain.
Multiplayer rounds (such as Ladykiller)
In multiplayer rounds every player's browser also contributes randomness, and results arrive 1–2 s after close (Ladykiller v5). There is one extra risk compared with the coin flip: the platform could join a round with an account it controls and decide not to reveal after seeing everyone else's secrets. The rules below deal with exactly that.
- House seeds locked in advance. The house builds a hash chain and writes its tail into the contract, so the seed for round k is fixed when the chain is built (a new chain applies only to rounds not yet started). Each revealed seed must hash to the previous one.
- Bets carry only a fingerprint. The browser makes a secret and submits only its hash with the bet.
- Everyone reveals after close. At close the contract first shuts betting on chain; browsers send their secrets only after seeing the "closed" block themselves (sending earlier would let the platform use everyone's secrets to slip in a bet). Secrets arrive within 1 s, and the platform signs a receipt for each, stating when it arrived. Anything received within 1 s by receipt time must be counted.
- One transaction settles it. The collected secrets go in together with the round's house seed; the contract computes result = keccak256(house seed, all secrets) and settles in the same transaction.
| Case | How the result is decided | Time after close |
|---|---|---|
| Everyone reveals (normal) | House seed + all secrets | 1–2 s |
| A player doesn't reveal | The drand round published 1 s after the settlement transaction lands is used instead. The absent player's stake is frozen: revealing within 7 days returns it, otherwise it goes to the round's other players | about 3–4 s |
| The house doesn't reveal its seed in time | The round's entire locked reserve is shared among players by stake. It is never less than the most the house could owe under any result, so withholding a seed never pays | after a 10-minute timeout |
| drand pauses | Wait for it to resume. Slower, never wrong | — |
- Why an absence switches to drand instead of counting only those present. The platform holds every secret it received. If absent players were simply dropped, the platform could compute both outcomes, with and without its own account, and pick one. Switching to a drand round published after the window closes turns an absence into a new result nobody knows: a blind redraw.
- A blind redraw still costs. To get its stake back, the absent account must reveal its secret, and then anyone can compute what the result would have been. If absences keep turning rounds the house would lose into rounds it wins, it shows within a few rounds. Without the reveal, the stake goes to the other players, not the house.
- A house absence is punished, never redrawn. Only the house sees the full result first. If withholding its seed also fell back to drand, it could redraw for free whenever it was about to lose. So this case only punishes: the round's whole locked reserve goes to the players.
- Anyone can trigger the fallback. Once the drand round is out, anyone can submit it to settle; you can press "Draw it myself" on the page. The contract has no way to void a round.
Honest limits
These are the problems not yet solved, or that can be detected but not prevented. We list them here rather than hide them.
- A refused reveal can be detected, not enforced: today the platform is the only relayer and the only block producer. Once independent validators exist, your reveal can reach the chain through someone else's node, and this becomes enforceable. Before wUSD games, we will also publish rules for paying out on page evidence.
- One "blind redraw" remains in multiplayer rounds: by keeping its own account absent, the platform can replace a round's result with a drand redraw once. It can't choose the result, and each time it loses the stake or leaves public evidence. With independent validators, randomness moves to threshold signatures among them, closing this gap.
- The validator's clock has to be right: the drand fallback and multiplayer rounds depend on chain time. Clock monitoring on observer nodes is being built.
- Test coins for now: all of the above runs on the sbUSD test coin, with no real money involved.