1n2.org / coin-flip
How it works

One flip, end to end.

Two players, two secrets, one hash. The outcome is decided by math neither side could predict alone. Here's exactly what happens.

The short version

You commit to a secret. Your opponent commits too. You both pay into escrow over Lightning. You both reveal. The winner is determined by hashing both secrets together — a value neither of you could forge in advance. The winner gets paid. The house takes a small cut. A signed record is published to Nostr so anyone can verify the math.

Step by step

  1. Player A opens a flip. A picks a side (heads or tails) and a wager in sats. Their client generates a random 32-byte secret sA. We compute commitA = SHA-256(sA || sideA). Only commitA and the wager are published. sA never leaves A's device.
  2. Player A funds escrow. The backend issues a Lightning invoice for the wager. A pays it. The sats sit in the operator's LNbits node, earmarked for this flip.
  3. Player B joins. B sees the open flip in the lobby. B takes the opposite side, generates their own secret sB, and publishes commitB = SHA-256(sB || sideB). B pays a matching invoice into escrow.
  4. Both sides reveal. With both commits locked and both wagers funded, A and B each reveal their secret. The backend verifies that SHA-256(sX || sideX) equals the commit each player posted. If either reveal is invalid, the flip aborts and funds are refunded.
  5. The outcome is computed. outcome = SHA-256(sA || sB). The low bit of the digest decides heads or tails. Because neither sA nor sB was known to the other player at commit time, neither side could have biased the result. The winner is the player whose declared side matches outcome.
  6. Payout. The winner receives (wager × 2) × (1 − fee) via their Lightning address (LNURL-pay). The house keeps the fee — 3% by default. If the payout route fails, funds stay in escrow and the winner can claim with a different address via /claim.
  7. Publication. The COIN FLIP Nostr identity signs an event containing the commits, the reveals, the outcome, the winner, and the payout preimage, and publishes it to relays. Anyone can verify the hashes without trusting us.

The flow, as a diagram

  Player A                Backend                 Player B
     |                       |                        |
     |  open(commitA, wager) |                        |
     |---------------------->|                        |
     |  pay invoice (escrow) |                        |
     |---------------------->|                        |
     |                       |      lobby: flip open  |
     |                       |----------------------->|
     |                       |  join(commitB)         |
     |                       |<-----------------------|
     |                       |  pay invoice (escrow)  |
     |                       |<-----------------------|
     |       reveal(sA)      |                        |
     |---------------------->|                        |
     |                       |       reveal(sB)       |
     |                       |<-----------------------|
     |                       |                        |
     |                 outcome = SHA-256(sA || sB)     |
     |                 winner = side matching outcome  |
     |                       |                        |
     |     LNURL payout      |     LNURL payout       |
     |<- (winner only) ------|---- (winner only) ----->|
     |                       |                        |
     |                       | publish signed event   |
     |                       |------> Nostr relays    |

What if someone refuses to reveal?

Cheat timer

Once both players have funded escrow, a 10-minute reveal window opens. If either player fails to reveal their secret before it closes, the other player is declared the winner and paid out. The no-show forfeits their wager. This is the only honest punishment we can apply without a reveal — and it's enough to make refusing to reveal strictly worse than revealing a losing secret.

If neither side reveals, both wagers are refunded after the timer expires. Nobody wins, nobody loses, nobody pays the fee.

Why this is provable

Because SHA-256 is a one-way function, committing to commitA locks A into sA without revealing it. B then locks in sB without having seen sA. Once both commits are on the record, neither player can choose a new secret to change the outcome — any swap would fail the commit check. And because the outcome is the hash of both secrets, neither side alone could predict it when they committed.

You don't have to trust us that this is how it works. Every settlement is published, signed, and verifiable. See the trust page for the honest breakdown of what's trustless and what isn't.