Flip game
Flip is the headline game on ThisOrThat. Buyer picks a card (or a multi-card cart), chooses a spread, and a coin flip decides whether they pay BELOW market or ABOVE. Either outcome, they get the card. The spread is the gambling element; the card delivery is the certainty.
The math
Every Flip listing has three numbers stored in FlipConfig:
cardValue— the card's market value (or lot total)spread— typically0.25(25%, our current default)winPrice=cardValue × (1 - spread)— what buyer pays on a WINlosePrice=cardValue × (1 + spread)— what buyer pays on a LOSE
Example: $100 card at 25% spread:
- Win → buyer pays $75 (saves $25)
- Lose → buyer pays $125 (overpays $25)
- Either way → card ships
The provably-fair flow
The buyer can verify the outcome wasn't rigged. Sequence:
- Buyer commits the play with a Stripe payment intent (manual capture)
- Server generates seed:
crypto.getRandomValues(32 bytes) - Server hashes seed:
sha256 = SHA-256(seedHex) - Server anchors hash on Solana (memo transaction). Buyer can verify the hash existed before the result was decided.
- Server reveals seed + computes outcome:
seed[31] % 2 === 0 ? WIN : LOSE(last byte's parity) - Buyer's UI animates the coin flip, lands on result
- Server captures the right amount via Stripe: winPrice if win, losePrice if lose
- Order created, label printable, fulfillment proceeds
The hash gets anchored on-chain BEFORE the seed is revealed. Anyone can verify after the fact: take the revealed seed, recompute SHA-256, check it matches what's anchored on Solana. If the hash doesn't match, the operator cheated. If it does, the math is verifiable.
Multi-card flip carts
Buyers can build a cart of 2+ cards and flip them all on one outcome. Use case: stacking
sub-$15 cards over the shipping floor. Math is identical — cardValue becomes the cart total.
| Cart | Total value | Spread | Win price | Lose price |
|---|---|---|---|---|
| 1× $50 card | $50 | 25% | $37.50 | $62.50 |
| 3× $5 cards | $15 | 25% | $11.25 | $18.75 |
| 5× $20 cards | $100 | 25% | $75 | $125 |
Eligibility rules
- Solo flip floor: a single card needs
marketValue ≥ $15to be flipped on its own (shipping economics). Cards below are flaggedflipEligible: false. - Cart total floor: a multi-card cart needs
combined ≥ $15. The per-card flag is bypassed for cart length ≥ 2. - Pull-only cards: cards intentionally routed as Pull-only (
pullEligible: true, flipEligible: false) can still be added to flip carts when combined with other cards.
Lots vs singles in Flip
A "lot" is a Listing with multiple cards stored as a single unit. The buyer flips the whole lot once, ship every card on the same outcome.
- City lots, team lots, player lots — all valid Flip listings
- The
FlipConfig.cardValueis the lot'stotal_value - One outcome, one shipment, all cards together
Spread defaults
Currently 25% across the system (recently bumped from 15%). The spread number is the operator's risk knob:
- Lower spread (10-15%) → buyers happier, smaller upside on losses, less margin per play
- Higher spread (25-35%) → bigger swings, gambling appeal stronger, margin per loss-play larger
- Above 40% → starts looking predatory, FTC risk
Code references
- Game logic:
thisorthat/src/lib/games/flip.ts - Play endpoint:
thisorthat/src/app/api/play/flip/route.ts - Payment intent path:
thisorthat/src/app/api/payment/route.ts - Solana anchoring:
thisorthat/src/lib/blockchain/solana.ts - Settlement on Stripe: capture-or-cancel via webhook handlers in
/api/stripe/webhook/route.ts