Quiver architecture
A map of the moving parts and how a randomness request flows through them. For the cryptographic mechanism see protocol-design.md.
Components
| Component | Layer | Role |
|---|---|---|
QuiverCoordinator | on-chain | The protocol core: registers providers, escrows fees, stores requests, verifies reveals, delivers callbacks |
QuiverConsumer / IQuiverConsumer | on-chain | Base + interface for contracts that receive push-flow randomness |
Examples (CoinFlip, DiceGame) | on-chain | Reference consumer integrations |
@quiver/sdk | off-chain (TS) | Client for requesting/tracking randomness; hash-chain utilities; chain + ABI definitions |
@quiver/fletcher | off-chain (TS) | The provider's keeper: holds the seed, watches requests, submits reveals |
| Deploy scripts | tooling | Foundry scripts for deploy + provider registration |
Roles
- Provider — commits a hash chain and operates a keeper (Fletcher). Earns a per-request fee.
- Requester / Consumer — a contract or account that requests randomness and receives it back (via callback or self-reveal).
- Coordinator owner — protocol admin: sets the protocol fee, can pause new requests. Cannot touch seeds or in-flight randomness.
Push-flow sequence
Consumer QuiverCoordinator Fletcher (provider keeper)
│ │ │
│ requestWithCallback │ │
│───────────────────────▶│ store Request(seq) │
│ │ emit RandomnessRequested │
│ │─────────────────────────▶│ (event: seq, userRandom)
│ │ │ compute value = chain[N-seq]
│ │ revealWithCallback │ (simulate, then send)
│ │◀─────────────────────────│
│ quiverCallback(rnd) │ verify + combine │
│◀───────────────────────│ (delete req, advance) │
│ _fulfillRandomness │ emit RandomnessRevealed │
│ │ + CallbackSucceeded │
If quiverCallback reverts, the coordinator emits CallbackFailed and buffers rnd;
anyone can call retryCallback later. The provider is paid and unblocked regardless.
Pull-flow sequence
Requester QuiverCoordinator Provider endpoint
│ request(commit) │ │
│──────────────────────────▶│ store Request(seq) │
│ │ │
│ fetch value for seq ─────┼───────────────────────▶│ (off-chain)
│◀──────────────────────────┼────────────────────────│
│ reveal(userRandom, value)│ verify + combine │
│──────────────────────────▶│ returns randomNumber │
On-chain state
providers[address] → ProviderInfo— commitment tip, moving anchor, sequence counters, fee, chain length, fee manager, metadata.requests[keccak(provider, seq)] → Request— the request's commitments, anchor,numHashes, requester, flags. Deleted on reveal.failedCallbacks[keccak(provider, seq)] → FailedCallback— buffered randomness for retry.- Protocol fee + accrued protocol fees.
The design keeps per-request storage to ~4 slots and reveal cost to O(outstanding requests) hashes (usually 1). See protocol-design.md §4.
Trust boundary summary
┌───────────────────────── on-chain (trustless) ─────────────────────────┐
│ QuiverCoordinator: verifies every reveal, combines committed values, │
│ cannot be made to produce a biased result. │
└────────────────────────────────────────────────────────────────────────┘
▲ ▲
commit (tip)│ commit (hash)│
┌───────────┴───────────┐ ┌──────────┴───────────┐
│ Provider + Fletcher │ │ Requester / Consumer │
│ (trusted for liveness │ │ (trusted for its own │
│ & seed secrecy only) │ │ liveness only) │
└────────────────────────┘ └──────────────────────┘
Neither off-chain party is trusted for fairness — only for liveness. See security.md.