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): 0x14f2b39f42f9e7865ed65ba7cb10f1f3141787b3a94da8daa0508ed1d347d2be
clientSeed: 0x073513d3e5ccfbb8480f8dbfcf688b46aed3c216f22554e637330aa9d82c344f
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x98885846d08990270c1b30f0bcaea305ac46357eef9890c267c50558ed3607b3
clientSeed: 0xc225205c73013a112a94a4bc3fc7e8f4c9e08c95ce722dc3b4ee1717bf7698ce
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0xd449f4dc8f4994cc7c58d5ee3451cc40a65f0076a822926c1139ddd40bea0bb3
clientSeed: 0x784fc8db8aa524dc91467d096b5b9c554b245854bd8a025f940d258928a9b57f
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x1de14308e3055e32d9036594b402fa7d4b23e064f19f926e2e66b8e23301aa1a
clientSeed: 0x19af35baedda7731037af3be6faf601530cecb36afc236f3791b09e792b82184
chain entropy: not yet, arrives with the draw
serverSeedHash: 0x492da7a519e6fcfec461b22510205c8097ebfb2bef4d8498723601a5624ecfbb
clientSeed: 0x312ef6de704f0b54c95adacc1ca58e93b1ee458d768db21d3bcaa766b4808467
serverSeed (revealed): 0x1e0d5628d8201f5c919641e03ac3f4911f712616fe88badc6db8176187e3b9cf
chainBlockhash (revealed): 4nMjgeuZJFytjW5G2noJNkMbSo5JuxGGq7N9VzfJpXQ1
chainSlot: 458512793
serverSeedHash: 0xaf16219d1d62e4b4f76d5331fdd01f8c116e281ef263bb9cbec593ebb9fd6ecc
clientSeed: 0x1a99154353082a2dd9f7bd57e125c5a8646580971b2f119513fd4c481713040c
serverSeed (revealed): 0xe8af6f15f8f65e5c084414eaa1eaf370821e188abf63e80820cc7ef041ce73a3
chainBlockhash (revealed): AzpKvVTKmnh9M6BwVYatNAeWRJia28o79skL6ZWqZUzu
chainSlot: 458511417
serverSeedHash: 0xb0f4330f27f70e729439b48fe19657684171f090896a707289c692fe138fb2ba
clientSeed: 0x45c1d998ae1dab0c8881363a75ee28c3432e186939ee70a4f1b5be39e2b87d47
serverSeed (revealed): 0xe4eb2365d142d00f3a9ba7f5e5430e0264f3eaa01bf9c8fd1947aba5d36be294
chainBlockhash (revealed): 6MPahLXnQ9pA2KDQvxhU2LSZQwMM4w2u2k2MDPthqGx7
chainSlot: 458510047
serverSeedHash: 0x2a8dea3bf27b504b296c694c5bce19161ce5e0dbcc1229d5d7f6e7ba75c23c5d
clientSeed: 0xc3ab5499b34feb62c645b0d5847fb03388f8e5b37f5469ede37f3344334fb591
serverSeed (revealed): 0xaec8929fe96ee4d1122a35101f700f382e820cdb9b8eb2d2b6de157dfc16118c
chainBlockhash (revealed): 7mB7L9kboWiEJEPvWJdrHXX3WJdisRjxVUdDZakrDhcP
chainSlot: 458510046
serverSeedHash: 0x34a5a2b600f745d76b43f590803e54f64e436f0d2dcb6dc1a55539dfb3ace0e2
clientSeed: 0x9e402179a99131f8ee2670d9c7b2e4c1c1dc008c3bd3b76c21139f1fe5797048
serverSeed (revealed): 0xa77eb8e8c9ff3fc48387a00938aba8337faaaf66eb6b24e50a6c3f57c23a940c
chainBlockhash (revealed): 5LC2uNSNqfTERoP8wQDgaP4igZ5EQpYk791jh19fUUYF
chainSlot: 458508678
serverSeedHash: 0xccb007ec57c4f2a06c7b831327e6ed03b2b15648ab054aded337593dba781bbc
clientSeed: 0xac2962cb0809da5cc9883c86d09a89d3fd056c9c2f06ef0a7958cd3b91a37a88
serverSeed (revealed): 0xe2aac906f3942d63831c7d73d2017055c1b16b44dba16b49e1769dd25829cbd7
chainBlockhash (revealed): 141GKpBKNcaVSKqNgxJYHS2ufTR4XkgLyPxHYHAFE6hM
chainSlot: 458507294
serverSeedHash: 0x75219daa8dc0281e18f5ab95c26335fc3179955d0f2682a0dd10ca6b380f3c2e
clientSeed: 0xa18d4ae33cbf3207791c04413c76843c27586d1f22cc20d62c9a50efc1d28e5b
serverSeed (revealed): 0x8fed5f7f9d8826495012e97a777630b539c965a5a4bf4c1ae80ea04b2187a2d4
chainBlockhash (revealed): Bg5Kf7dWoexzGn2vyMyJrCGKQkumJXuQ6CLL1d2Dm1MQ
chainSlot: 458505902
serverSeedHash: 0x1b2d5080f20f643963b531bc744ba3a66164be5b21d410fe7a3482733828af4a
clientSeed: 0x23c8525caa3337230b7b15fc2d772bc45fa56c58f766f8b0b99715c7de0abc71
serverSeed (revealed): 0xab78d031a9a33ba4b8dad3af97d4ec57164636fac952661d96ec0ef468da8fb0
chainBlockhash (revealed): GxuVXRkX4BYbC84YbuG6HRxQ7WHpnjSH5rngyV3BwSkn
chainSlot: 458504504
serverSeedHash: 0x53c6c7d452ddd29772bfd7c791f671a4c5619367665f6221daebdf49f6db0ad6
clientSeed: 0xb8f6843517892e6bc6e0a7ae63e6e79dec20a5075fdaf717905e81b4f33fe5e5
serverSeed (revealed): 0x51be38e09ab1124d0bef244517d3c2967b4766b7c323f5be08af38d0caa18e4d
chainBlockhash (revealed): 81h3nL8o46f1mL2rFg2tgFtNJnNbfgQFZgvDb8pz4shn
chainSlot: 458503106
serverSeedHash: 0xfa646cf801dab38af9f5fa615f5de986db7527a1268621eb1bf7ba7b1c9c65b0
clientSeed: 0x3b73c5f603e78c806036e6e74fc7e18dabdf677bc4f6b6578293783c9b216649
serverSeed (revealed): 0xf86464819f2f8c66d1031f36518d13793d138dfe332113c7b30e1670e2266a23
chainBlockhash (revealed): BCCGeJNi3Fb1gdfmuv7br6iFoLhJBSoGJkze9MoudmAw
chainSlot: 458501719
serverSeedHash: 0x27ed30e07bdfbf409f773768ec3e0bf563d8a4ccaba3c7c3ba9bcd08cbf6d3ca
clientSeed: 0x4fcc0aa352fdd7f22c047547d75afaab101d13badfa3aff779033f4debc5e58e
serverSeed (revealed): 0x5299b5cff4f829ef3eaaa91b1d1c794f9272470c59aa899a132c79781320eedf
chainBlockhash (revealed): AQQ9NE3A45QVq79HWFrYoZJ6PYzMZ77t3NUmzKt39sJY
chainSlot: 458500330
serverSeedHash: 0xd45d9fe4b3316b51884026be98557aa551f512fff91205c74e6c5c270a57f3c5
clientSeed: 0xf432fc0f7e3f8f6750b999e1bdf119bac8ec32ddcb444833f03060487a335ec5
serverSeed (revealed): 0xd9501d9c771aecbeaeff5b28cf7e5ea8b267eede792d94010a36ea82aecb4aab
chainBlockhash (revealed): HRNYkkopRwa2AexSm5Z6QykFA5ndq2MLo91uMrdiEe1W
chainSlot: 458498948