> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chance.money/llms.txt
> Use this file to discover all available pages before exploring further.

# Provably fair

> Epoch commit–reveal with Poseidon entropy and ZK proofs — no key can decide a payout.

Chance uses **commit–reveal with an epoch-bound server seed**. Every payout derives from entropy the contract itself verified — either against the revealed seed or via a Groth16 proof. There is no operator-attested settle path.

## How an epoch works

<Steps>
  <Step title="Commit">
    The pool opens an epoch by publishing `commitment = PoseidonT2([serverSeed])` on-chain. Many bets share one epoch commitment; the seed itself stays secret.
  </Step>

  <Step title="Play">
    Each bet binds your `clientSeed` and its unique `betId` under the open epoch. The outcome is already fixed: `entropy = PoseidonT4([serverSeed, clientSeed, betId])`. The house cannot pick your entropy without breaking the commitment; you contribute `clientSeed`, so it cannot precompute a forced loss either.
  </Step>

  <Step title="Settle early with a proof (optional)">
    While the epoch is still open, anyone can call `settleWithProof(betId, entropy, proof)` with a Groth16 proof that the entropy is consistent with the committed seed — without revealing the seed. The API computes and delivers these proofs in realtime (see [Results & proofs](/integrate/results-and-proofs)).
  </Step>

  <Step title="Close, then reveal">
    `advanceEpoch(nextCommitment)` closes the epoch (no seed in that transaction) and opens the next. Afterwards, anyone holding the seed can call `settleWithSeed(betId, serverSeed)` — the contract checks `PoseidonT2([seed])` against the commitment, publishes the seed, and settles. Remaining bets settle with `settleBet` / `settleBets`.
  </Step>

  <Step title="Verify">
    With the revealed seed public, anyone can recompute every outcome in the epoch (see below).
  </Step>
</Steps>

## Verify a bet yourself

After the epoch's `EpochRevealed` event publishes `serverSeed`:

1. **Check the commitment:** `computeCommitment(serverSeed)` (a public view on ChancePool) must equal the `commitment` from the epoch's `EpochOpened` event.
2. **Recompute the entropy:** `computeEntropy(serverSeed, clientSeed, betId)` — also a public view — must produce the entropy the bet settled with.
3. **Re-derive the payout:** map entropy to the outcome with the mode formula ([Strike / Range / Ladder](/protocol/bet-modes)) and compare against the `BetSettled` event's `payout`.

The Poseidon hashes match circomlib / `poseidon-lite`, so the same math runs in JavaScript verifiers and inside the ZK circuit.

## The refund safety net

Every bet carries a deadline of `placedAt + revealTimeout` (default 1 hour):

| Timing                                                  | Result                                                                                                                                       |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| Seed public (or proof supplied) **before** the deadline | The bet settles for its real outcome, forever — a proven win never expires into a refund                                                     |
| Deadline passes while the epoch is unrevealed           | The bet is **refund-only forever**: stake back on every path (`forceRefundOnTimeout`, `settleBet`, `claim`), even if the seed shows up later |

If the server seed is ever lost, the operator's only power is closing the compromised epoch (`forceAdvanceEpoch`) so bets refund — it can never choose an outcome.

<Note>
  The public API delivers results and proofs, but **never the server seed** while an epoch is open. Treat any result shown before an on-chain settle as display-only; the paid truth is always the contract settle.
</Note>
