The quote lifecycle
1
Pass the edge screen
Requests are screened before they reach the coordinator. One that arrives without a browser challenge token is answered at the edge with
202 and a challenge page, so only a browser running the Iris app reaches the steps below.2
Check the origin
The deployed coordinator answers the Iris app’s browser origin only. A request whose
Origin header is missing or unrecognised returns 403 before the body is read.3
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.4
Validate the request
Three checks run before any fan-out: both
collateralToken and debtToken must be protocol-supported tokens, every bit set in venueBitmap must correspond to a registered venue, and every venue the bitmap names must have a market for the pair. Any failure returns 400. The last check is per venue, not “at least one can serve”: a bitmap naming a venue with no market for the pair is rejected even when another named venue could quote it.5
Select eligible solvers
The coordinator reads its solver registry and filters it down before making a single HTTP call. See Eligibility below.
6
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.7
Validate each response
Every returned quote is checked independently: schema, terms, signatures, registry enablement, bond sufficiency, and solver funding. A quote that fails any definitive check is dropped. A dropped quote never fails the round. See Validation.
8
Select the best quote
Among surviving quotes, the lowest
fixedRate is ranked best. The response carries that quote inline plus allQuotes, every valid quote from the round; the borrower may take any of them. If no quote survives, the round returns 404.Eligibility
Not every registered solver sees every request. Four filters run before any HTTP call, so an ineligible solver costs the round no latency at all:
These are the reason a healthy, registered solver can see no traffic at all. See the 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 HTTP404 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 lock module, and each registered solver’s debt-token balance and allowances, are fetched the moment the request arrives, unawaited and batched, so they have resolved by the time responses need checking against them. Bond and funding validation therefore add 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.
take().
What a quote is
A quote is a signed, short-lived offer. It always carries theQuote signature: an EIP-712 signature over the on-chain Quote struct, which is what take() verifies to bind the solver to these terms.
How the bond pull is authorised depends on the solver’s funding mode. take() tries a standing ERC-20 approval to Iris first; a solver maintaining one signs nothing further and omits the Permit2 pair. Otherwise the quote also carries the Permit2 signature: an EIP-712 signature over a Permit2 PermitSingle authorising Iris to pull exactly this quote’s bond in the debt token, travelling with the quote because the solver is not in the call path to approve the pull at settlement.
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 seen only by that round’s eligible solvers and are never 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.

