DEV Community

How a Provably Fair USDC Coin Flip Actually Works on Base

Most "+provably fair+" claims are just a badge slapped on a black box.

Here’s what a real on-chain, commit–reveal coin flip looks like in practice — the exact pattern we use at Yoss.gg for P2P USDC flips on Base.


1. Two players, one pot, no house

  • Player A and Player B both stake the same amount of USDC
  • There is no house balance and no rake
  • All funds live in a smart contract escrow until the flip resolves

If the flip never happens (someone fails to reveal, times out, etc.), funds are returned by the contract rules. There is no off-chain admin button deciding who gets paid.


2. Commit first, reveal later

The core problem: if one player can see the other player’s randomness before sending their own, they can cheat.

To avoid that, we use a commit–reveal flow:

  1. Commit phase

    • Each player picks a secret random value sA and sB
    • They hash it with a salt: hA = keccak256(sA || saltA), hB = keccak256(sB || saltB)
    • They send only the hashes hA and hB on-chain when joining the game
    • The contract stores the hashes, not the secrets
  2. Reveal phase

    • After both commits are locked in, each player reveals sA, saltA and sB, saltB
    • The contract recomputes the hashes and verifies they match hA and hB
    • If a player fails to reveal within a timeout, the other wins by default (this rule is enforced on-chain)

At no point can a player see the other’s secret before their own commit is finalized.


3. Turning randomness into a coin flip

Once both secrets are revealed and validated, we need a single random bit that decides who wins.

A simple pattern:

bytes32 combined = keccak256(abi.encodePacked(sA, sB));
bool aWins = (uint256(combined) % 2) == 0;
Enter fullscreen mode Exit fullscreen mode
  • We combine both secrets in a hash
  • Convert to a uint256
  • Take mod 2 to get a fair 0/1 outcome

Because both players contributed entropy, no one can bias the result on their own — and because the hash function is deterministic, anyone can recompute the outcome independently.


4. Escrow, payouts, and timeouts on Base

On Base L2 this feels instant, but the rules are still strict:

  • Both players deposit exactly the same USDC amount
  • The total pot is 2 * stake
  • Once the winner is known, the contract transfers 100% of the pot to the winner’s address
  • There is no separate fee transfer, rake, or skim
  • If a timeout is hit (e.g., one player never reveals), the contract follows a clear, public rule for refunding or awarding the pot

Because it’s all on-chain, you can:

  • Inspect the game history
  • Verify every commit and reveal
  • Recompute the winner locally from the revealed secrets

If the contract mispaid, everyone would see it — which is the whole point.


5. Hiding the crypto complexity from the player

The crypto-native version of this flow assumes:

  • You have a wallet
  • You understand gas
  • You’re comfortable signing multiple txs

Most people aren’t.

At Yoss.gg we hide that by:

  • Using smart accounts under the hood (ERC-4337)
  • Letting people sign up with just an email
  • Sponsoring gas on Base so users don’t need ETH in a fresh wallet

The result: you still get a pure on-chain, commit–reveal coin flip with no house edge — but the UX feels more like a web app than a DeFi ritual.


6. Why this matters

If you’re building any on-chain game where outcomes actually matter, you should be asking:

  • Who controls the randomness?
  • Can any single party tilt the odds?
  • Can users independently verify every result?

If you can’t clearly answer those questions, your "+provably fair+" label is just marketing.

With commit–reveal on Base, you can build:

  • Simple P2P coin flips (like Yoss.gg)
  • High/low games
  • Multi-player raffles and lotteries

All without running a custodial balance or sneaking in a house edge.


If you want to see this pattern live, check out Yoss.gg — it’s literally a two-click way to watch a commit–reveal coin flip play out on-chain, without ever touching a wallet extension.

Top comments (0)