# Consumer contract reference

## Push flow (callback) — recommended

You inherit `QuiverConsumer`, request randomness, and a keeper delivers the result to your
`quiverCallback`, which the base contract dispatches to your `_fulfillRandomness`.

```
request  ──▶ QuiverCoordinator.requestWithCallback(provider, userRandom)  ──▶ seq
keeper   ──▶ QuiverCoordinator.revealWithCallback(...)  ──▶ your quiverCallback(seq, provider, rnd)
                                                          └▶ _fulfillRandomness(seq, provider, rnd)
```

`QuiverConsumer` (abstract base) gives you:

| Member | Purpose |
|---|---|
| `constructor(address coordinator, address provider)` | Binds the coordinator + default provider (both must be non-zero). |
| `_requestRandomness(bytes32 userRandom) → uint64 seq` | Request from the default provider, paying `getFee` from contract balance. |
| `_requestRandomness(address provider, bytes32 userRandom) → uint64 seq` | Request from a specific provider. |
| `_randomnessFee() → uint128` | Current fee for the default provider. |
| `_fulfillRandomness(uint64 seq, address provider, bytes32 rnd)` | **You implement this.** Settlement logic. |
| `quiverCallback(...)` | Coordinator-gated entry — **do not override.** |
| `getCoordinator()` / `getProvider()` | Views for the bound addresses. |

### The retry buffer

If `_fulfillRandomness` reverts, the coordinator catches it, emits `CallbackFailed`, and stores the
random number. Anyone can later call `QuiverCoordinator.retryCallback(provider, seq)` to redeliver
it. This is a safety net, not a happy path — a reverting callback means your users' outcomes stall
until someone retries. Design `_fulfillRandomness` to never revert (early-`return` on unknown or
already-settled sequence numbers).

## Pull flow

No keeper. You request with a *sealed* commitment, then reveal later by submitting both revelations.

```solidity
// 1. Request: commit to a secret userRandom.
uint64 seq = coordinator.request{value: fee}(
    provider,
    keccak256(abi.encodePacked(userRandom)), // userCommitment (see constructUserCommitment)
    useBlockhash                              // fold in blockhash(requestBlock)?
);

// 2. Reveal: submit your userRandom + the provider's revelation to get the result.
bytes32 rnd = coordinator.reveal(provider, seq, userRandom, providerRevelation);
```

You obtain `providerRevelation` from the provider's reveal endpoint (its `uri`), or off-chain from
the SDK hash-chain helpers if you run the provider. Use pull when you don't want to depend on a
keeper and can drive the reveal yourself.

### `useBlockhash`

When `true`, `blockhash(requestBlock)` is folded into the result:
`keccak256(userRevelation ‖ providerRevelation ‖ blockHash)`. It adds a third entropy source but
means the request must be revealed within 256 blocks (after which `blockhash` returns zero on most
EVM chains). Leave it `false` unless you specifically want block-hash binding.

## `IQuiverCoordinator` — the functions you'll call

Randomness flow:
- `request(provider, userCommitment, useBlockhash) → seq` — pull request (payable).
- `requestWithCallback(provider, userRandomNumber) → seq` — push request (payable).
- `reveal(provider, seq, userRevelation, providerRevelation) → randomNumber` — pull reveal.
- `revealWithCallback(provider, seq, userRandomNumber, providerRevelation)` — push reveal (keeper).
- `retryCallback(provider, seq)` — redeliver a previously-failed callback.

Views:
- `getFee(provider) → uint128` — total fee (provider + protocol) to request. **Always read this;
  do not hardcode.**
- `getProtocolFee() → uint128`, `getAccruedProtocolFees() → uint128`.
- `getProviderInfo(provider) → ProviderInfo` — full provider record.
- `getProviderSequenceNumber(provider) → uint64` — next seq the provider will assign.
- `getRequest(provider, seq) → Request` — the active request record.
- `getFailedCallback(provider, seq) → (bool exists, bytes32 randomNumber)`.
- `constructUserCommitment(userRandomNumber) → bytes32` — helper for pull commitments.
- `combineRandomValues(userRevelation, providerRevelation, blockHash) → bytes32` — recompute a
  result off the raw inputs (verification).

Key events:
- `RandomnessRequested(provider, requester, seq, userContribution, numHashes, withCallback, useBlockhash)`
- `RandomnessRevealed(provider, seq, requester, randomNumber, userRevelation, providerRevelation)`
- `CallbackSucceeded(...)` / `CallbackFailed(..., bytes reason)`

Consumer-side errors (from `QuiverConsumer`):
- `CallerNotCoordinator(address caller)` — `quiverCallback` was called by a non-coordinator.
- `ZeroAddress()` — a zero coordinator/provider was passed to the constructor.

## Verifying a result independently

The result is deterministic from its inputs:

```
randomNumber == keccak256(userRevelation ‖ providerRevelation)          // useBlockhash == false
randomNumber == keccak256(userRevelation ‖ providerRevelation ‖ blockHash) // useBlockhash == true
```

where `userRevelation` is the raw `userRandomNumber` and `providerRevelation` is the provider's
hash-chain link for that sequence number. Recompute it with `combineRandomValues` on-chain or the
SDK's `combineRandomValues` off-chain to prove fairness.
