# Quiver API reference

Complete reference for the on-chain interface (`IQuiverCoordinator`), the consumer
callback (`IQuiverConsumer` / `QuiverConsumer`), the data types, events, and errors.
Signatures are authoritative in `src/interfaces/`.

---

## `IQuiverCoordinator`

### Randomness — requester functions

#### `request(address provider, bytes32 userCommitment, bool useBlockhash) payable → uint64`
Pull flow. Reserves the next sequence number from `provider`. `userCommitment` is
`keccak256(userRandomNumber)`; keep `userRandomNumber` secret. Set `useBlockhash` to fold
`blockhash(requestBlock)` into the result (reveal within 256 blocks). Requires
`msg.value ≥ getFee(provider)`; overpayment is refunded. Returns the assigned sequence
number. Reverts: `ProviderNotRegistered`, `ProviderChainExhausted`, `TooManyHashes`,
`InsufficientFee`. Blocked while paused.

#### `requestWithCallback(address provider, bytes32 userRandomNumber) payable → uint64`
Push flow. Commits `keccak256(userRandomNumber)` and emits the raw `userRandomNumber` for
the keeper. The caller should implement `IQuiverConsumer`. Same fee rules and reverts as
`request`. Returns the assigned sequence number.

#### `reveal(address provider, uint64 sequenceNumber, bytes32 userRevelation, bytes32 providerRevelation) → bytes32`
Completes a pull-flow request and returns the random number. Verifies both revelations,
advances the provider anchor, deletes the request. Reverts: `NoSuchRequest`,
`RequestCallbackMismatch(true)` (if it was a callback request), `IncorrectUserRevelation`,
`IncorrectProviderRevelation`. `nonReentrant`.

#### `revealWithCallback(address provider, uint64 sequenceNumber, bytes32 userRandomNumber, bytes32 providerRevelation)`
Completes a push-flow request and delivers randomness to the requester's
`quiverCallback`. On callback revert/OOG, buffers the value (`CallbackFailed`) instead of
reverting the whole tx. Reverts: `NoSuchRequest`, `RequestCallbackMismatch(false)`,
`IncorrectUserRevelation`, `IncorrectProviderRevelation`. `nonReentrant`.

#### `retryCallback(address provider, uint64 sequenceNumber)`
Re-delivers buffered randomness for a previously-failed callback. Reverts
`NoFailedCallback` if none. If the callback reverts again, the whole tx reverts and the
buffer is preserved. `nonReentrant`.

### Provider management

#### `register(uint128 feeInWei, bytes32 commitment, bytes commitmentMetadata, uint64 chainLength, uint64 maxNumHashes, bytes uri)`
Registers `msg.sender` as a provider. `commitment = keccak256^chainLength(seed)`.
`chainLength ≥ 2`; `1 ≤ maxNumHashes ≤ 10_000`. Reverts `ProviderAlreadyRegistered`,
`InvalidChainLength`, `InvalidMaxNumHashes`.

#### `rotateCommitment(bytes32 newCommitment, bytes commitmentMetadata, uint64 newChainLength, bytes uri)`
Rotates `msg.sender` onto a fresh chain, anchored at `sequenceNumber - 1`. In-flight
requests are unaffected. Reverts `ProviderNotRegistered`, `InvalidChainLength`.

#### `setProviderFee(uint128)` / `setProviderFeeAsFeeManager(address, uint128)`
Update a provider's per-request fee — by the provider itself, or its delegated fee
manager. Emits `ProviderFeeUpdated`.

#### `setFeeManager(address feeManager)`
Delegate fee-setting and withdrawals for `msg.sender`'s provider. Emits
`ProviderFeeManagerUpdated`.

#### `withdraw(uint128 amount)` / `withdrawAsFeeManager(address provider, uint128 amount)`
Withdraw accrued provider fees to `msg.sender`. Reverts `InsufficientAccruedFees`,
`NotFeeManager`. `nonReentrant`.

### Administration (`onlyOwner`)

| Function | Effect |
| --- | --- |
| `setProtocolFee(uint128)` | Set the protocol fee added to every request |
| `withdrawProtocolFees(address to, uint128 amount)` | Withdraw accrued protocol fees |
| `pause()` / `unpause()` | Halt / resume **new requests** (reveals stay enabled) |

Ownership is `Ownable2Step` — transfers require the new owner to accept.

### Views

| Function | Returns |
| --- | --- |
| `getFee(address provider)` | provider fee + protocol fee (wei) |
| `getProtocolFee()` | protocol fee component |
| `getAccruedProtocolFees()` | withdrawable protocol fees |
| `getProviderInfo(address)` | full `ProviderInfo` struct |
| `getProviderSequenceNumber(address)` | next sequence number |
| `getRequest(address, uint64)` | the `Request` struct (zeroed if none) |
| `getFailedCallback(address, uint64)` | `(bool exists, bytes32 randomNumber)` |
| `constructUserCommitment(bytes32)` | `keccak256(abi.encodePacked(userRandomNumber))` |
| `combineRandomValues(bytes32,bytes32,bytes32)` | `keccak256(abi.encodePacked(u,p,b))` |

### Constants

| Name | Value | Meaning |
| --- | --- | --- |
| `MAX_NUM_HASHES` | `10_000` | ceiling on a provider's `maxNumHashes` |
| `MIN_CHAIN_LENGTH` | `2` | minimum registrable chain length |

---

## `IQuiverConsumer`

#### `quiverCallback(uint64 sequenceNumber, address provider, bytes32 randomNumber)`
Implement to receive push-flow randomness. **Must** require
`msg.sender == coordinator`. Prefer inheriting `QuiverConsumer`, which enforces this and
dispatches to `_fulfillRandomness`.

## `QuiverConsumer` (abstract base)

| Member | Purpose |
| --- | --- |
| `constructor(address quiver, address provider)` | Bind coordinator + default provider |
| `_requestRandomness(bytes32 userRandom) → uint64` | Draw from the default provider, paying the fee |
| `_requestRandomness(address provider, bytes32 userRandom) → uint64` | Draw from a specific provider |
| `_fulfillRandomness(uint64 seq, address provider, bytes32 rnd)` | **override** — your logic |
| `_randomnessFee() → uint128` | Fee for the default provider |
| `getCoordinator() → address` / `getProvider() → address` | Bound addresses |

---

## Data types (`QuiverStructs`)

### `ProviderInfo`
`feeInWei`, `accruedFeesInWei`, `originalCommitment`, `currentCommitment`,
`originalChainLength`, `currentCommitmentSequenceNumber`, `sequenceNumber`,
`endSequenceNumber`, `maxNumHashes`, `feeManager`, `uri`, `commitmentMetadata`.

### `Request`
`provider`, `sequenceNumber`, `numHashes`, `userCommitment`, `providerCommitment`
(verification anchor), `requester`, `blockNumber`, `useBlockhash`, `isRequestWithCallback`.
A zero `provider` means "no active request".

### `FailedCallback`
`randomNumber`, `requester`, `exists`.

---

## Events

| Event | When |
| --- | --- |
| `ProviderRegistered(provider, feeInWei, commitment, chainLength, maxNumHashes)` | `register` |
| `ProviderCommitmentRotated(provider, newCommitment, newChainLength, anchorSequenceNumber)` | `rotateCommitment` |
| `ProviderFeeUpdated(provider, oldFeeInWei, newFeeInWei)` | fee change |
| `ProviderFeeManagerUpdated(provider, feeManager)` | delegate change |
| `ProviderWithdrawal(provider, to, amount)` | fee withdrawal |
| `RandomnessRequested(provider, requester, sequenceNumber, userContribution, numHashes, withCallback, useBlockhash)` | a request. `userContribution` = commitment (pull) or raw value (callback) |
| `RandomnessRevealed(provider, sequenceNumber, requester, randomNumber, userRevelation, providerRevelation)` | a reveal |
| `CallbackSucceeded(provider, sequenceNumber, requester, randomNumber)` | callback delivered |
| `CallbackFailed(provider, sequenceNumber, requester, randomNumber, reason)` | callback reverted → buffered |
| `ProtocolFeeUpdated(oldFeeInWei, newFeeInWei)` / `ProtocolFeeWithdrawal(to, amount)` | admin fee ops |

Indexed fields: provider / requester / sequenceNumber are indexed on the core events for
efficient filtering.

---

## Errors

| Error | Meaning |
| --- | --- |
| `ProviderNotRegistered(provider)` | provider unknown |
| `ProviderAlreadyRegistered(provider)` | double `register` — use `rotateCommitment` |
| `InvalidChainLength(chainLength)` | `< MIN_CHAIN_LENGTH` |
| `InvalidMaxNumHashes(maxNumHashes)` | `0` or `> MAX_NUM_HASHES` |
| `ProviderChainExhausted(provider, endSequenceNumber)` | chain fully consumed — rotate |
| `TooManyHashes(required, maxNumHashes)` | too many outstanding requests; provider must reveal |
| `NoSuchRequest(provider, sequenceNumber)` | no active request (or already revealed) |
| `IncorrectUserRevelation()` | user revelation ≠ commitment |
| `IncorrectProviderRevelation()` | provider revelation doesn't chain to the anchor |
| `RequestCallbackMismatch(isRequestWithCallback)` | wrong reveal function for the request type |
| `NoFailedCallback(provider, sequenceNumber)` | nothing buffered to retry |
| `InsufficientFee(provided, required)` | `msg.value` too low |
| `InsufficientAccruedFees(requested, available)` | over-withdrawal |
| `TransferFailed(to, amount)` | native transfer failed |
| `NotFeeManager(caller, provider)` | not the delegated fee manager |
| `ZeroAddress()` | zero address where non-zero required |

---

## SDK surface (`@quiver/sdk`)

- `QuiverClient` — `getFee`, `getProviderInfo`, `getRequest`, `getFailedCallback`,
  `request`, `requestRandomness`, `reveal`, `waitForFulfillment`; static
  `generateUserRandom`, `userCommitment`.
- Hash-chain utils — `buildQuiver`, `commitmentOf`, `revelationOf`, `userCommitmentOf`,
  `combineRandomValues`.
- Chains — `robinhoodMainnet`, `robinhoodTestnet`, `anvilLocal`, `QUIVER_CHAINS`.
- ABIs — `quiverCoordinatorAbi`, `quiverConsumerAbi`.
