Everyone in crypto says "provably fair". Fewer people are willing to walk through the exact mechanics.
This is how we implemented a true 50-50 P2P USDC coin flip on Base using a simple commit–reveal pattern, zero rake, and non-custodial smart contracts:
1. The design constraints
We started with a few hard rules:
- No house edge or rake. Winner takes 100% of the pot.
- Yoss.gg never holds user funds in a custodial wallet.
- Every flip must be independently verifiable on-chain.
- UX has to work for someone who has never touched a wallet before.
Those constraints immediately kill most "crypto casino" architectures. So we built a minimal primitive instead: one contract, one coin, one flip.
2. Why commit–reveal and not just blockhash
Using blockhash or timestamps for randomness looks simple but is trivial to manipulate—especially for miners/validators and contracts that can choose when to settle.
Commit–reveal gives you:
- A private secret at commit time
- A public commitment stored on-chain
- A reveal step that proves you did not change your secret after seeing the other side
In our case, each player contributes entropy and the contract combines both secrets so neither side can force a win alone.
3. A minimal flow for a coin flip
At a high level:
- Player A chooses a random 256-bit secret
sAand computeshA = keccak256(sA). - Player A posts a game with stake
XUSDC and commitmenthA. Funds go into the contract. - Player B matches the game with stake
XUSDC and their own commitmenthB. - Once both commitments are locked, each player reveals their secret (
sA,sB). - The contract verifies
keccak256(sA) == hAandkeccak256(sB) == hB. - We derive randomness from
keccak256(sA, sB)and take the least significant bit as the coin flip. - Winner receives the full
2XUSDC pot.
No oracle, no trusted server, no off-chain "magic RNG". If either player refuses to reveal, the contract has explicit timeout logic for refunds/penalties depending on who stalled.
4. Non-custodial by default
All funds live in the contract, never in a Yoss.gg wallet. We use USDC on Base for:
- Stable, non-volatile stakes
- Cheap gas
- Fast settlement
The contract enforces:
- Exact stakes from both sides
- No skimmed fees or silent rake
- Direct payouts to the players’ smart accounts
Because there is no house edge, there is nothing for us to siphon off even if we wanted to. The pot flows from Player A + Player B straight to the winner.
5. Making this usable for non-crypto players
Everything above is great for devs and fairness nerds. Most players just want to click a button, flip a coin, and see numbers go up or down.
To bridge that gap we:
- Use smart accounts (ERC-4337) so users can sign up with email instead of a browser wallet.
- Abstract gas on Base so they are not juggling ETH balances.
- Integrate fiat on-ramps (MoonPay, Coinbase, Transak) so they can land directly in USDC on Base.
Under the hood, they are still using the same non-custodial contract and commit–reveal flow. They just never have to think about it unless they want to audit the chain.
6. How you can verify a flip yourself
If you are the kind of person who reads commit–reveal explainers (hi, friend), verification is straightforward:
- Look up the game and its commitments on Base.
- Fetch the revealed secrets from the resolution transaction.
- Locally compute
keccak256(sA)andkeccak256(sB)and confirm they match the commitments. - Compute
keccak256(sA, sB)yourself and check that the least significant bit matches the winner recorded on-chain.
If any of those checks fail, something is wrong—and you do not have to take our word for it.
7. Why we care about boring math
Crypto is full of "provably fair" banners glued onto opaque systems. We went the opposite way: minimal game, maximal transparency.
A single coin, zero rake, and a commit–reveal you can verify in a 20-line script.
If more games looked like this, we would have fewer rug stories and more people willing to touch on-chain betting at all.
If you are building something similar on Base (or want to), I would love to see your approach and tradeoffs.
Top comments (0)