The RFQ Lifecycle
Everything in Overcast revolves around one data structure and one flow. This page explains both; the RFQ quoter guide turns them into code.
The data model
OptionDetails
OptionDetails is the canonical, signable description of an option's terms:
import type { Bytes32 } from "@overcast-xyz/core";
type OptionDetails = {
startTimestamp: number; // option becomes exercisable (unix seconds)
endTimestamp: number; // option expires (unix seconds)
premiumAsset: Bytes32; // what the taker pays the maker up front
premiumAmount: bigint;
collateralAsset: Bytes32; // what the maker locks up
collateralAmount: bigint;
settlementAsset: Bytes32; // what the taker pays on exercise
settlementAmount: bigint;
settlementLayer: Bytes32; // on-chain settlement-layer config committed to
domain: number;
borrowAllowed: boolean; // signable term: feeds getId + operation bytes
};
Read it as: the maker locks collateralAmount of collateralAsset; the
taker pays premiumAmount of premiumAsset for the right to swap
settlementAmount of settlementAsset for that collateral until
endTimestamp. A covered call and a cash-secured put are the same structure
with the cash leg on different sides.
Offers and options
Each side of a trade is expressed as an offer over the same details.
There is a single Offer type — { creator, expiry, details, salt, side }
— with side: "MAKER" | "TAKER" selecting the collateral vs settlement side:
side: "MAKER"— the maker's side (posts collateral).side: "TAKER"— the taker's side (pays the premium).
Matching a collateral offer with a settlement offer whose details agree mints
a MarketOption on-chain. An option carries an optionId derived from both
offer IDs (plus parties + terms) — there is no independent id apart from
that derivation.
Offer (MAKER) ┐
├──► matchOffer ──► MarketOption
Offer (TAKER) ┘
Once minted, the option is managed through claims:
- The taker holds exercise claims and calls
exerciseOptionto swap settlement for collateral (any amount up to the exercise-claim balance, whilestartTimestamp <= now <= endTimestampand with borrows repaid). - The maker holds redeem claims and calls
redeemOptionto pull their collateral (plus any settlement paid in) back out.
Canonical IDs and signatures
Offers and options are content-addressed: async getId serializes the struct
into a fixed byte layout (byte-for-byte identical to the on-chain
implementations), sha256-hashes it, and returns a 0x-hex Bytes32
(const id = await getId(offer)). Every field — including the random salt,
the expiry, and borrowAllowed — is part of the hash, so an
ID commits to the complete terms.
Authorization in the RFQ flow is a signature over the CreateOfferOperation
digest (which embeds the offer bytes: domain-separated "overcast_intent" +
version + domain + curve + action + expiry + nonce + offer bytes), produced by
the OvercastProtocolSigner (ed25519 or secp256k1 depending on the chain).
There are no session
tokens: your public key identifies you, your signature over the operation proves you
authored the offer.
Offer expiry
Offers carry a unix-seconds expiry. If you don't set one, the SDK defaults
to 60 seconds from now (DEFAULT_EXPIRY_DURATION). The minted option itself
has no offer expiry — its own endTimestamp governs its life.
Settlement Methods
The settlementLayer field commits the option to an on-chain settlement
configuration. The SDK ships a registry (app.settlement) with two known
kinds:
"physical"— direct asset-for-asset settlement (the default)."oracle"— oracle-gated settlement derived from the assets' price feeds (Gated or Intrinsic mode).
Pick the config before signing — the writer commits whatever the offer carries, verbatim:
details.settlementLayer = await app.settlement.defaultConfig(details);
How these layers compose into the five product methods (Physical · Raw and Physical · Gated share capital; Intrinsic; Access × both) is covered in Settlement Methods.
The RFQ flow
RFQ is the off-chain price-discovery channel: a socket.io namespace on the Overcast backend that brokers quote requests between the two sides.
Participants register a role:
MAKER— will end up on the collateral side (e.g. writes the covered call).TAKER— will end up on the settlement side, pays the premium. Market makers register asTAKER: they buy the option.
The flow, end to end:
- Create. The creator sends an RFQ with partial details — all the
terms except the premium — via
createRfq. The server assigns anrfqIdand broadcastsnewRfqto the opposite side. - Quote. Responders price the request and call
submitQuotewith the completeOptionDetails(their premium filled in). Under the hood the SDK builds the responder's offer, content-addresses it withgetId, signs theCreateOfferOperationdigest, and sends it. The server broadcastsnewQuoteback to the creator. - Accept. The creator picks a quote and calls
acceptQuote. The SDK builds and signs the creator's opposite offer, and the backend settles the pair on-chain inline — the acknowledgment carries{ optionId, txHashes }. - Terminal events.
rfqCancelledandrfqExpiredbroadcasts close the loop for everyone else.
State machines, as stored by the backend:
| Entity | Statuses |
|---|---|
| RFQ | open → quoted → accepted | cancelled | expired |
| Quote | open → accepted | rejected | expired |
Wire format notes
Two representations of the same data cross the network:
- Wire details —
OptionDetailswith thebigintamounts as decimal strings (JSON can't carry bigints). The SDK converts withamountToWire/amountFromWire; you always work withbigint. - Curated details — broadcast payloads (
newRfq,newQuote) resolve raw asset addresses into fullAssetmetadata (symbol, decimals, price hints).completeOptionDetails(details, premium, utils)(or(await app.curator()).completeOptionDetails(details, premium)) anduncurateOptionDetails(details, utils)convert curated shapes back into signableOptionDetails.
All payloads are validated with zod schemas exported from @overcast-xyz/core
(createRfqPayloadWireSchema, submitQuotePayloadWireSchema, …; note
quoteNewPayloadSchema is the curated newQuote broadcast shape, not the
client→server wire shape), so you can reuse
the exact contract in your own services.