arkade (arkadeSwapRequest) is specified and joins when
served — Asset Swaps covers how that route
sources its quote today.
Quote Lifecycle
Addressed and Published Requests
Addressed is the shipped path — build against it. Published mode is still
in development: no client publisher exists, the reference deployment bids only
on Lightning sends, and its payloads are not specified below, deliberately.
Pinning
rfq_open and rfq_bid field names before an implementation exists
would publish a schema that the first working publisher then contradicts. The
client work is tracked in
ts-sdk#725; once it lands,
dropping the transport’s solverPubkey is the entire client change.
Neither a request nor a bid locks funds. A bid is signed and attributable but
not bonded. The signed quote returned by the selected solver is the binding
RFQ message.
Relay
RFQ messages may travel through Nostr relays. Client and solver each dial out; neither needs to accept inbound connections. A relay transports messages but does not select a solver, aggregate quotes, or touch funds.
The negotiation kinds sit in NIP-01’s ephemeral range: relays deliver
them to live subscribers and store nothing, so an expired negotiation leaves
no public record. The cost is no store-and-forward — a request sent while the
solver is offline is dropped, which the client timeout and retry cover. The
advertisement is replaceable: standing state a relay keeps the current
version of. Kind numbers remain provisional.
Message Family
Every payload carries the envelope{"v": 1, "type": …}.
Addressed payloads are transport-independent. The reference service accepts
HTTP and Nostr traffic; clients can implement another transport while
preserving the same payloads.
Payload Schemas
Field names below are exact. The reference solver validates a request strictly: an unknown field, a misspelled one, or a missing required one refuses the whole request rather than being ignored — a wrong name and an absent field fail identically. These are the addressed-mode payloads.rfq_open and rfq_bid are work in
progress and are not specified here — see
Addressed and Published Requests.
Encodings
Both scripts commit to
ripemd160(sha256(P)), derived locally from
payment_hash on each side; the hex on the wire is the sha256 digest alone.
Client-supplied keys are x-only. Solver-supplied keys — solver_pubkey,
htlc_pubkey, claim_pubkey — may also arrive as 33-byte compressed keys, and
the reference client drops the prefix before using them.
Request Envelope
rfq_id is the client’s, not the solver’s — generate it before sending and
correlate every reply against it. A reply whose rfq_id differs is a reply to
a different negotiation and must not be read as this one’s answer.
The BOLT11 send profile is the one route that omits amount: the invoice fixes
it, so the request pins amount_side to to and restates nothing.
arkade:BTC → lightning:BTC
arkade:BTC → onchain:BTC
lightning:BTC → arkade:BTC
P never travels in the clear. The solver receives the hash and the sealed
packet; it learns the preimage only when a claim publishes it.
onchain:BTC → arkade:BTC
Routes whose endpoints both use arkade
Specified, not served — see Asset Swaps for
how this route sources its quote today. The pair string stays coarse and the
asset ids ride the profile, mirroring the offer TLV.
want_asset and offer_asset is set per request — the BTC
side names no asset. want_asset describes an arkade:BTC->arkade:ASSET
request, offer_asset the reverse; each is the hex-serialized asset id.
Quote
rfq_id and pair must equal the request’s. refund_locktime is present on
every HTLC-class quote and absent where both endpoints use arkade. The spread
between from_amount and to_amount is the complete cost — there is no fee
field.
The quote profile carries the route’s construction data:
Which of these bind and which are compared is set out in
Quote Boundary and, per direction, in
Derive, Never Accept.
Refusal
reason comes from a closed set: unsupported_pair, unsupported_payload,
amount_out_of_range, exposure_cap, invoice_expired, quote_conflict,
pricing_unavailable. Treat an unrecognized reason as a generic decline —
the set may grow, and a refusal is never an error to retry blindly.
Status
state is one of the wire states below. Status is best effort: a timeout, a
missing response, or an unknown state means unknown, never failed.
Transport Framing
The payloads above are what a transport carries; neither transport changes a field.
A 4xx carrying an
rfq_refusal body is the refusal path, so the status code
alone cannot decide whether to read the body — parse it, and fall back to the
status code only when the body is not a payload of this family.
On Nostr the client signs with a transport key it may generate fresh per
negotiation; nothing in the protocol needs a stable client identity, since the
quote binds to the contract rather than to who asked for it. Replies arrive on
a subscription filtered to that key and are correlated by rfq_id.
RFQ Wire States
The client-side
RfqSwapManager monitors funded swaps from chain evidence
with its own states rather than consuming these wire states; its failed
outcome is client-side reporting.
Quote Boundary
Economic commitments stay at the top level. Settlement construction data stays insideprofile.
Profile fields are also checked against client-owned inputs such as an invoice,
payment hash, destination, and network. Recheck time-sensitive conditions
immediately before value moves.
Transport Requirements
Regardless of transport implementation:- reconnect after both connection errors and clean closes;
- restore live subscriptions on a new connection;
- bound and persist or reject outbound events queued while disconnected;
- correlate every response with the expected RFQ identifier and route;
- treat a status timeout as unknown, not failed.
Persistence Requirements
Persist recovery data before the route’s first enforceable commitment. At a minimum, retain:- route;
- swap identifier or RFQ identifier;
- encoded terms and verified solver identity;
- derived script or contract data;
- funding transaction identifier;
- expiry and refund timing;
- wallet-owned key or preimage derivation data;
- destination-network identifiers required for reconciliation.