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): n/a
clientSeed: 0xc7232ae2d71047eab03ff5d11ac53807851945f1f3754091bbb5f13cee458411
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x7591ec4d1345de1f0409076449154a9bda730fe8cc1b78b0ab9c266ac98974c2
clientSeed: 0x2d4980a83e5d62b80ab5e9d3cb6fb7d6181e2d026ee0365f5e97164344ea655e
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x0cd8a3fdd8f77e0a9eb76230726ffd1e2843c87411f4d83a2d58ba791a1c265a
clientSeed: 0xb88f05779b1c4e92a0c92252ddc6efb2fad0c85286745f8a4a0d882da666cc06
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0xd141a9cdbb4df966a65cb0c74863245d48c910c0b171cf2afd18e7f0c1bc3214
clientSeed: 0x5131b2aa68e920aacc3e9368129b70d342ce7bc6b0dab05039d62e1b63f33b81
chain entropy: not yet, arrives with the draw
serverSeedHash: 0xbef2d343796ff5728d09f2ccb72c33cc751116414307e3d81d3ec731e3df376c
clientSeed: 0x19366e4df599a35ca8a4cd36a034d3fd532fd6e3a10a62da28d264a04fbb7154
serverSeed (revealed): 0x5538a24c79011ac5a52c0bf57fb8bf2517639f50b739c8e2b492ccff186bd706
chainBlockhash (revealed): Gp71HocnCP66da5LJYEyToHYHikKB2TbAgMB8SEticQr
chainSlot: 458077133
serverSeedHash: 0x3230395d99c6a863971c438200da5d252eeae8ceb58adb61ed7188d055be98c9
clientSeed: 0x0e961d8d6f5c39f26e15a3142df95d7b0b966bf7a94ad2baff6015679a3b6b93
serverSeed (revealed): 0x37ce00aaec56264d12e615c74813eb1f1b6ba33f84d286d3a13d44eb06ddbeb8
chainBlockhash (revealed): CGH5i67QUbk8PanPzVsCGEGipo9wTk1Nm1bLHakErR8G
chainSlot: 458075743
serverSeedHash: 0x0f29c11c09c6929775837ba56f305b7c8c1f20bf79957ef95e18f654250124a1
clientSeed: 0x52993c33d7c841f27176312cceab1a977c7ed1cde843ce61450f73d893d9eb25
serverSeed (revealed): 0x0368928e6bcf35690a1d07b7476e4b8febb8031981bffba1a8df107096433983
chainBlockhash (revealed): HCD9gYdYEFTvC1JVMNc9hWXDGUWbvSR7La5Sgw262gd7
chainSlot: 458074363
serverSeedHash: 0x945e23e661b67b00dcb981cc25ec479e24970a0a47f2f6ad3be8652ed50a8de4
clientSeed: 0xaa85a74a6b92a6889af0e03db5a4edae54b0a4db6ae6ba11d99c42ac608980a7
serverSeed (revealed): 0xeb0103bda3d6ce42364e30666bf65e040c648e99236332da5538ae09faac5986
chainBlockhash (revealed): 2kWC9mXUUgyzXciTQLMnfmbcFJi9VdkhKwHjE8e5j989
chainSlot: 458072977
serverSeedHash: 0x8a464f277ff13f16c2ba2fd32d612e5f6178efc814c6bce89120d78e47f32e5f
clientSeed: 0x1f7e8910593e902effe9753833ba0cdb0b999e6d94bd1216fbb1ed1e12bf1b85
serverSeed (revealed): 0xaeb21faa8e5225c2b98b95a608ad71b185afe9827543bebc5d4635b8b5e615d7
chainBlockhash (revealed): DDVqdrs11BgpXiStJxqw6pGuwMDALK3wBKmD5gZyJqwA
chainSlot: 458071590
serverSeedHash: 0x0063026c1f40fe011a292d566c773d4fc3455046a1b8298937e4c27ba3b81fbf
clientSeed: 0x6a5ae599f6f03c71180b6eb8cceb4d59b26d2592531f5f0fa27a7f17ef3c2be4
serverSeed (revealed): 0x64731c7f2c5d238a131bc8e6c0cd2a53c07eadee4b0176c38c3ec05181b86a9c
chainBlockhash (revealed): 4DEuFyXdhwJKb74SUgc2DFqtuKJ2MRLYK2bQV6nwAWQF
chainSlot: 458070213
serverSeedHash: 0x7940f90821ad52ce85da01cbd38a544322f164fb349369652bb4fd46060cc4ae
clientSeed: 0xd369e2dfe09ebde1a0b467ed0ce035ed873376293b7bf1cd90c5b63b1d8c0fec
serverSeed (revealed): 0xbf35189cad83e52ff953d519e604cc9993441e613b3ab324e64e3f0542883bf6
chainBlockhash (revealed): A6yo5MgZUnZVwFBxBuf4X6NAMvztnVJPp29XL3GUoA9m
chainSlot: 458068833
serverSeedHash: 0xb226248ddfdc741d776743e1e4a1533fb051fe5d066e0f9cb7a2882e40eb24c7
clientSeed: 0x519db113edecbaa3d9960748641fc2c1168f2426bf1813d99d3f88b3dec65448
serverSeed (revealed): 0xb12ed6d6dc78a8f65c969063c015d0b64c689d5bcda7c5734f9722416a89b284
chainBlockhash (revealed): HYVF7NXDoqj1VGbFreSkDK7HFKHv2p4NqW6fEChXQM9R
chainSlot: 458067455
serverSeedHash: 0x66645ce0ff6ba0c1b80041351a774d0ed4a4aa82ac22f22f253cbd9de3446492
clientSeed: 0x2ed0a357ccf57ec5c6eef15d1265a808189d2a2948837d49c86f4a7fb09eee48
serverSeed (revealed): 0x93fab6007a9c52d906b5dc7d84aafd36a74747ee707013204993208de8913f23
chainBlockhash (revealed): 6pMjJaMJ6BDDEhfuBu17gtvJyN5HX91a7MXMjodgDra4
chainSlot: 458066074
serverSeedHash: 0x5afceacb6d46f8aa97bcdea947cc719157d066132fd74f2446a69d2709787ec9
clientSeed: 0xfe2bf2089a17086ac6ad50d1a3f93fc7d61ced5c30388812cce50c7bec6a64a7
serverSeed (revealed): 0xaf1481a9e1694e4559f52db6a515586dba13e7e0a98ba68d9e304528ab44e4a7
chainBlockhash (revealed): 9HbvZhny8Uc5tGH3ZBE9aA5qX8FmvLmyPTCNyqdis9fs
chainSlot: 458064688
serverSeedHash: 0x27ce4431811207134c7d9b76679ca86629ffe892a8fd704a280158eb8e8790b4
clientSeed: 0x54bbecbde976cb715dee3e1f58f7248d2b26c729aec54afe52fbe2d22c3bfc64
serverSeed (revealed): 0xc7b7ce74e8e635c8203c4bae1a592f9779b8519d35903facd537233c676286f4
chainBlockhash (revealed): BVsHnuGgAvxweXZWrrHYMfnyPGRjCEsgbcLZS2HNBZWV
chainSlot: 458063292
serverSeedHash: 0x6a5b1c1728b18df6331373ff0f1ae5cc15539e54c7b34b63db693233bce50f82
clientSeed: 0x69480c98d36b39149b7a83894de6650879c95387544365e1a512e1eaf9c6958c
serverSeed (revealed): 0x6630753d796c9cf7c901d6f5c3d92a5b40dd915608217679ea365552ac8e2f61
chainBlockhash (revealed): BZJREGyvb1Gn5nCgXFDhn5nrCJazX3aWASHrJGV1JP26
chainSlot: 458061909