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): 0x179451ff41740867803144ab220e3f9a3998feebedbd149c001b805c45f00a92
clientSeed: 0xd989ebc218b3772b3611b937b380face05db9e769b868125f58ab8c7fc0915e0
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x950e3d0dbb6b3dff783f3917056e2932fc5c21ea8777b360b011bb031f47e473
clientSeed: 0x2089f2aad607c8db3c166f15091cd24ef230e6815307bc2aa8795ffa91a49f5f
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: 0x46bda15d3f02c811fb76651cc86742bd99c0e69d0f6d1ad8fc86baa2c9490aa0
clientSeed: 0x54fe3241b8924f4a3af7fc34b0fe2a6e00f3f88724ad8fbd81c9233cb02c31dd
serverSeed (revealed): 0x9fc78b287eeb55e741d3840d2abc8cff61226b37ed36cdb0f9daf936a4af3975
chainBlockhash (revealed): BDKpjQtmkj6Z6cF2jJFBNkFVGYK3DLm8R5ezv8hBdFm8
chainSlot: 458489265
serverSeedHash: 0xb5b35c51f2e5206894f6a8166fb75d32dc7befe651ee40da8b21eb0eab50ee12
clientSeed: 0xe3aab19c93bcb4eef8c08847ac36ea3d9f90a2710e2072e058f33b9149df9e0a
serverSeed (revealed): 0x949c56b66f3a051ae5bbcc50ab38319d8c4853aa3e7586fd4ceb0d3107a19193
chainBlockhash (revealed): FvW3ySR4bMnkVi9RSXayYQYcsYZuZopQecBXiYWxcns2
chainSlot: 458487891
serverSeedHash: 0x96509d6ef808f21b3787d18f61e0fcf04969fe610844a6bd4208bca90a7daa4d
clientSeed: 0x5f0d2ab2037342f729f6e2ac7870b6b4cbc768be14b1330fd56747965753576c
serverSeed (revealed): 0xb9eb738447c709e457aa8d3627a61d6c0e21d33476aad8c13e10320aa3b3abf7
chainBlockhash (revealed): DbKWNppATY7dPsBPgdswenXueDbgaTh3aXE37ajz2UrN
chainSlot: 458486506
serverSeedHash: 0x65d649d0e51d9ec08f8c93600289375a9d27c28f9ec46e5e85ca71a4c952b6cb
clientSeed: 0x4cfa3fe3f742578ceb787b44ebc9c8540ac20c4c312990d1d817aa4c3d6eb82a
serverSeed (revealed): 0x121e3b7a5afaf8f86130ee8985ba87f194b5412e0e1102554cedac0a5cb6c6ef
chainBlockhash (revealed): CdQCz3PFfq1mkLFdMP5ejdzFzUMt8CKutBNh3ia5QxCy
chainSlot: 458485120
serverSeedHash: 0xe379276faccb918acd0ada72d5c91fac991a857f5615383db7ea2ddbfb1f4ff2
clientSeed: 0x1bb875a0870c0adc8a4897a3e66f389a59cfc129c28ebf6103ebded4ec1f6c25
serverSeed (revealed): 0xace19b5b5e8b297f2331297362419b3b548a191765a0789e179947e0e946df6e
chainBlockhash (revealed): 816DXETU1L1kxHThcGjNiNCFnXPvbwk9DhAaWrv7uNqN
chainSlot: 458483732
serverSeedHash: 0x9c5d5e8083858960012f97db0d020135ad3e6d46ce781e8739778ad08ef20644
clientSeed: 0x61a53874dba33aaba294ead80a397e30b94124da34e56263441fc8e073515a85
serverSeed (revealed): 0x77d3f93c8db32a4cd1f05f3309ac6e2911eafa348b62dc7c12ce8ac0e7f263fd
chainBlockhash (revealed): 63X78queqMNHsgK9Y2xwFANFJ9atMKe1fniRAcZa6jQ4
chainSlot: 458482337
serverSeedHash: 0x683fc9abfc02b1f92e54c3998d49011d535234cb8757f669641ddf51ee1bbd8d
clientSeed: 0xf3ae452cb95f55c1edf6f0e0a6474a607e8149db11f319472bfedfb0a1751041
serverSeed (revealed): 0x72c2681fe0c3df439c0d9bf7aa0e1e299b523da30fa527070a4b286d704d0417
chainBlockhash (revealed): 91BbsmEd794qkynoMUtgbWjsUa1vrBEZmReKGVsCE8Q4
chainSlot: 458480955
serverSeedHash: 0x48ca59c0afd2a435d9411e343a026fe005751fbd9210ed76dde1dbf111ea8484
clientSeed: 0x491f7792d7dee21ad95d20da509e57e833c8c14b69fa1404ce76bb85f051bf96
serverSeed (revealed): 0x12859b36892a1dd11f552d5ee3fcf023ec1404ff115bc955313bce2a56639c8f
chainBlockhash (revealed): FB1Ls6cWNRbru3tA94doTmoZrWMaU3F7aFAwoiDUeoZY
chainSlot: 458479566
serverSeedHash: 0xb157c95c707f6f205cdccaa6c083be8162d7ae6fb432c03c44392f8c4f3ada93
clientSeed: 0x0485e1ba36131edc3a7c8d495c7894eb026b31375623bb7a22d782e8bb38ac2a
serverSeed (revealed): 0x7d40962e22c6109bd10e3dea01c893638876d011d99e577151736ab3c4971234
chainBlockhash (revealed): HDtyGWc57cUUDGhx5263wTE7CcBCXR4yPuPAYNEMTjom
chainSlot: 458478191
serverSeedHash: 0xe32d780df2a30ef1de6c6d06c8f7e20c212cd405b94149e2ce9da30e8502b262
clientSeed: 0x5bed710f9bb54b34af611deb2627e673001062eb221e441d646fbdd1d881387e
serverSeed (revealed): 0x80a0ee879505d06e7a8a048527220e0ab7c4be8e82c4d457a5115b3b86306f6c
chainBlockhash (revealed): ALtzcEKxcdYDtZgRmKm54G2VXWRC1u1pb6bxgcq3gt51
chainSlot: 458476827
serverSeedHash: 0x845c0032c5cd1343a49717b893f98cd3714380b7204f4f4fc421bee45e243941
clientSeed: 0x71db4f9795ed61efe8b664391ec06e7be842c418326f07920508387852925387
serverSeed (revealed): 0x72fde5dddb706b3a8cbe2c554b03ad901aa9854b44609caca593e615fb8a7c8e
chainBlockhash (revealed): qjrPnMM3RXcqduLoxoQrAQt5Y2A5HY8KHcKyi5CD2HZ
chainSlot: 458476826
serverSeedHash: 0x6ca19b605cb29955c74159b55dd6b7f8e242d3b3a5c2e4be1f84f866b914046e
clientSeed: 0x60fa33fed9a3f72ab8bf0c1534c3e960446343ccfd24215d3f8b01667570d2b6
serverSeed (revealed): 0xeea4c8959bedea3785c86a5f78dd97e4568ca65c1cff070ad23b47db2236888e
chainBlockhash (revealed): C6L4MYK7qYGsY3Qmcj71beYsaKL2JkE2ArBLCQ33L9AN
chainSlot: 458475416