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): 0x74d8aa4ed68ccf1d5d01ae1a2393e5cf3945a555fc00014da3ff726b04317762
clientSeed: 0xd03d6c6f7ace0af258a387164786bcc1191f2bc1b74dab8f35edc10a770f4f12
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x234b621c4fef04f872e16f538ee1e076142d0b326d8114ac329cd58c992fc1a9
clientSeed: 0xd77825946e37800b666e0e37e8674d8d9ca83080ec77e18b448a535434f261ae
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: 0x5fc1c682f74306aafd0636aadd8dd5ce3fcb47205b41bd83cc7365265840a7ea
clientSeed: 0xd201bb04498ce99d9b42b21e409c0a4b4987594eb77e6995dac0fe6f750a725f
serverSeed (revealed): 0x4516c0e5a4a7ce927e6553feb6d4cc20040ff7bcef9842a0edbf42d1cfa0d475
chainBlockhash (revealed): 7wryd7P58pv8QGtCtPToF6Nq8XBosQkPhgzuXEwskNww
chainSlot: 457436415
serverSeedHash: 0x5052d563f8d96a534d4664b1ddd80792bc252975973dc7093b189fb0dd0e6e5d
clientSeed: 0x46b280e6790ec62e20ba55c019c656ecf65f671e238aa88bf180771bb6fa47a1
serverSeed (revealed): 0xefc110e3fa8bbb3297ccb3c6fcd336b9dbc16f896f23ada7c5354766d12e2fc3
chainBlockhash (revealed): HoPnYrRGdunCR8nPKbn2FH8XVCeZaA8GcKe6z2tvAyuQ
chainSlot: 457435029
serverSeedHash: 0x7daa5fe9a172b10a3919d49a8f449cfde16c7426ece0a80bf0895abdbceef700
clientSeed: 0xc859b326bd043828d7dd2aa8530516ae8f7d9ae4018643142291fc9c05237f03
serverSeed (revealed): 0xd06d4e0940d863b3ed6fd62787f5ca8a49671677d3adb028075985bcae2eef3c
chainBlockhash (revealed): AnjPP3oUY8k1QHKSwAoisVag8EytFLUDVv9CK845cz8u
chainSlot: 457433634
serverSeedHash: 0x25a4d63f10353a6277372301069c49dc47922f6fe5f3720c2b9473cb91588206
clientSeed: 0x39cdb26c42f0e21c78a6362fef3de9a3d53a2147f1d1b4f216179c0fce6ffbd3
serverSeed (revealed): 0xa7746289f9351249ce0c1e03d787f50dc0087022a2fafb5058dd51639a5c6f97
chainBlockhash (revealed): 6Vj2zxqokgnmQConWBJj9duptoJyNZvEdfsQzxfLaKgj
chainSlot: 457432255
serverSeedHash: 0x6f99680632f7fd89374bcc585dfcd4e1b498a761f7c569c9a9f300c9be4c42ff
clientSeed: 0x690774a0a152c5d9b40b8ee51a484e0935d434371ef6c31a10a3c60551a8527d
serverSeed (revealed): 0xf336279e183abe3ccf478d223e3770cee0bd148ab14299e7a396cc257f0547be
chainBlockhash (revealed): 8s332KgcvPTUshMJkzQw1UQHwnxcnnjxDvmMfJnimJHj
chainSlot: 457430868
serverSeedHash: 0xd3b03debd2bc5c2ec8802af15cafca3e23e26d6064e31b21b8ea14d2613e97b0
clientSeed: 0x86188312cb772bc71d4940b4b19f94df2d46c4a4d2664965ec3d14021656bf3b
serverSeed (revealed): 0x66a666b696ea53bc193614c471faeeef65bc95bb9891cbf5a28eeb6b691becf3
chainBlockhash (revealed): DRxaSoxo3hKGmcZZvKezw2ZiLxHaeq3YKC5XAygsCNyJ
chainSlot: 457429496
serverSeedHash: 0xa9f63ed7ea79085369d7af301a7d15071ca7609fed6ca916d67e3505b0d11ad6
clientSeed: 0x57d7b156c552eeeb49766f92d4a1ca748e1c1506564008d007723c1451b67cf2
serverSeed (revealed): 0x67a127f5ae60b275ce9b601af69c29aeb56faac6a6c83fa3f65d5ebd1070940d
chainBlockhash (revealed): DRxaSoxo3hKGmcZZvKezw2ZiLxHaeq3YKC5XAygsCNyJ
chainSlot: 457429496
serverSeedHash: 0x6ee8adb58cff0377d104ac905a978d21ae504aebbbd3ff0fe6312efd1e93b1d8
clientSeed: 0x66b400bb50281bad5b8adddac4dd465c4ccfe216e1cd5bbdbc852ca1fbfe5b63
serverSeed (revealed): 0x00b74ec0d23d456158a610356309fd165e040ce2dc18cb88af6e909cc09e629c
chainBlockhash (revealed): 96qE6vj2Mk3jFw3wMhz3Gu4T1cUTNpjDRNg5VNasMs83
chainSlot: 457428097
serverSeedHash: 0x6dc12bd190fe44b37de36ebf47341f7141872a07f40ad27c49b44167f6e60449
clientSeed: 0xdcb7d3cb9ecfb450899b95232124505a11ba54e9972e5042046c2b4cdb2173c0
serverSeed (revealed): 0xde233d218c466ea3d076dee313118339cfd803a7c4dd2e5bbcc37b2e8d39949a
chainBlockhash (revealed): 4s1TvmzasfJiMuwXttVV8GjUnt352oTxmJNZABAJNjef
chainSlot: 457426728
serverSeedHash: 0x640d51322c3c065010b0ef74c90be585bf9425d0987ba8dbbe51770a82d4babf
clientSeed: 0x539a2ce541795da80670f4e3d3acd3cebb63505ba6090f09da5109b47066a54f
serverSeed (revealed): 0xd03a17b615c13eb9fc301facd8f05275d63c5eaae3f4476fd4c5a14273faca8c
chainBlockhash (revealed): 21S7Hh6kPKPmCFf432XmgrLepxFKBFUvUfuQ7KHJoVwy
chainSlot: 457425354
serverSeedHash: 0x6b2fb5ea70974e934fd4d6a183b0668d8d2d1cb200d59b9139749f243ebff34d
clientSeed: 0x22e3c853fe1f425c5acca6ac9f0b2ea14b5ced990e0a746ab1aba26ced9f18ff
serverSeed (revealed): 0x44b48a1e2db8092c1e0ccda9ed5e51bd09f012b588c751a8e81b9a38fe973275
chainBlockhash (revealed): AZf2A9VRasGt9nS5TcfTH2CfkaYDAaPRvGeqkmemwfQX
chainSlot: 457423976
serverSeedHash: 0x3c813f5ac7304193de0230e1b11521ca7db0aed00136b010d8c8657d94a62780
clientSeed: 0x82435bb125409437b4c8a9915aed61181a93249f00591627662f5419c37ae75e
serverSeed (revealed): 0x1367ef4a807bc358973f71de9d6fd2ef78f44497ed144c22dcd26995fbf51c14
chainBlockhash (revealed): FY77Bw3PhMdwxpqeJMsRSVhXFrjoHFKZ185HR1E3y9DU
chainSlot: 457422596