Provably Fair
Every game commits first, then rolls with entropy from the Solana chain. Here is exactly what that does and does not protect you from.
How a round actually runs
- Commit. When a lottery round, duel lobby or case battle is created, the server generates a secret
serverSeedand publisheskeccak256(serverSeed)straight away, next to the publicclientSeed. For duels and battles this happens before an opponent even exists, so nobody can pick a seed that targets a known player list. Lottery rounds commit before a single ticket goes on sale. - Close. Entries lock: lottery buys and sells stop at the closing tick, a duel needs both stakes in, a battle needs both players matched. Case battles also freeze a copy of the case's drop table at match, so later case edits cannot touch a battle already running.
- Entropy. Only after the inputs are locked does the settlement worker fetch one Solana blockhash and persist it together with its slot. Battles fetch theirs at match because the live per-round reveal starts there. The fetch only accepts a slot strictly newer than the chain tip recorded at commitment, so a game created and matched inside a single slot waits for the chain to move. A blockhash from after the commitment cannot be known at commitment time, which is what breaks seed grinding: the operator can try seeds all it wants, the final input has not happened yet.
- Derive and reveal. The outcome is one hash over
serverSeed,clientSeed, the chain blockhash and the game id. At settlement everything is revealed: the seed, its published hash, the blockhash and its slot. You can re-run the math yourself in the verifier below and check the blockhash on any Solana explorer against the published slot.
What we can still do, stated plainly
- The worker that fetches the blockhash is ours. It keeps trying until a value lands in a slot newer than the commitment, and exactly one fetched value is written with the settlement claim, so it cannot be quietly swapped afterwards. Attempts that fail or land too early simply retry, and a compromised or dishonest server could still time or retry that fetch. That is a single point of infrastructure trust, and no purely server-run scheme removes it.
- Your account, your balance and the payouts live in our database. If the whole stack is compromised, fairness math will not save you. What this design removes is protocol-level steering: grinding seeds, re-rolling after seeing entries, or adding tickets once the draw entropy is known.
- Rounds settled before this upgrade (visible in the reveal: no chain blockhash) used only the two seeds, and are still verifiable with the legacy formula.
Formulas
Winner-take-all lottery draws:
target(tier, attempt) = uint256(keccak256(serverSeed || clientSeed || [chainBlockhash] || drawId || tier || attempt)) mod totalTickets; winner(tier) = first entrant whose cumulative ticket count exceeds target; the single tier-1 winner takes the whole pot (legacy rounds paid up to 4 tiers; collisions with an earlier tier re-derive with attempt+1). Rounds settled after the chain-entropy upgrade include the 32 raw bytes of the revealed Solana blockhash (base58-decoded) between clientSeed and drawId; legacy rounds verified without it leave that segment out
Duel coin flip:
winnerSide = uint256(keccak256(serverSeed || clientSeed || [chainBlockhash] || lobbyId || 0x01 || 0x00)) mod 2; side 0 = lobby creator, side 1 = opponent (join order); rake = floor(pot * 0.5%). Duels settled after the chain-entropy upgrade include the 32 raw bytes of the revealed Solana blockhash (base58-decoded) between clientSeed and lobbyId; legacy duels verified without it leave that segment out
Case battle drops:
value(round, slot) = uint256(keccak256(serverSeed || clientSeed || [chainBlockhash] || battleId || round || slot)) mod 10000; drop = case dropItem whose cumulative weight range contains value; slot 0 = creator, slot 1 = joiner; winner = higher cumulative drop total; exact tie splits the pot after rake; winner takes the pot minus 5% rake, not the opened items. Battles settled after the chain-entropy upgrade include the 32 raw bytes of the revealed Solana blockhash (base58-decoded) between clientSeed and battleId, and derive against the drop table frozen on the battle at match; legacy battles verified without it leave that segment out and use the case's current drop table
Seed commitments
serverSeedHash (commitment): 0x1c4e96d0583f8ffaded7066fcb6e6d24a42e915c2f64e7a44c097a9076e38e23
clientSeed: 0x9072138af3e04fcb1daf1b64d8b80a4214c6a66a6cfc86962aae177f687788d1
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0xfe3dacdd80e638748a5bf69245e67467cfc4bca75066dd4d12798e90c88670f9
clientSeed: 0x49e4606d2eb76acb05aa6240759107c1a09d90e62e406874c3ab2ed6093a60dc
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x24d5e14176236ff7fcb2d4db69870149192d8369adf799313bff22ad8d10f7ef
clientSeed: 0xe7ee2dd6d3bc1b68ccb2f80429ab27cbe9d8c0870cb67e94d0f69f68444a4120
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): n/a
clientSeed: 0xc7232ae2d71047eab03ff5d11ac53807851945f1f3754091bbb5f13cee458411
chain entropy: not yet, arrives with the draw
serverSeedHash: 0x45064f63a269ac828d3a638af98c649e5d24ca042748c112b4acfe493d1d6320
clientSeed: 0x561aed690cb1cdb466a6e0aa2bd87d30798ab2cf5c27de23a5062c9960e3c02d
serverSeed (revealed): 0x0bff2db1a070432a157b256504f3185ad7504ea020e9dead5f2e154f9d1a4730
chainBlockhash (revealed): 75JX7pWqaxnYK5cgbk5DnWx2Ndmrr6Q71azR89AK7dBf
chainSlot: 457678262
serverSeedHash: 0xabb57679f54b204b1b48f3d86e589abeaca565be94aef78131a6e3ee6adff3de
clientSeed: 0xdcb60fa32650f514ab42ba642a3af03aeb0a64ef8a931a4b3e744b23ae7256d3
serverSeed (revealed): 0xe6cdca83c52f21dd0167a1d5716a9f37d09b65010782937cbe38fd096c0ebcc4
chainBlockhash (revealed): 9Z5bFVgc174sThGf5kQLr3cF6MLtFZKFHh91u4n64J8L
chainSlot: 457676866
serverSeedHash: 0x84c6370378e99963ff73273ac4c8fb5e3a64d6774cfb28e7cf5e0c1e1c5ffe38
clientSeed: 0x7d5cde5d8d6a833b489b2be5ad34fe0471ea729221ed793c35ad7a0200ea5f07
serverSeed (revealed): 0x2dcbbba95258500610ea200afc18a96d5b2d396a1eb1651e8b8819ffac800371
chainBlockhash (revealed): 9KjJwauWJqDHbTTxDZRWQdVb7s7jD6TfWZ9mJbTCaiMw
chainSlot: 457675472
serverSeedHash: 0x74fe8d27aee998e0093dac350d57ad99a42866c4575c1ab9b7ab8dd575659e57
clientSeed: 0x0139bb5a06e4d45e88e91aa3352d8cbec84d49d4a7a25c5845b49e8803a917c7
serverSeed (revealed): 0x62d237b8210f89a55d7fe240ea09b33b090dfa2d23c49e0a0070c1b7ae82ec89
chainBlockhash (revealed): 8YCFbh7sCAxmVUYmjHL7D1qGnbVVW1Nj1PCLyuC7A4Mn
chainSlot: 457674066
serverSeedHash: 0x2221b6505e7269eff22781ff0dab0a50191c21887c699c543fd037679f020c7d
clientSeed: 0x76299ff4de831596329a9a07eaf464c512dd692933312eb84796a37417fcbcaf
serverSeed (revealed): 0x1987592c161a07964d3dc17a20904114d92b7102af9ff76c795cfc262aee7f83
chainBlockhash (revealed): EkMp8JF2TKAnnXTKvVFkk24p2nxYGxK9p4o8Rzg6y9dT
chainSlot: 457672676
serverSeedHash: 0x5361d18a65231843399b143ac648f28c31545841796014b0b8f5d64eb5f3b26b
clientSeed: 0xe58a5cf97fa48875114c9793db29043c1d6ca2f5be6fa847137c2d6400c88747
serverSeed (revealed): 0x37a86dad00541265a255927eda2e49b1348ddc81cb832ea365379249d13e76ad
chainBlockhash (revealed): HFx8qoHCgVrwQEJyY2k2HPwazRx4w3H7yY1FnoR8x4oN
chainSlot: 457671273
serverSeedHash: 0xfe21d7d001f03eb607756db07328ffe8a9cfbcdf6f470a92045c65f257afe746
clientSeed: 0x7b2fc29b7c3465589ddd028ab50f6a77dcdfb1a57b5f7f77a3525f36ed6c12a0
serverSeed (revealed): 0x30856d75b9f54e3709e8b0429d04e5116817cfc787926716aa101d5264788de9
chainBlockhash (revealed): 2pyEKJsT1mTgrSZbBHvZQrBhJnqY1rFfsJNHdy71r4im
chainSlot: 457669889
serverSeedHash: 0x2c4192bdc4095858d6fd493b116de0085eaddf2c39e9821854eda714f7903bf4
clientSeed: 0x19f90c22a0914d5cacf6a2090d0802b3c6a5b78fbe9e3eb4a1f991490c7f6d80
serverSeed (revealed): 0xfe1c7305400663cf4c5e0766d8c08a5455539d251b546227d5b3c6e322315a2e
chainBlockhash (revealed): FzP7xGZ5XLEbBDAWzMow1x99TWXffSXGxGs9Z92XJZuu
chainSlot: 457668511
serverSeedHash: 0x8097651149312c4eedc1c1ff6d783f314b10d430f5bcc2f63c2101780f2b7ba4
clientSeed: 0x0d532dce90f3243d6745ffe1e38c7dba9a07295544284adc05193a169f73f1c3
serverSeed (revealed): 0x35240573bd89068898c5318318f8110b9cc89a3257ff86c06252515091d2be2a
chainBlockhash (revealed): 7jkmtm9JTtKf5A2AbBFR7DBo1ehmC6Z94TmdfzKJjsvU
chainSlot: 457667119
serverSeedHash: 0xf2618dd1818ae6a148a24c060745fb2c0aea971f69d8a1f36d8ab35c74b3baa9
clientSeed: 0xed9e9f780ac01b0071cf24c765223741839cdd414554692559c6c0abca90a388
serverSeed (revealed): 0x0c74315e0d70215ecbeba2c7c63b6389e801784780fd9858c4f406443f43bb2c
chainBlockhash (revealed): cxmwp2t9nJNKy5r1hRJPobopWiWYBaas9Atpxop3iVi
chainSlot: 457665734
serverSeedHash: 0x8e3b26430c69f1fa242ed707438d092169ae94cd3a4f71247a577a1dcebf9ad8
clientSeed: 0x01a5208e6f56d9a6b8010d60747e5af5d59457cc8072f6ab7ef2eb2debd81494
serverSeed (revealed): 0x2be5cfbb0d767bdfe56d46f1cf08de60a513d2f6ea876766be8ed0b2325d181d
chainBlockhash (revealed): G4SUsFd1BKjgDtPdM3cpFpc8MLApygoifsFmhGkXgNNU
chainSlot: 457664334
serverSeedHash: 0x3203074f24ea7e7e91f490c1f97baea0cc9058a4441be55317bce2d8a15fd077
clientSeed: 0xc0bbaeda57507a69a49e826301495ae6812283ee2c55a1d98f6e5b25d8cec0aa
serverSeed (revealed): 0x61aa46d47e14da6efba8b02806f42d512ab270b7758b5503ae532a88371137be
chainBlockhash (revealed): 8iWEcTfqb8dmX8rkf5PvNbFyFwbYZ5335LgHsu4stAcK
chainSlot: 457662938