How to prove we didn't cheat
Every spin's result is math — not a decision. The server commits to a secret seed on-chain before you bet, your session fixes its own seed, and each spin is computed deterministically from both. The contract re-runs that exact math at settlement, so the operator can't fake a result. After settling, the secret seed is revealed on-chain and anyone can replay every spin and check it. This page explains exactly how.
How a spin is decided
- 1Server commits to a seed (on-chain)When you open a session the server generates a random 32-byte
serverSeedand keeps it secret. Its hashserverSeedHash = keccak256(serverSeed)and the backend's short-lived signed offer go on-chain withopenSession(serverSeedHash, clientSeed, spinSigner, budget, validAfter, expiresAt, offerSignature). The hash is committed publicly and immutably — the server cannot swap the seed afterward without changing this hash. - 2Your session fixes a client seedThe same
openSessioncall records a 32-byteclientSeedon-chain. It is generated in your browser (Web Crypto API) and is fixed for the whole session— it mixes your entropy into every spin so the server's seed alone can't determine results. - 3Each spin is a signed receipt; the contract recomputes itFor every spin your session key signs an EIP-712
SpinReceipt(player, sessionId, nonce, betAmount). The result is computed fromkeccak256(serverSeed, clientSeed, nonce)— the first 20 bytes give the 5 reel stops (each 4-byte group mod 30), and reading 3 symbols down each reel gives the 5×3 grid. The paytable (20 paylines) is applied for the win. A monotonicnoncemakes every spin unique. The server shows you this immediately, but it is not the final word: the SlotsV6 contract re-runs this exact computation for every signed receipt at settlement. - 4Cash out: the seed is revealed on-chainWhen you cash out (Stop), the session settles: the operator submits the original
serverSeedtosettleSession. The contract checkskeccak256(serverSeed) == committed hash(a mismatch reverts — nothing moves), recomputes every receipt, and pays the verified total. The revealedserverSeedis emitted in theSlotSessionSettledevent, so you can re-run the math for any spin you took. Paste it into the verifier below.
What you need to save
Auditing only works if you have the evidence. While you play:
- •Server seed hash — from the Seed bar on the slots page, or read it straight off the
openSessiontx on Arbiscan. Copy it or screenshot when your session opens. - •The client seed — fixed for the session and recorded on-chain at
openSession. One value covers every spin. - •Each spin's nonce and the grid you saw — note or screenshot the 5×3 symbols and nonce.
- !Cash out to reveal the seed. The
serverSeedis published only atsettleSession(in theSlotSessionSettledevent). You can't verify without it.
Verifier
Paste the revealed serverSeed, the session'sclientSeed, and a spinnonce. Runs in your browser — nothing is sent to us.
What's enforced on-chain
The seed is committed on Arbitrum.Your session'sserverSeedHash and clientSeed are set on-chain at openSession. The tx is public and immutable.
The contract recomputes every spin at settlement. AtsettleSession the SlotsV6 contract first verifieskeccak256(serverSeed) == committed hash(reveal can't be faked — a wrong seed reverts), then re-runs the reel + paytable math for every signed SpinReceipt itself and pays the verified total. The operator never asserts a number — the chain derives the payout. This is strictly stronger than an operator-reported net: there is no number for the operator to mis-state.
You can independently replay it. Once serverSeed is revealed in the SlotSessionSettled event, plug (serverSeed, clientSeed, nonce) into the verifier above for any spin — the grid it derives is exactly what the contract used. Any mismatch with what you were shown is provable evidence.
SlotsV6 contract: 0xe6dA6bcD64aa9de1EFE45a73fd3282844009B3ff on Arbitrum Sepolia. Open it on Arbiscan to read your openSession andsettleSession transactions and the SlotSessionSettled event.
Algorithm reference
Full logic, to the byte (matches SlotsV6Math.sol):
// Reel strip (same for all 5 reels). 30 stops. REEL = [0, 2, 1, 3, 0, 4, 2, 1, 5, 0, 3, 2, 6, 1, 4, 0, 3, 7, 1, 5, 2, 6, 0, 3, 8, 4, 2, 6, 5, 9] // Symbols: 0=L 1=10 2=J 3=Q 4=K 5=A // 6=Bell 7=Seven 8=Wild 9=Scatter // For each spin: // hash = keccak256(abi.encodePacked(serverSeed, clientSeed, nonce)) // bytes = the 32 bytes of that hash // For reel r in 0..4: // stop_r = uint32_big_endian(bytes[r*4 .. r*4+3]) mod 30 // visible column = [REEL[stop_r], REEL[(stop_r+1)%30], REEL[(stop_r+2)%30]] // Then apply the paytable over 20 paylines. WILD substitutes for everything except SCATTER. // See the full paytable on the slots page under "Paytable".