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

# Concepts

> How a quote round runs: eligibility, fan-out, validation, and selection.

A quote round is a single synchronous pass. The borrower's request comes in, the coordinator does everything it can before and during the solver wait, and the response goes back in the same HTTP exchange. There is no queue, no retry, and no state carried between rounds.

## The quote lifecycle

<Steps>
  <Step title="Parse the request">
    The body is parsed against the request schema. Numeric fields arrive as decimal strings and are range-checked before conversion, so malformed input is a clean `400` rather than a server error. A failure here ends the round: no solver is contacted.
  </Step>

  <Step title="Validate the request">
    Two checks run before any fan-out: both `collateralToken` and `debtToken` must be protocol-supported tokens, and every bit set in `venueBitmap` must correspond to a registered venue. Either failure returns `400`.
  </Step>

  <Step title="Select eligible solvers">
    The coordinator reads its solver registry and filters it down before making a single HTTP call. See [Eligibility](#eligibility) below.
  </Step>

  <Step title="Fan out in parallel">
    Every eligible solver is called simultaneously with the same intent, each carrying its own fresh `quoteId`. The round is bounded by the slowest solver, not their sum. A solver that times out costs the round nothing beyond its own timeout.
  </Step>

  <Step title="Validate each response">
    Every returned quote is checked independently: schema, terms, both signatures, registry enablement, and bond sufficiency. A quote that fails any definitive check is dropped. A dropped quote never fails the round. See [Validation](/rfq/running-a-solver/validation).
  </Step>

  <Step title="Select the winner">
    Among surviving quotes, the **lowest `fixedRate` wins**. The response carries that quote inline plus `allQuotes`, every valid quote from the round. If no quote survives, the round returns `404`.
  </Step>
</Steps>

## Eligibility

Not every registered solver sees every request. Three filters run before any HTTP call, so an ineligible solver costs the round no latency at all:

| Filter            | Effect                                                                                                                                   |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `chainIds`        | The solver is skipped unless the request's `chainId` is one it declared. A solver that declares nothing receives every chain.            |
| `supportedTokens` | Matched against the request's **debt** token only; collateral is never filtered on. A solver that declares nothing receives every token. |
| Compliance        | A per-endpoint borrower blocklist. If the request's `borrower` is blocked for that endpoint, the solver is skipped.                      |

These are the reason a healthy, registered solver can see no traffic at all. See the [FAQ](/rfq/running-a-solver/faq).

## Fan-out and timing

Solvers are called concurrently and independently. The default response window is **5 seconds**, raisable per solver during onboarding. A solver that exceeds its window is abandoned for that round: the round does not wait, and the timeout is recorded against that endpoint.

Declining is a first-class outcome, not an error. A solver that does not want to quote returns HTTP `404` or a quote with `bond: "0"`; both are recorded as non-quotes and are treated differently from failures for health purposes.

Everything the coordinator can do in advance happens during the solver wait rather than after it. Bond-curve parameters for every enabled bond liquidity manager are fetched the moment the request arrives, unawaited and batched, so they have resolved by the time responses need checking against them. Bond validation therefore adds no latency to the round.

## Validation is convenience-grade

This is the doctrine that explains most of the coordinator's behaviour.

`Iris.take()` re-verifies every term on-chain. The coordinator's checks exist to drop quotes that are **definitively unsubmittable** before a borrower wastes gas on them, not to replicate the contract. That produces two rules:

* **Reject only on a definitive invalid.** A signature that recovers to the wrong address is unsubmittable, so the quote is dropped.
* **Fail open when a check cannot run.** If bond parameters could not be fetched, bond validation is skipped rather than failing the quote. The contract is the backstop.

The practical consequence for solvers: passing validation here is necessary but not sufficient. A quote that survives the round can still revert at `take()`.

## What a quote is

A quote is a signed, short-lived offer. It carries two signatures, both from the solver:

* **The `Quote` signature**: an EIP-712 signature over the on-chain `Quote` struct, which is what `take()` verifies to bind the solver to these terms.
* **The Permit2 signature**: an EIP-712 signature over a Permit2 `PermitSingle` authorising `Iris` to pull exactly this quote's `bond` in the debt token. `take()` pulls the bond from the solver, and the solver is not in the call path to approve it, so the authorisation travels with the quote.

Quotes expire within **two minutes** of issue. They are not stored, not re-offered, and not cancellable: expiry is the only exit.

## What the coordinator is not

* **Not an order book.** Intents are not broadcast or persisted; a round is private to its participants.
* **Not a matching engine.** It returns a quote; it never settles one. Settlement is the borrower calling `take()`.
* **Not custodial.** It never holds tokens, keys, or positions.
* **Not open enrolment.** Solvers are onboarded through a whitelist.
