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): 0xa29847d85cdfed3994fd691f90fbcd7cb383d15c5d1c287004618d38ef71c8ee
clientSeed: 0xd8e81b9a9251ab0f07f9b1008bff3ef6b6c39394a90c2113db17fd98616d4e98
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0xda466e013455b2c1ccf70a6b29605b2090b769a3d96383dd0ee4c98b1d8c0de2
clientSeed: 0x57c2ed0e68cad1554da86699062693698d1ad416fcee2a8adc7687199bae73a7
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): n/a
clientSeed: 0xc7232ae2d71047eab03ff5d11ac53807851945f1f3754091bbb5f13cee458411
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0xd141a9cdbb4df966a65cb0c74863245d48c910c0b171cf2afd18e7f0c1bc3214
clientSeed: 0x5131b2aa68e920aacc3e9368129b70d342ce7bc6b0dab05039d62e1b63f33b81
chain entropy: not yet, arrives with the draw
serverSeedHash: 0x521295495e03a932817ff90e8bbfb6b6afd87ab2e485748f69c6a54e3b15e42f
clientSeed: 0xaeb8d1e67362513a6c7fc7ded2a8c6590ef87f0ef29d2265bd306cca579caa48
serverSeed (revealed): 0xc584ef95de7ea233d349bf6a8956825339d6e264431e34a67dbf6ea3b4ac0dd1
chainBlockhash (revealed): FJnhSRgxLrJN82VJn8uNL8KAv3s4j3M9PtnbFBZ1B5s6
chainSlot: 457920760
serverSeedHash: 0x8be619fb1af0ebdd3126bbfb511d3696bb758368e7d9bf2fc394e3c4c4923fb5
clientSeed: 0x0c96f93f4680613a0a64aab01b9a289ae2a0d1791e8cb9c630489059bb441aff
serverSeed (revealed): 0x83025f06b13e1d3383dee5a26d0fdadb085b78d3c012f0ebaff720e63cca5045
chainBlockhash (revealed): 2rx8KRBQa458ZoXYp2MRBG2zg3CHJhDXyQPQB1AzTPEp
chainSlot: 457919369
serverSeedHash: 0xb258f59e3a8021080f8f1c9fe3541f796162312f7d8311baeb7438fded6e9743
clientSeed: 0xf921ad31347177f98b5a57760cace97ab7947ddd1e7b139c9a5946972f618b1b
serverSeed (revealed): 0xae417c85285764ab66b77dcfb00766324cc9f5b2708ca95a068b88672e2089f9
chainBlockhash (revealed): 7jgnCyGTzba6K43tSRP7DarzFe26NS7TsqXWE1bYd5eU
chainSlot: 457917983
serverSeedHash: 0x34bd4afd4df53cbcc1e2f9cc7008103da7f3983cb3c028d70bca10f21703c8d7
clientSeed: 0xd3ed9fe2413c8b24981bbbca883938a496217182f0f924eb42c4a9a7f7406a34
serverSeed (revealed): 0xf2ef6114c15e83041769e679b35c290512087260f6808f94f87baf935fee5ecf
chainBlockhash (revealed): 5E5QqZd95MnDxEwGusWY68cVyHgvw7GT4hVyY4jcHNE4
chainSlot: 457916596
serverSeedHash: 0xb60a29e86343c17c8ab6b260bf8c77bcbb3e2e70b925c90fe53021226714a53d
clientSeed: 0x167285d7462ba3af67cc2e705343bf3031a3505b903c3e1142103ce1c643db89
serverSeed (revealed): 0xee8cdc3942f9c96b521598ce384dc142812907e2290e9700b3f7ee141af9d113
chainBlockhash (revealed): 9YKssFcp6nnMiz1jydcbWAotVgrbEMmvqWqWdG41GXoc
chainSlot: 457915202
serverSeedHash: 0xcbbee995184ecb8103e8db08cac55b8b85551098eba96f751949bea18f822936
clientSeed: 0x1e4670bfb5cdbde7e1e2524e9fe8ac620f4cd209d7130c068d4481be7bf962f7
serverSeed (revealed): 0x330efa5a7730d97c19bac39f6bba3b714ae944597b90611cbe1bdc34794433c7
chainBlockhash (revealed): 6rvReHpik1MMAvGd8KqhNB6FnRUiHupihAtVEsDiT4WN
chainSlot: 457913821
serverSeedHash: 0xc5d8e71d68713807deabbd9970f171ae015fc1ac6f28e2d4a26827ba3bee2adb
clientSeed: 0xe250cf7c842068db6cb5965a8102f07dfe7043a39ff1cc55f2845fe8c9401723
serverSeed (revealed): 0x03b5cb82ba596b99a480b29f1a5be62c674dc2d60791cf8b8ded3274972fe39c
chainBlockhash (revealed): VKmL8GXRJcCziwBC6CLe3oREWMa89HDui9R7KftZ8hi
chainSlot: 457912442
serverSeedHash: 0xf7f57cb6e8d89537f2fabc0fb967c34db5078a1a87fbe4352bb965865fde5186
clientSeed: 0x8d9c3afbde38c757d567643fd96b7950ba978384afb03eb619a2e432e5137ce9
serverSeed (revealed): 0x62c521b2c910292aca69361b86e7f271552bd8fadb29c57fd0c011b2d5673284
chainBlockhash (revealed): 67aXLY4aba1DHjKZgy5H3m6yaYfbKpeUVEku6UcSgS7p
chainSlot: 457912443
serverSeedHash: 0x2956710844245175eae7b0032f86ba4cb2abfa5761e9453d0068b383dc01bde7
clientSeed: 0xb0f1ce7c8975a4995059665ff0eab34b734b07cde39b97f295a3521fb6f9393f
serverSeed (revealed): 0xb32a734ff210b2f8ce00ceb8767f49a23f1353c480eb89c37fbf7f19c6009365
chainBlockhash (revealed): CJFd8Dj2DD7cytVTV9mt6rG5wa2cqSPzQYec6TMxPd5
chainSlot: 457911060
serverSeedHash: 0xd9ddbe4c0c6dfcb10c490973f9325c0cabf61ab3678d32ad18643c933984d0c2
clientSeed: 0x091c17f14132846552121fc6e46fb67367876e6663da0fa1f43e9a894b37ed65
serverSeed (revealed): 0x5f950cccbaad6849f1d2c8996b13c71ae91ae0a2f86bf78f7185e4949f87e127
chainBlockhash (revealed): 3PQ4fn9MfKUPL4zNYMWgUZ8vcA3jPTE16kbpWxirf4hE
chainSlot: 457909665
serverSeedHash: 0xa84e7623387f5883645e55370be57c2c474610c2f3b0e9fab3082d62e5ed0e07
clientSeed: 0xd26b4c941c22e00343b3c6fcbf89c5bd83011d176e7d980879f754c9dbe54734
serverSeed (revealed): 0x2f44e5d33d0a194bb5df68328db97e8d0548f4c16986979cca040fa8889f0820
chainBlockhash (revealed): 3nXHFQER45mfK18iMC7vyzXLuRHKgrCP81RsKnZz4wtT
chainSlot: 457908277
serverSeedHash: 0x13087ed130931221cae6f0c1d3112e07bd4f248f423380b9aaea91dade7ed80f
clientSeed: 0x4012210275ba4c9a6ab2ba37a6729710bbdc031cdcdf730db8f3937a674aa2c9
serverSeed (revealed): 0xc84d87139e95085a39f64f3688fee7e4240cbc514d7753e8217a52364ddcfc3d
chainBlockhash (revealed): Ge83iMinFEjbjEe3iQGntWdw9eSKAqLMKcoK9QuVoL8f
chainSlot: 457906879