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): 0xf36fed4d0afa5382f0da0742bc32858a0cabcffe7a0755d2e40f56a28d59ca53
clientSeed: 0x478e85f1a83c51cabc3bf7f1b30c785959552f43bf5f4c4507405d0421535367
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x01c94f4f3c12fe26587d8f01e296d60c59fd4bad69b486eff22fef641d6453c3
clientSeed: 0xd856c1bae554c942ab646fb0a78fa4fdc4f2c876f05b032fca236ea981240f77
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: 0xbafdc34442f197967c7935d060fc045de6dc53891449f1de1d164cbc9d79eb63
clientSeed: 0xe0602b2a31c124f19ecf6b8cd07ba93cb8a4c138ce282baa5044756c2b521753
serverSeed (revealed): 0xf4aa75fb41d4028022caffa942d56f164eb5443ad061e1e3588d94a1f4078b2b
chainBlockhash (revealed): ErH5f4QxmwpDu2vJ6jQ4woRjhPaHn9dWJm9d69Foyrui
chainSlot: 457612925
serverSeedHash: 0xcf47ad597f5dd7eb831936ee53e62f48047e0c35eec4dbe4a44d846b30dce93a
clientSeed: 0xce9ca07227c130234329c8a93f908dafd8ba287f15279d0bc76ed9c796c000fc
serverSeed (revealed): 0x561e26a5902239b778129b32d52c81831664d36540bbe9ec69cc45e622209b4c
chainBlockhash (revealed): BdBz1f5K3HPPDWkeEbaUhozpZYRDtUdKZ4QideDGC2Kg
chainSlot: 457612924
serverSeedHash: 0xfd642ca7424b5b3174143c78090fef2b204a15ace8a58a3792cee96dcd0026cc
clientSeed: 0x1f755b2a2edaba0c5865cd75188cde113593665c9c9feaee8d8d411305d83933
serverSeed (revealed): 0x1a7b2d2e3d0d3aeed429309a701f195c4f41eb373aaa1489f2037a9348461e75
chainBlockhash (revealed): BCPUZTTCki9KiNND2qAXjFzikVBNUciNGWVTsz5ATXjb
chainSlot: 457611523
serverSeedHash: 0x5e301862970fd25aa844c9db88f06c52c69419c65a02be29280546ee3c377da7
clientSeed: 0x5aa838842fa4318c8a764531826581ffe782594543fc93becb2fd8c5422d2ad5
serverSeed (revealed): 0x17362b78c66348c6848b73e69727ea223aa97f410d29e4d088923c5e219d97ca
chainBlockhash (revealed): 9SGxWXDmwVQVhjMgudNa3usHi4GmWwrjyW293pEhmZH2
chainSlot: 457610132
serverSeedHash: 0x09f96e5aeef0c86c85cc3b1fa11b1a365551ff4366213b9e82c40adb95dcb4f5
clientSeed: 0x7522f2e18af5fb2155919ecde52a3e1465211962ee59ca834ed198d7168db2ed
serverSeed (revealed): 0x390256b19bff81e03b7c743ccb37df73b952c90862fb213434a44ab34c5500a4
chainBlockhash (revealed): 9N9QXa3xnQY1LbRpogrZrhVx4x9MXEzA59KWZuYXzbr1
chainSlot: 457608736
serverSeedHash: 0x39a52948abb781a4e6af73cc1aa37b271ab346ac20d0261676faf658e55322c3
clientSeed: 0x271fb8ae928200ef62f24a4f3ec797fa040d836155b4ba24f58168985c0ad040
serverSeed (revealed): 0xe0bb396c234f817cd3a06871d8a009c7ea39afe77531f96bbc0fbfcb0d89dcd5
chainBlockhash (revealed): B4MQUdLtUNro5LRq736KEpfhVdh3fjDpzMb2aYyGjcgg
chainSlot: 457607343
serverSeedHash: 0xa528d8401707102fc9e2a20f50e690500806e94177029b6ece9530a2772b2bbd
clientSeed: 0x21b44bdcf5b4894ffbcbc70bfc11604e179142a433c3cc7adee956fb4aa23791
serverSeed (revealed): 0x1d2d39ffc3fa75c4c6d644c295a72d50d4a8ebd41ee7ab7b544f6ef0c3199dda
chainBlockhash (revealed): GNyHfJNMkHL9fFabF8jDj2xsmbCUFqU2EKCvya2dnPn8
chainSlot: 457605946
serverSeedHash: 0x5b2bad074c56629e99036cc234427d9ef7bfc72ce2a732d2e17fc70fc2fcbea6
clientSeed: 0x00da03d1250123fb30a57c66b94e6d27846110c4559f30c3c58c2d6fbee051e2
serverSeed (revealed): 0x7910132cebaaa72c32f7f030311d45af938f3359b2a2c51bf1c532348ddbfeda
chainBlockhash (revealed): GmAXmBdzjKcDUaq2dwQ8CEekpSAAeDMQVWscJegbugjr
chainSlot: 457604566
serverSeedHash: 0xee9b3d8cae484f696f16ca5423d3ca0f2dd5a82197164c127dc5e832f7a92106
clientSeed: 0x87a8885033e133a2275b39cdb40382f406992bfdb678eaf97893e080851617bd
serverSeed (revealed): 0x6031582222fc84157565d6e890771bd048d534ecc02c49c0899dc8763d34becc
chainBlockhash (revealed): HhDWghX8jaktPMoRBJGGPxdEhER52KpRATPUGpV9rE83
chainSlot: 457603177
serverSeedHash: 0xc048d83153ca207c34498dd44b113c1b6ef4af6c633bf57badd571df6b3941b1
clientSeed: 0x589abe855a558a799342e0003cf28fe18236b10eebd7eedb84ce742a4134fbf2
serverSeed (revealed): 0xde24730ebf318a827d8c026d26d37ae6b124ae2165da517c7ef24cb28182e31d
chainBlockhash (revealed): BE2MtzjPT6jh7VKiCApUTbWttnGPNTnPQWdtJBueBFpF
chainSlot: 457601776
serverSeedHash: 0x47566ae2889e31b177641e4ac887675eb695712fa4b38f6344ab383e07849be7
clientSeed: 0xfa567eac0627f39b461d0fd1180e1492d610ba927ea5ccf37bc4a2c36fca24fc
serverSeed (revealed): 0xda331840f2d9451d397169705cf4b757d5def176da2f0c577cca91d1ed4d63f4
chainBlockhash (revealed): hydnB4374RHwFH3dJckBygvJP981NajkF8vvAUf2Kj3
chainSlot: 457600383
serverSeedHash: 0x589170849db2c2ad33e236c077bc218d9b1dd36a28336922311ef4ad3298ede5
clientSeed: 0x0c63edd6779ee6ae8842497dc48d6669fe3158ca2ff015f18d951afe463292d9
serverSeed (revealed): 0xe26d3201178111f22876ae8e96843aa981e121403c4705cc7b7fec0bd3792501
chainBlockhash (revealed): DPYY6AJKRq8QeN6aXkuNp23ZFNcYhDGkPkN99pDv6Wxp
chainSlot: 457598993