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): 0x24d5e14176236ff7fcb2d4db69870149192d8369adf799313bff22ad8d10f7ef
clientSeed: 0xe7ee2dd6d3bc1b68ccb2f80429ab27cbe9d8c0870cb67e94d0f69f68444a4120
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x8a3fc52019c8886b9c1863afe09c8ac1d8151ef4ad7789a13062d1ce6a4fb708
clientSeed: 0x104763734b4dd810537ee7ddb29fa08a802df4afa9ff533c2db80b32bbf3fda8
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x709767ea02701eacccc8f13b5ccb692bdb2f767c18ea1465dcd58d6e89e20ad8
clientSeed: 0x38fa167420db0f78f8750e326775fd52a09cc738f83eb6071a3d45cf444401e7
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): n/a
clientSeed: 0xc7232ae2d71047eab03ff5d11ac53807851945f1f3754091bbb5f13cee458411
chain entropy: not yet, arrives with the draw
serverSeedHash: 0xad93f15976f5aea8b6d5340443b08fa45a57dfcaddc7795c1e8a62bb7eae4ab6
clientSeed: 0xa0e688d03edd0b511180f1eba418c58b76eff73f873a3eaa2f1df3f4d67edd4e
serverSeed (revealed): 0x70d76ff2387a233de251b59d6cb8d87529af4242f728c0705e18bdd19c4ad1d2
chainBlockhash (revealed): Vb5dJhenYS55WpcTaWgyqkBvKnoaqKAiEhVnmTU66ef
chainSlot: 457777883
serverSeedHash: 0x79fa0fa8e5cd27bfafde2ee6a3a49f74af33bf58664b8d1e6029a75aa12479e8
clientSeed: 0xbb48fbc6fb4bad813e4ef72023b5301f3b82ec51585f4fa924c6d0caee5f185f
serverSeed (revealed): 0x2cd1fcfaaa9e94e00a651bf7e9f048987f49273ddc57428cf224404074191668
chainBlockhash (revealed): 36TKnAAbjdj1AfVVy2ScWrNiu2A3x1t9FGQoVQHS8BPd
chainSlot: 457776499
serverSeedHash: 0xa22e7668dc425bf550e296fd43b1e6bdcfbc6a422d078f7e2ac2dd2ef87ad60b
clientSeed: 0x241d7165684b45b6868962df23a70d6d3b3a865d31aebef3a9c2fd9adca1f204
serverSeed (revealed): 0x2964b4499e781a7cdea156646a89d9ab6ec4b734e55e92f0c8199012e22b70f1
chainBlockhash (revealed): HVcAaG5yjMqrapzPNMkwc87AAXgx2TVSCWTTsU7BdAcX
chainSlot: 457775113
serverSeedHash: 0x1e6e5efcafd02474d9d5e6da2a5e0abffd2e2a3012be4746b65b039688bea9c6
clientSeed: 0xda3c7d104f07a5911cebc7cc18728a329deaf04598f6e85d54a76a67d9d22251
serverSeed (revealed): 0x77f065ee4e3ad84d200ee4286e46e3e9f810e5834d814a6120f58da69cf542c2
chainBlockhash (revealed): 3d7B5Msxz9ZZBZkZmDWmPx8kFUaHFKth8An3d2nPC9N6
chainSlot: 457773733
serverSeedHash: 0x774a3651d40d722b68d68c08bf8deb210fa1177b79bd3aac3526778fe7db0fc9
clientSeed: 0x8b3ae9bccdf1c456858ab614b7e18395645d42f49d49357b161060ca895463d9
serverSeed (revealed): 0x2b0561efba487ee6ed35ff539f667389c743816b1cefd313b921143c72847362
chainBlockhash (revealed): 7ybt82XeVKbB16be1CW5SsBJsNHZq1ZtoVhx8QYaSDvk
chainSlot: 457772349
serverSeedHash: 0x9eaa798bfa60375f9c3b4e166101d75e0abdaa26a822a6dd831c0e781be11511
clientSeed: 0x84e2aa217761bd4b0c26f6f8f4aa96b8c864be563aa99345903731fcda621392
serverSeed (revealed): 0xf86c320ab937d0784163c033baa1fb78f75b57100b3ff5fa7c4b381bde0c483c
chainBlockhash (revealed): CxBf4GdPLfgvUsc8Cf9VKKLUZTN9VkGPiRCMYkyKQQZa
chainSlot: 457770954
serverSeedHash: 0x9160beafccd3c88e92e7844d5c58941ef51b95958837e9ad1e388a8e4a060c8b
clientSeed: 0xde8b04376b2e759d66b39ee12457481210db7eb4d62bb3d3e307b7823eaee297
serverSeed (revealed): 0xecf4541ea040e650cea6b39aba4e402150c2665750d50a2c32483810a9a2af8f
chainBlockhash (revealed): FrRNwyczytMdQMVbBJzgFDzSFwhpMRWKszZpFWoweqCQ
chainSlot: 457769581
serverSeedHash: 0x85d34c832bf700d28ebd525cf7d3a55522c4a8edc9ac51ed03078e1ac234c591
clientSeed: 0xcbf7fb964ea6d6ce3d1caebd6b9c0f52fa506904fa9be070980995276158fdff
serverSeed (revealed): 0x1bf84db5c6a1b2bf4886cba60d27a5607d4353a5b73741655036f84490ce74bf
chainBlockhash (revealed): EDhpv8cxB12YGS4pDUkSv5XEEp9hXmhhVwHVvz6ZKU6N
chainSlot: 457768195
serverSeedHash: 0x90dc956aaad29272da3ecca754bff0871ba95fe86d3685671bd58197c5362d55
clientSeed: 0xc9aeb9e956ebc7db20fb06519d3ea8d7f794f61ab6ce76afa66e7e61ea4f470b
serverSeed (revealed): 0xf0af9899f77bc46939a567a64490c2fba850523c6b50197f778b639dea0e66cc
chainBlockhash (revealed): 42SgNQQ5Q8WK6zXDkHN1wqGBFhCTduz82dL7pZZhhueK
chainSlot: 457766816
serverSeedHash: 0x70e0dbf06e18e0271c1dc92622216fa5f247b1cde8088b103e9ae4f648a43f52
clientSeed: 0x526fd6fb9de7a5d3249caca1538597d4b62c1f0e0ae742a88310386f254260b4
serverSeed (revealed): 0x2a2989edf73536030ee056e466e8f2866bcbcd99b8b374cb07713635e3612452
chainBlockhash (revealed): 7pQ8baWNrggsjkHgSS3kbnWDVnKdCvb5VL9gN4SrQ5Kf
chainSlot: 457765444
serverSeedHash: 0x9314e2d54f56ee4d18607722444f5f4d7cf54d4d83c8d930ab0065f9f6570781
clientSeed: 0x6b38aa218d497db72eef091a6ec101a9d7d882983ef14f64cd5db9913fb752b7
serverSeed (revealed): 0x3c3460973fa6b869746d51d954998f7a2260577bbdd837f23ab5d4de228097bb
chainBlockhash (revealed): HDKXVnmpd9JHxhCHX6C9cB5amNfSZAC3PNPbjPSkXXcF
chainSlot: 457764053
serverSeedHash: 0xe426a10ed9e59a868034747688fb21ac24335cf5e13565ca895d79a640b283b1
clientSeed: 0x0a4f16402624fcf0d02b79c594fd7ecdc10801da7e37999f001d3fb829022d0d
serverSeed (revealed): 0xd5c1c2a7af81b26c888364e0ebba5d43246904e45149950fe3382157b1ed95b9
chainBlockhash (revealed): B7JVBWoqQ77CtUySGKHihDKBQkDNc5mmTUK8Bpxv3utf
chainSlot: 457762650