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): 0xc16d2d7747da8037441ed135c776b6ee4bb3916da0e18451aa9d84878193ba4e
clientSeed: 0x02615b20de0617ec6ba1f8bc0fde60f51ff8392b0cb9969a266e18db791d32b8
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x6a5b1c1728b18df6331373ff0f1ae5cc15539e54c7b34b63db693233bce50f82
clientSeed: 0x69480c98d36b39149b7a83894de6650879c95387544365e1a512e1eaf9c6958c
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: 0xb36cc4df30e71a0452b56d56cc037799e8d221fcbf56e05913cb3e485912e6de
clientSeed: 0x9d801b90b09d37c475f037a66b4ef0e980bd3d8159cd16656b13c1987f44f63b
serverSeed (revealed): 0x26ea8bba9142a71246bd9ca6b9b0e09d8e420ae47bcc23d6353358800c3cd61f
chainBlockhash (revealed): Gg1kJgPGJ6E9ySGeCVDFdm3xsW9F2kBTkGFx2rULohs2
chainSlot: 458056353
serverSeedHash: 0xc751f5e24799d9c6e2953c7ac82c0146b4046e64f0debc9f2faa75bfae8cfafd
clientSeed: 0xe885090629039af17f4c48edb1568c70562eaceb504f32797608ec624d65d282
serverSeed (revealed): 0xb38e4d289b9fe350673bf5405b4d6b86f074755846a7da4a9f9c9a98d941ca31
chainBlockhash (revealed): 56ZDwwhm6zGayUVhY1NdsvByhmJgHrsQTtByiotrux3B
chainSlot: 458054979
serverSeedHash: 0x26b2d500b9ba44422ab9889755d2a20648f5aec0c27efca910c7b856aa77e0d5
clientSeed: 0x0be9f730ef7cbdc94c16337f5856961aaf522fc854c87a159e674a3f976336ae
serverSeed (revealed): 0xf95a71d0b5d7401dddbf0e8e35332230afea654ed6b5299d4a6ba0be596a1290
chainBlockhash (revealed): GTJjrJb6WweELEu53zQo64ZQR31fdSRDFHXLUZQnsntB
chainSlot: 458053603
serverSeedHash: 0xc3e07be52384c6101a7135d3e88f4f3e7eb35aaabf582eab35cbb860be93855e
clientSeed: 0x9ce3f304e02017765121a1d9fc43af7a3daac5bed6c7f93c5b33f6d1134369cb
serverSeed (revealed): 0x44b951dcbdcb9a3a00fc6128c31d38eb4efaa63b2949dce30e5308bf09c70964
chainBlockhash (revealed): 7bidUG9uuzwMZvzjB5DDvMzkXE3L2iZcTGoESFW11ypS
chainSlot: 458052222
serverSeedHash: 0xce340c33db0b3ae5c4a119698f4a43f25007ca888256bcc09b6f94906d4a49a3
clientSeed: 0x4afe0b003ac9cc443ae95774387dd95e1fc12516d493d0600f074826d02ada22
serverSeed (revealed): 0xd0e5219a1cff79ca6c5773a0499b11209befed1251958353bddca504e542710b
chainBlockhash (revealed): CmCUpcpatfVMWgei43Fb6ntaJgMpb833TZvQhmwmiJiQ
chainSlot: 458050841
serverSeedHash: 0x4fd13ae2aa4d4647ae0e94a7a1c9963cde7f66c5a84f523371c35de1286dc137
clientSeed: 0xe9f285b276fda4f44f3e3ece2df113a91c9cda49e9f7c42f8b818824ef11b51b
serverSeed (revealed): 0x421e89d6bb785b50a4778de388403ca4a9987c2701ff0f199dbc270a368d92d0
chainBlockhash (revealed): 6sERgFSgjC8PoQa8d4HuKznNxi8NB2LCxQB7qu1Tqam9
chainSlot: 458049458
serverSeedHash: 0x82093bb65b0677ee4872aa9acf330010205adc694887bc384a96535054139a8f
clientSeed: 0x6f01b623d90114bd49f4125eebbc78f4501cdbe364fe455674c05237bd473645
serverSeed (revealed): 0xbff3e1b5876a48480e3cb91380c436ceb10c7c3974429d369cb48bb3b65fb069
chainBlockhash (revealed): 4T2U9zXawMuTMb16wWbzEEhB1b3Mt1jZSiBauJ852w6c
chainSlot: 458048084
serverSeedHash: 0x4a743c47d2606b3b944536b5795fb7bfafc119091618a2cab6cd6d81f9ab0aaa
clientSeed: 0xfafdb88f2e50104059b447160d83202bc890437059d6950f6f3185bbecf9356f
serverSeed (revealed): 0x25ab179131264622412a50e2a0ade4d6d12a5eb0f81a223d240eb04ba7fba4e5
chainBlockhash (revealed): CfY7wbi3y1akZm2zDDM7SNR6K32JqZfRzygTEaMWuyFz
chainSlot: 458046701
serverSeedHash: 0x9337ed873afc76193df8b093f7705d7f39518407e079d63d8d5b3b6755f1df7d
clientSeed: 0x85ab5ef59aab7c4a3897d6445ad96cbe5bbff715186d93c165c7d4f457272e54
serverSeed (revealed): 0x16fa712a7cf7c3a7d616d385c817c614681607b88e989321d4395e497976edfe
chainBlockhash (revealed): 2sL8mASS2wBgRpZCEfvxwSEbgDeqcLK2npA56tA68Gui
chainSlot: 458045334
serverSeedHash: 0x78a5f6631687ff955cec00c9664a2ca681a784cbe90752ee5fcea5aeb7471cd1
clientSeed: 0xde918c747cd8618fd09de694f59af26567861a00d33df71832008b2c058c92cc
serverSeed (revealed): 0x8294ce1dcc15f1780482df26dcb7ef2ac3efc0e742b8d31a9ef990b6031e95a1
chainBlockhash (revealed): 4a4xCPqfF4oddpMbniRgzJ6qvW7UNyitEVfBTTkNyVpn
chainSlot: 458045333
serverSeedHash: 0x6045549b2d51008136e1ab478dffa588b9279e3cfcdb6681ed393d385b9a43b2
clientSeed: 0x7245acbc3a81c471a3021e6684cfcc4a79ac7e105c71709f5fae582f04af50ad
serverSeed (revealed): 0x86c270451df657218d6b6d2ed368bfbe181c8bdf46f237d69ca059de8684b8d0
chainBlockhash (revealed): 2t2dbcwt8TDnd8EQNm9kyEfUXXpDi8jEXxfWeL11GT2u
chainSlot: 458043965
serverSeedHash: 0x073b3c44012921defe5bdbea8f56f3d9c078bf569a0c308d5bce225cee22e4c3
clientSeed: 0xdc34d4bac0532b8eba27f456b6f56ca2d14c12713cf6168f0444fce4770b55cb
serverSeed (revealed): 0x5d1426776cdb63b54fb4baf1a59c31421f9935d29c66fa9b7cde2532d7aba784
chainBlockhash (revealed): DpnAshgqfet1n75S1fKiDj8dTayQvkzb4m7Z4A6uduMs
chainSlot: 458042592