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): 0xefd7dc2c43e485fb05a23b250a0f0da7daa0515b35aded428e21e463972c82fb
clientSeed: 0xc88ccee47450a19b6e344cab2dfe232fe03a2482d750a7785e129c35a98acb9e
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x0cd3a12cf486e400751dfdb438e1cd2d633d0dddfad0ffd1f02cb449d6f483fc
clientSeed: 0xcc092f5e88b9f3fc9c505dfb423055302acb82a91891b4caaf65dd1438f76e34
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x070dd2a18ce55b6c2f247441fe7818e17ed0d9bd8bcc0019bb1216a84218fbc2
clientSeed: 0xb924e15e3fac5b2dc63e559fa237449e343dfef7b24799e56011630cd32f3a85
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): n/a
clientSeed: 0xc7232ae2d71047eab03ff5d11ac53807851945f1f3754091bbb5f13cee458411
chain entropy: not yet, arrives with the draw
serverSeedHash: 0x1aed12687cdb5b07b83e51e4730b07089aafad98ab063ff11aea646137cce76a
clientSeed: 0x0e163e1e3a89443689acde7b22e32d820ec71c2292df0984889c59d7d6296509
serverSeed (revealed): 0x5698fd2f654b7ef367c1e279f6532d0a0752cf5668156df07d1d266db9ec5f4c
chainBlockhash (revealed): EfzUcpzk9e5tvRika9kngzMe3a9NiuUGLET7ErWWZhU
chainSlot: 457376763
serverSeedHash: 0xee6fc328f35f68c8a513f7ac8f3cd84331bbf84ae62f6d0c8609660709192c26
clientSeed: 0x5b2eb2ab5e8f7aa7ea2dfb37ac1659bec17459d9622bc3be8d2abfac41f8b4c4
serverSeed (revealed): 0x7b5c8f2c03241dc44c2f361050935a2789b1938cd206a569f9e142239660c1a6
chainBlockhash (revealed): 2h3jetgTtrqrz9s5G2fkKM19HTe89KcUhm4qYw5pZfNx
chainSlot: 457375388
serverSeedHash: 0x4191853ef2a852efee33886e6b40cf11b3c4f7e0bd3baee5de5a433717384fa7
clientSeed: 0x02860ec87a1da0a3b30930b08827484e079abe14f95ff8356fa798d838141c8c
serverSeed (revealed): 0xc968fa69ca9743c040676b84e18491a50b12edde14dcc4af349a7591c2b5233b
chainBlockhash (revealed): 84UEq8LxMJ7xiL8bSHbbhD94nSd9YvK7UYgUqaSsgqxB
chainSlot: 457373996
serverSeedHash: 0xf8873226e4fc91830a39e076cd59dc94acf72a8aacfa00a7a3568459e968f1ca
clientSeed: 0x42d75e8e44d3c7e58e5a4480a1f4a14ab9ddee425d8d3020c6a699c37950d67f
serverSeed (revealed): 0x9a08b95f3b12c66cf33f0cf67f77ae600a6adb693adc9b5684dba8fba2eb2d6e
chainBlockhash (revealed): D7EYqS14fBVQyMEvobCey5t3KTtFhX8tRBGVefg3vj6V
chainSlot: 457372619
serverSeedHash: 0x8fb5c9960e8dec2f0d04adc246b4dcd3d0673ba3ac73fd148fe5836df766be2d
clientSeed: 0xe6f476752b5aaf2f5645f16eb9380309114a3d001fea1cd514a7f9c5e869a040
serverSeed (revealed): 0xcc87a6c4c56f0ca8dd71ebee178a9ced204389b830f0e04c7e27ee23319d6c4e
chain entropy: none (round settled before the upgrade)
serverSeedHash: 0x2a985096df3f81e7d066837a22d68cded24354cd4e8b7011d678df0a3ef7baa3
clientSeed: 0x930dcc3423fb47a6d90d31cd28ca255cc9901509919d119214b890bcca4e4956
serverSeed (revealed): 0x03b667d19f7dd6273a68471883889ba154324648e4b260e4968458c1e29e09d4
chain entropy: none (round settled before the upgrade)
serverSeedHash: 0x185171ccd145c0b93825925c3db2c0e3ede2d1857b33f04d3c5067967d7f083b
clientSeed: 0xca36627d24264f3de1e996ea4a8db59ccb37f1597f067e938ed059ccf0542b1c
serverSeed (revealed): 0xbb6da7371f50a0b71ed2ab57711178aba764c6252ecdba1fd63ddc7dac9ae88a
chain entropy: none (round settled before the upgrade)
serverSeedHash: 0xb0e1ffbdfb5acf1c34d90ae87b594db0d5d41d2fd3a903eb7a70b3bfeb7a5506
clientSeed: 0x073c48a13236e3af56df2417a0eb91e882e265db814fba01da25791dbc403eed
serverSeed (revealed): 0x09c593c9e32ebfabc661c285b5ce6175b736e06ca7639cbea39b7bb539114beb
chain entropy: none (round settled before the upgrade)
serverSeedHash: 0x926fc8d10b3fd6df5124adabb91b2c8a852119006adadcec6077dffe10f32173
clientSeed: 0xd5f4cb3818d09dd92592c830e477c53890d0eb74b6c5a4a252e5dc286cedcf77
serverSeed (revealed): 0x4865569aece40c593f687987695c44a18b899f7fc13c78b85675258333971766
chain entropy: none (round settled before the upgrade)
serverSeedHash: 0xd4ccfb4274110ecdb3d0d8c874544c6b94e998d5c9da0104479e12aa0920bafa
clientSeed: 0x6a89adfdc601c05446437be98aa92eb8514067bd2f3f09ac97336fa3b597101d
serverSeed (revealed): 0x7a33f18c023b843803d8caa6fe7bf4ee4ad5248369253b6c1857835318470f31
chain entropy: none (round settled before the upgrade)
serverSeedHash: 0x8259d8bed7193554b6d1fd6f16492b7e4278118c3d50f05ff35e68df97a047ea
clientSeed: 0x6082fb99429d1b5d2511beb8b5285ea8e46b48279bc772f2e6f5345819c942ab
serverSeed (revealed): 0x6051e7f51ec761def4a98609640a5a733dc065cbd67d02510aaa87bc1bcb2d16
chain entropy: none (round settled before the upgrade)
serverSeedHash: 0x38d82ffc4f043604661dac4628f97956e0b5ad2c6c0f9b9ccfe0e6084bda4d95
clientSeed: 0xbc4eacae4810b920ec8accd0150d1b4dabae7d97ba5626398c33e03d2b161efa
serverSeed (revealed): 0x4889abcb032a44cf163c1db6eac3262a0a11b8c068cdb1c78926d7a4b80e37e5
chain entropy: none (round settled before the upgrade)