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): 0xd71d711f27e190489a594b59ee5e2989e984413ac29c763e12f4f2bcd61ec3f9
clientSeed: 0x495caa7d73b511dac907ab1e5f326f3c722927bbab02fd0f43f7ac36d399f70f
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x8e46b599dd3e0a2e4ccf00bbffb1611ac82f88daf40a83d594ebb0a5655ef1fd
clientSeed: 0x6074c4adcb4923f45b2a3910621db001a0dbf162c6ea3945ab012518acdd45ed
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): n/a
clientSeed: 0xc7232ae2d71047eab03ff5d11ac53807851945f1f3754091bbb5f13cee458411
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0xd141a9cdbb4df966a65cb0c74863245d48c910c0b171cf2afd18e7f0c1bc3214
clientSeed: 0x5131b2aa68e920aacc3e9368129b70d342ce7bc6b0dab05039d62e1b63f33b81
chain entropy: not yet, arrives with the draw
serverSeedHash: 0x4f37a4b9d56b3af960a6aa4eb8d60a09da073ec538fa539aec768a10ca6053c6
clientSeed: 0x4eb9ce9002459dc1592bd90d916557d256f403b023dcaac54727426ca948ccf3
serverSeed (revealed): 0xa89e04d08e28ac5f3227cfdcdbe750ebdb8d1a0cef5e199f7b7f12181cdd1ca8
chainBlockhash (revealed): 9rU7MVcFUsDHSkYCUcaWkCLLo9DECQGS4b9ZxECZgkGz
chainSlot: 457949936
serverSeedHash: 0xec2164705ad401fbd176da1a4df330178d718a0602bd928238a4f6b6201bcc31
clientSeed: 0xe4996acd506884bf8a971fd4eef716de0ab778a273c1f492220673af6e3241ad
serverSeed (revealed): 0x99c6b1ebb49d2e48cc3b066d1c00476e85fc34bea96a9ec8fe46cb1672c19578
chainBlockhash (revealed): 5iFRYdxWACRD465otji5XEgZbzzKVW2mD9NrXm6oQmra
chainSlot: 457948531
serverSeedHash: 0x45b5b7f5326cd452d8d93887c74455a523a27a49ee587fe2aad437829e1b4c1a
clientSeed: 0xa764eb2807e0714c5e92533b915bb83f9a21c5e7d52efb0cfcda465691e12a80
serverSeed (revealed): 0x6a8856e492dda8b4c24a3e735725351d3e2d8104dc09766c402c59c1e8888f77
chainBlockhash (revealed): zYE5nEkTh9XxqY7tG4QmgJCAjrJrgmee4jNyvyPXQrT
chainSlot: 457947144
serverSeedHash: 0x6ad78294a1a4249f663692de0bb778907b88d7e45490a17579aac6b19ef08455
clientSeed: 0x67906969f20cab485508ab0900a22744652e254c30baa0af6474a11c67189028
serverSeed (revealed): 0x5971bbf7edffbe322edd0865d1f5db549c615d1b2d31d5fe26480d921f0eef84
chainBlockhash (revealed): 9VsCw4oq55Gh3GLo36AxCiofMDNgwvqmBu2cZ9KXFsiY
chainSlot: 457945756
serverSeedHash: 0x913447eda50451bab17783cb5c794d612816b7511638dd24704462f6b9c2a777
clientSeed: 0x4e870a317ade340378d889488dfb2f8b23d2cffa42242ec782a1eb8bb9334cff
serverSeed (revealed): 0x37546f59a445972f8e2ca5bd916b541ab8f0eee70cdbb96e0f9d5f6ae92683af
chainBlockhash (revealed): 9VsCw4oq55Gh3GLo36AxCiofMDNgwvqmBu2cZ9KXFsiY
chainSlot: 457945756
serverSeedHash: 0xcff37067b0f457ab87f16a2742fc3aceab2a24f80e30b8754a20828277a78fcd
clientSeed: 0xeb8e070b2687f1e8436dc0bc574289655d7507fc62ad3283c4a7ba48a6e2d99f
serverSeed (revealed): 0x530ee42fe882263c2e0716e8d08d82ce195174bda2d70f49fefdeff42a946e12
chainBlockhash (revealed): 8tTwFw8MMhW4JqhBTAkEC8eJRBwap1xKoSJzE2F8LjBp
chainSlot: 457944370
serverSeedHash: 0x0e3f3ccbaaf7beff1ce234a965d85bdeb320f87e0d910ac24f2419f51b0efd16
clientSeed: 0xd60c6002e49fb0a8dfea11e8ca112882ed033a982910194c18bfa6968856eaa0
serverSeed (revealed): 0xc2918d68ccaaf37d9978acc800df255d77d3136fe12bc8382936d9ebd5bab73b
chainBlockhash (revealed): FYDHxk41m6rzzM6wDtuppGQagPPFdrJQTHw2tn2JbmWh
chainSlot: 457942978
serverSeedHash: 0x0915b1a666c9009517f7e8f30a22978eaf60d2d47dbad6b798ebc13df7a91244
clientSeed: 0x7af48e299e6c5958210b4967682fcd3bce21fe474b2c66054e5a507f8d4fe334
serverSeed (revealed): 0x8031f0da2de2607d56c57af9ce2fb32c72bebfe38e2bb28b55c690e57cf2a4a3
chainBlockhash (revealed): 7kVasqCxZLBXVRriUfVMHYBLtkThJseghnowrPRHDWR2
chainSlot: 457941584
serverSeedHash: 0xc8d65f13ff0ccc5f1b8b39aa0c5c568805ec36557c11bb65958e6fe29054ba9c
clientSeed: 0xcdcf11a9e88c8fddba95f3f5d5be7dbe09bc492121f872eaf11dfb0bb2f21ced
serverSeed (revealed): 0x7d1282a72562bc40244259c43663b561690c6dc403b8ff33cbae8eaac82f98c5
chainBlockhash (revealed): Hp6VGiyKGi3yS9BjYEoHA5UWkYrEJ8oFKYkRk9RYZGDE
chainSlot: 457940196
serverSeedHash: 0xd072c2ee77a5499d2a3da1bab574a533751c8f3cdad8b0cc617eb0b7c90b87d7
clientSeed: 0xe4bf69a41ce8546461a69a64ff82106d9df8cc922739ba92b4295ac59e1a2902
serverSeed (revealed): 0x2a408cf529423b7e25be9f4ce1f021039430bbde69ebc3dff113b277cdb64426
chainBlockhash (revealed): DGNmQbTVG8a63XJgVxhPjziNUKg5NoBKqGgzqtAtQ3Si
chainSlot: 457938819
serverSeedHash: 0x49df5e3364975be6f5a662541eb4b88df4145e17b04de1e5b03df250da568505
clientSeed: 0x86c7109f7c28746ad5d518fb51c7bd9a9e2ba77f1920869010e96c8e17c11b14
serverSeed (revealed): 0x16ad232042e28a121a83789f1aeefc4a3c3de4bf37f16e9a0cd2f2e1ca5b3256
chainBlockhash (revealed): AHPhfKgcmjh8DPWaUvfmDJM2fUUQ8EhyYiP86BbEfpmY
chainSlot: 457937433
serverSeedHash: 0xca61c05e9933d1f49e1c628622508964e2a53c79d373851a558cf379f2be9f1f
clientSeed: 0xc5574dd0d4a611a67ff5b0b3d13db88a06077fa3b2b824db38b1ac2023c08df7
serverSeed (revealed): 0x95fe65cf23b45a189c96473327730549f164d43fc883507a373d244e00d8898c
chainBlockhash (revealed): GnhpPzLJSRkYGApt3Tonn5J3ygycUfcwGj8yTQGmc3Xu
chainSlot: 457936045