Skip to main content
An asset swap follows the same quote-first flow as every route. Today the quote is computed client-side: the application prices it from the market card’s own feed, the user funds the derived contract, and any compatible solver fills it. The contract records what the user gives and the minimum result a fulfillment must deliver; it stays open until a solver fills it or the user cancels. The RFQ transport for this route is specified and replaces local pricing without changing the flow.

Lifecycle

The deposit is a VTXO at the covenant script, and every status is a reading of that one VTXO. The covenant’s whole vocabulary is two leaves, so a deposit that moved took fulfill or it took cancel — and which one is read off the spending transaction’s tapleaf, not inferred from what the transaction moved. The leaf is the evidence, not the amounts. What a fill has to deliver is the covenant’s business and is enforced when the transaction is validated; asking what a transaction moved cannot classify one, because an asset swap’s cancel takes the asset out of the covenant and hands it straight back, netting to zero and reading exactly like its fill. A spend that took neither leaf, or one that cannot be fetched yet, is left unclassified — the record keeps the status it had and a later read decides it. Nothing sticky is written on a guess. cancelling is local and provisional. cancelOffer writes it before it broadcasts, so a crash between the submit and the record leaves a marker rather than a swap that still reads pending. It is not evidence that a cancel happened: a fill can win the race, and whichever leaf lands is what the status becomes. A cancel made from another device never passes through it. recoverable is the one status no spend produces. The deposit was swept — the batch it sat in expired before either leaf was taken — so it is a recoverable VTXO like any other: still yours at that script, no longer exitable unilaterally, and recovered by settling it rather than through the covenant. Keep the script watched; a swept deposit is money still sitting there. The restore scan is what writes this status, on records it rebuilds — the live watcher reports spends, and a sweep is not one.

Funding the Swap

The application derives the non-interactive swap contract from the approved terms. createOffer registers the contract and returns the type 0x03 extension; it does not broadcast a transaction. The swap becomes discoverable when the wallet funds the derived address and includes that extension. The packet tells solvers watching the Arkade transaction stream how to interpret the funded output. Persist both the encoded offer and the funding transaction identifier. Identical terms derive the same address, so the address alone does not identify one deposit.

What the Contract Enforces

The non-interactive swap contract binds the asset identity and minimum amount the fulfillment must deliver. Both legs settle in one Arkade transaction. The covenant reads exactly one output. A fill is any transaction whose output 0 pays your script at least the amount of the asset you named; everything else about it — how many inputs the solver brings, where its change goes — is the solver’s business. The deposit side is never inspected, which is why the same contract carries BTC, an asset, or an asset-for-asset swap. Read the fill’s two inputs together and the swap is visible: the solver’s coins pay you, your deposit pays the solver, and neither leg can happen without the other because they are the same transaction. The funding transaction carries the type 0x03 packet alongside its outputs; that is what tells watching solvers the funded output is an offer and how to read its terms. The two ways out are deliberately asymmetric. A fill needs no signature from you — the covenant is the constraint, so a solver cannot take the deposit without paying output 0, and you can be offline while it happens. A cancellation needs no signature from the solver, so taking the deposit back never waits on a counterparty. Neither program carries a timelock, so nothing about the offer expires: an unfilled deposit keeps its place at the swap address on the terms it was funded with, and there is no expired state to unwind. The VTXO holding it still carries its batch expiry — one left resting past that is swept rather than filled or cancelled, which is the recoverable status above and the only exit the covenant has no leaf for. The contract does not guarantee:
  • that a solver has sufficient inventory;
  • that the feed represented a fair or current market price;
  • that the swap fills within a particular time;
  • that an asset issuer redeems or honors the asset.
The covenant path depends on the Emulator key, which the client package resolves from the Arkade operator (overridable via the optional emulatorPubkey parameter). Review Trust and Limitations before using the flow with value.

Standing Offers

A funded contract does not wait on the person who funded it. It names the asset, the minimum amount, and the script a fill has to pay, and anything that delivers those three settles it — from any solver, at any time, with the funder offline. An exchange would call terms fixed in advance a limit order, and one waiting to be taken a resting order. This is that, held as a contract on Arkade instead of a row in a venue’s book. The delivery and the spend are the same transaction, so there is no interval in which the contract is open and the payment is owed: a fill that does not pay the named terms is not a fill, it is an invalid transaction. A fill is all-or-nothing — partial fills would need a contract that pays a remainder back into itself, which this one does not do.

Price Without a Book

The terms fix a ratio: what the contract holds, against what a fill must deliver. That ratio is the price. Solvers watch resting contracts and take the ones that beat their own pricing, leaving the rest. Nothing aggregates them. Each contract is independently enforceable, so no venue holds the orders, matches them, or has to stay solvent for one to settle — the reason the pattern is worth having rather than a book with custody attached. Today the ratio comes from the market feed, not from you. The application prices the swap from the card and you approve the result before funding, so a contract rests at a price that was current when you funded it. Choosing your own ratio — an offer that waits for the market to reach it — is future work, as is any surface that ranks resting contracts as a book.

Discovery and Pricing

Solver cards advertise supported pairs, amount bounds, indicative fees, and a price feed for cross-asset markets. Applications choose which cards and registries they accept. The card and feed are advisory:
  • they do not reserve solver inventory;
  • a feed response is not a signed quote;
  • the application applies its own freshness, tolerance, and eligibility policy;
  • the user reviews the resulting deposit, receive amount, and fee before funding.
See Discovery and Registries for the card and index formats.

The maker Fields

The covenant programs and the Offer type carry maker* identifiers — makerWP, makerPkScript, makerPublicKey. They name contract positions, not roles: the side that funds the swap and receives the fill. Arkade Intents deliberately avoids maker and taker as participant vocabulary; the parties are the user and the solver.

Negotiated Asset Swaps

The client package can map a negotiated quote whose endpoints both use arkade onto the same swap terms. No reference solver serves that RFQ path today, so current asset integrations use discovery and market-feed pricing.

Sources