Skip to main content

Swaps

Quotes​

A quote is the server's price for one swap: a source, a destination and one amount. An end is a chain, or Lightning. The amount fixes either end, what the user receives or what they send.

let target = TargetAmount::Receive(100_000); // or TargetAmount::Send(100_000)
let quote = driver.quote(Some(Chain::Bitcoin), None, target).await?;
FieldMeaning
receive_amountwhat the user receives
send_amountwhat the user pays: receive_amount plus fee
feebase_fee plus service_fee
base_feethe server's on-chain costs at the current fee rate
service_feethe proportional fee, plus any rounding
expires_atthe last moment a swap can be created from it; after it, creating fails with QuoteExpired
await_opening_txSwapIn: how long the server waits for the deposit, in seconds

Show the quote, and create the swap when the user accepts. The swap carries both amounts as quoted. A SwapOut's claim pays its own network fee out of receive_amount.

SwapIn​

Mint an invoice for the quote and create the swap with it:

let swap = driver.swap_in(quote, bolt11, Some(refund_address)).await?;
let record = swap.record().await?;
println!("deposit {} to {}", record.send_amount, swap.address().await?);
RequirementOtherwise
The invoice is for exactly receive_amountcreating the swap fails
The invoice outlives min_confs + 1 blockscreating the swap fails
The invoice expires in await_opening_tx secondsa longer one shows the user more time than the server waits
The user sends send_amount to the address as one outputthe output is a stray, refunded as Refunds describes

The refund address is optional: without one, a refund waits for an address from the destinations hook or a call.

A SwapIn ends Completed once the server paid the invoice, or Canceled with the deposit still the user's, in funds.

SwapOut​

Create the swap with the address the funds land on, or none to take one from the destinations hook:

let swap = driver.swap_out(quote, Some(claim_address)).await?;
println!("pay {}", swap.claim_invoice().await?);

The user pays claim_invoice, a hold invoice for send_amount. The payment stays pending while the server locks the funds on chain. Once they are deep enough, the driver releases the preimage, which lets the payment settle, and claims the funds to the claim address.

The preimage waits whileStatus
the funds have fewer than min_confs confirmationsConfirming, with confs of needed
the fee estimate is above max_fee_rateConfirming, with the estimate as fee_rate_spike

Once less than claim_margin of the CSV is left, the preimage never goes out: the swap ends Canceled with ClaimWindowClosed, and the payment fails back.

A SwapOut ends Completed once the claim confirms, or Canceled with the payment failed back or failing back.

Statuses​

swap.status() returns where the swap stands:

StatusFlowThe swapFields
Restoringbothwas restored and is not read yet
Fundingbothhas nothing on chain yetexpires_at, the time to pay by; cancel_sent once the driver asked the server to cancel
Confirmingbothis on chain, confirmingtxid, confs of needed; SwapOut: fee_rate_spike while fees hold the preimage, beside max_fee_rate
ClaimingSwapOuthas released its preimage and is claimingopening; claim, confs and fee once the claim is broadcast
Completedbothis paid outopening, payout; SwapOut: fee, what the claim paid
Canceledbothdid not happen, for reasonopening, when the server's CSV refund takes it

expires_at is min_confs + 1 blocks before the invoice expires on a SwapIn, and no later than the hold invoice's expiry on a SwapOut. Past it, the driver asks the server to cancel and keeps watching.

fee is the network fee of the user's own claim, read from the chain. It is None until a claim is broadcast, and on a SwapIn, whose payout is the server's.

A Canceled swap says why in reason:

ReasonFlowMeaning
ServerCanceledbothThe server gave the swap up, with its error_type and cancel_message. UserCanceled is any cancel the driver sent; cancel_message says whose.
CsvMaturedSwapInThe deposit's CSV matured with no word from the server.
ServerRefundedSwapOutThe server's CSV refund took the funds.
ClaimWindowClosedSwapOutThe CSV ran short before the preimage went out. The payment fails back once the server's CSV refund confirms, from block at at the earliest.

Completed and Canceled are terminal: the deal is settled. A SwapIn's funds can still move after it.

The record's server_status is the server's own label from the last time the driver reached it. Show it, so a swap waiting on the server says so. It is not a sign the server is up, and the driver never acts on it.

SwapIn​

SwapOut​

Canceling​

match swap.cancel().await? {
Cancellation::Requested => {}
Cancellation::TooLate => {}
}
AnswerMeaning
RequestedThe swap is canceled, or closes once the server confirms. Asking again answers Requested again.
TooLateThe payment already left: a SwapIn's deposit was claimed, or a SwapOut's preimage went out. The swap continues.