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): 0x5b2bad074c56629e99036cc234427d9ef7bfc72ce2a732d2e17fc70fc2fcbea6
clientSeed: 0x00da03d1250123fb30a57c66b94e6d27846110c4559f30c3c58c2d6fbee051e2
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0xcf47ad597f5dd7eb831936ee53e62f48047e0c35eec4dbe4a44d846b30dce93a
clientSeed: 0xce9ca07227c130234329c8a93f908dafd8ba287f15279d0bc76ed9c796c000fc
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): 0x24d5e14176236ff7fcb2d4db69870149192d8369adf799313bff22ad8d10f7ef
clientSeed: 0xe7ee2dd6d3bc1b68ccb2f80429ab27cbe9d8c0870cb67e94d0f69f68444a4120
chain entropy: not yet, arrives with the draw
serverSeedHash (commitment): n/a
clientSeed: 0xc7232ae2d71047eab03ff5d11ac53807851945f1f3754091bbb5f13cee458411
chain entropy: not yet, arrives with the draw
serverSeedHash: 0xee9b3d8cae484f696f16ca5423d3ca0f2dd5a82197164c127dc5e832f7a92106
clientSeed: 0x87a8885033e133a2275b39cdb40382f406992bfdb678eaf97893e080851617bd
serverSeed (revealed): 0x6031582222fc84157565d6e890771bd048d534ecc02c49c0899dc8763d34becc
chainBlockhash (revealed): HhDWghX8jaktPMoRBJGGPxdEhER52KpRATPUGpV9rE83
chainSlot: 457603177
serverSeedHash: 0xc048d83153ca207c34498dd44b113c1b6ef4af6c633bf57badd571df6b3941b1
clientSeed: 0x589abe855a558a799342e0003cf28fe18236b10eebd7eedb84ce742a4134fbf2
serverSeed (revealed): 0xde24730ebf318a827d8c026d26d37ae6b124ae2165da517c7ef24cb28182e31d
chainBlockhash (revealed): BE2MtzjPT6jh7VKiCApUTbWttnGPNTnPQWdtJBueBFpF
chainSlot: 457601776
serverSeedHash: 0x47566ae2889e31b177641e4ac887675eb695712fa4b38f6344ab383e07849be7
clientSeed: 0xfa567eac0627f39b461d0fd1180e1492d610ba927ea5ccf37bc4a2c36fca24fc
serverSeed (revealed): 0xda331840f2d9451d397169705cf4b757d5def176da2f0c577cca91d1ed4d63f4
chainBlockhash (revealed): hydnB4374RHwFH3dJckBygvJP981NajkF8vvAUf2Kj3
chainSlot: 457600383
serverSeedHash: 0x589170849db2c2ad33e236c077bc218d9b1dd36a28336922311ef4ad3298ede5
clientSeed: 0x0c63edd6779ee6ae8842497dc48d6669fe3158ca2ff015f18d951afe463292d9
serverSeed (revealed): 0xe26d3201178111f22876ae8e96843aa981e121403c4705cc7b7fec0bd3792501
chainBlockhash (revealed): DPYY6AJKRq8QeN6aXkuNp23ZFNcYhDGkPkN99pDv6Wxp
chainSlot: 457598993
serverSeedHash: 0x0947ef2287350d5845e4fd17093f57c1084889ca852c33f698d11ed9932123ec
clientSeed: 0x34a1a7535769935f36fa81cea5a126e231fad6c8b7606b7c9214d234b26a37b5
serverSeed (revealed): 0x1a86751beae2a251a53a626197094deb47676b6700b7283537f5412f5d55f551
chainBlockhash (revealed): EjWGmiorM3wQUZfgaxvaig8QXHfYGCZvNez1pi1HaTxp
chainSlot: 457597605
serverSeedHash: 0x49045c0ba5b6275f6b39dbc2b42c5bdf8732a4738c4f85d84022f89c8cd7dc61
clientSeed: 0xd8a5f9c754db8cb0fbc51553d9ebb0a8d23a0f004187e065dc00da4b14d4b515
serverSeed (revealed): 0xca0df1c08fd1ac5e3bd5dcce34997e7292ced7e90a80f9032e622e191b4f92e8
chainBlockhash (revealed): Br17yxA6UUByBfrXgVBzfJs59LHsBVKp5Kn6PDJzqvHu
chainSlot: 457596212
serverSeedHash: 0x2ef09591eb786361648bd499f23731fef37ff84a10c11c8fa5d02e2900e89252
clientSeed: 0x9e9b9d63918c1d75b35b1d96b1c3e46b82c90311dcd3858af1d63fb0c61609be
serverSeed (revealed): 0xe514ef1a3b3576d187685dda23533986c6f24ae0f44adafdca0a3dae9ea4ab61
chainBlockhash (revealed): E92NpGeQ9qHusebGxHSv5zCsLQaESEHXFLBVDsrQZGJx
chainSlot: 457596213
serverSeedHash: 0xffa67fdd6bfcc8ddb062b227c096a15af762f2bec6c684a29066ef5bb8e2034a
clientSeed: 0x44ae4ead7ef0b13bc063c029a28391f54d2de7314e85de1ae8d2bd5ca3d0cca9
serverSeed (revealed): 0x27b39aefb68452adce24ca6b9f0141d723afcef4f44f6e5eeb38252452c73499
chainBlockhash (revealed): EMFwtT9Zeq4mkmSYAVyTGhpaAsuGCU21MmRTD9csAMZb
chainSlot: 457594797
serverSeedHash: 0x16f7bb99812835ff154b28e2c1ec96b6ebd4de12cf2221393229417687a0bdcd
clientSeed: 0xe6f0f18fe13b1ba6120568860da618a9d99f075179109ea2147261c5835a72ef
serverSeed (revealed): 0xa0713feaeceeefbc21bb41a0593e2c91217fd011f5d80e3345cec5b46aeafe7d
chainBlockhash (revealed): 83VygQTm27zRPkaEtRaqqSnwgtjuR8foLzYxQrbLDDyT
chainSlot: 457593406
serverSeedHash: 0x0cd724173f183b6fee3234aa0bfa3e80924c86ff5f5377298516f224d70908c1
clientSeed: 0x93f41e597fc0716d9954442772e09c02b691b3039e4ea2563e84912e40cab979
serverSeed (revealed): 0xe081746475502a2703f8886defb02526496e2e148f14f78a4824f3b3106ea086
chainBlockhash (revealed): 3vqdRmLbrWdxCfFitMDXoB5Fq8wRP6uMeLRDNKWQtEfu
chainSlot: 457591996
serverSeedHash: 0xc41d5288491d94cd2e44593141087c8771d933887507138269ffdad8540d9be1
clientSeed: 0x47e831298d0faa70d43c89ce96150309383c5f84aa4a6d1a458fe854d6c32044
serverSeed (revealed): 0xba4024b13f6030e15a1f8c232630ed8919b360e6e32fbf2d584c4ba09cb6fd96
chainBlockhash (revealed): 7sUGkHazdzkQnL3ijnywaUjUdbaK28BFy8HBQc4Ur2aZ
chainSlot: 457590607
serverSeedHash: 0x4f8b802014492ffc44a5bf9c1033f5443080dc96e33041d81512560c68e5d7ad
clientSeed: 0x9eec447a8664f273ba66a15805099da85884bed1eb79616969256c2eaac6517a
serverSeed (revealed): 0x986c617d7c4968a796e72998443adcc52de7aa8f1ce4494190f448f6b741ddb5
chainBlockhash (revealed): GL8vvfoRdiFBayKPJ9NVhqCGa1u9eT7qcnikSwN5zYFi
chainSlot: 457589228