Repository navigation
Releases: Blockstream/anyswap
Releases · Blockstream/anyswap
Release list
1.8.0
Rust: anyswap-sdk, anyswap-core
- Breaking:
HttpClient::newtakes theWalletthat signs protected
requests instead of its identityPrivateKey, and returns aResult.
set_private_keyis gone.
Minor
Walleterases its master key and seeds once its keys are derived, and its
keys when it drops. AMnemonicerases its words when it drops.
TypeScript: @blockstream/anyswap-sdk, @blockstream/anyswap-wasm
- Breaking:
AnySwapClienttakes thewalletthat signs protected
requests instead ofauth.identityPrivkey.AnySwapAuthis gone. - Breaking:
signalsandsubscribetake nouserId; they use the
client's wallet. - Breaking:
Wallet.identityPrivkeyis gone, and so are the bindings'
signRequestandgetPubkey: the client signs inside the wasm module, so
the identity key never leaves it.
1.7.0
Rust: anyswap-sdk, anyswap-core
- A SwapIn fund is
Dustunless it is worth its refund fee plus 546 sat on
Bitcoin, andpartition_economicalweighs outputs the same way.
TypeScript: @blockstream/anyswap-sdk, @blockstream/anyswap-wasm
- Breaking: the SDK exports what an app driving swaps uses.
SwapIn,
SwapOut,SwapUtxo,EconomicalSplit,DepositClassification,
validateSwap,sourceAsset,AnySwapClient.watchChangesand
SwapChanges, the Esplora clients'addressUtxosandaddressUtxoListing
withEsploraUtxo, andsignRequestwith its header constants,
AuthHeadersandRawBodyare gone. The claim and refund builders under the
driver stay public in the Rustanyswap-sdkcrate. - Breaking:
WalletkeepsuserId,network, the identity keys,
sourceRefundPubkeyanddestClaimPubkey. Its private swap keys, its
blinding keys,preimageandpaymentHashare gone; the driver derives them
itself. - Breaking:
@blockstream/anyswap-wasmkeeps the driver and what this SDK
calls.SwapIn,SwapOut,SwapUtxo,EconomicalSplit,serviceFee,
minSendForReceive,maxReceiveForSend, andWallet's private swap keys,
blinding keys,preimageandpaymentHashare gone. - A swap-in fund is
Dustunless it is worth its refund fee plus 546 sat on
Bitcoin.
1.6.0
- Breaking:
Status::Confirminggainsmax_fee_rate, the chain's, so a
fee_rate_spikecan be shown against it. - Breaking:
Quotegainsawait_opening_tx, how long after creation the
server waits for a SwapIn deposit to confirm, and so the expiry to give the
claim invoice.
Minor
- A SwapIn's
Fundingexpires_atismin_confs + 1blocks before the claim
invoice expires, so a deposit made by then confirms in time.
funding_timeoutonly caps it and defaults to 24 h, where it was 20 min. A
claim invoice needs to outlastmin_confs + 1blocks, where it needed
funding_timeoutmore.
1.5.0
- Breaking:
Status::Confirminggainsfee_rate_spike, the fee estimate
while it is abovemax_fee_rateand holds a SwapOut's preimage. - Breaking:
with_chainreturns aResult, refusing amax_fee_rate
that is not finite and positive withDriverError::InvalidChainConfig.
1.4.0
- Breaking: the driver reports the miner fee of the user's own spends as
fee, read from the transaction on chain: a SwapOut claim's in
Status::ClaimingandStatus::Completed, a SwapIn refund's in
FundState::RefundingandFundState::Refunded, where a batched refund's
fee is the whole transaction's on every fund it took.Spendercarries it
too. A stored swap still loads, with nofeeuntil a pass reads it again. - Breaking:
Configgainsfee_rate_cache_ttl, how long a chain's fee
estimate is reused, 30 seconds by default, so a sweep reads it once per
chain rather than once per swap. Zero reads it on every pass, as before. - Breaking:
Configgainsserver_timeout, 30 seconds by default. A call
to the server that goes unanswered that long fails as a transport error,
where the driver used to wait on it without limit. - Breaking:
max_htlc_holdmoves fromChainConfigtoConfigand caps
a SwapOut hold invoice'smin_final_cltv_expiry_deltaon its own, 1008
Lightning blocks by default, where it used to be added to the server's
dest_csv. - Breaking:
CancelReasongainsClaimWindowClosed { at }. A SwapOut
with less thanclaim_marginof the CSV left before its preimage went out
endsCanceledat once, its payment failing back once the server's CSV
refund takes the opening from blockat. It used to stayConfirming
until that refund confirmed. - A SwapOut's
Funding.expires_atis no later than the expiry of
claim_invoice, so it is the time to pay by, and the driver's cancel goes
out then. - A SwapOut holds its preimage while the fee estimate is above
max_fee_rate, so its claim pays the current rate. The swap stays
Confirmingmeanwhile. cancelanswersRequestedfor a swap already canceled, where it answered
TooLate. Against a 1.4.0 server, a cancel retried after a lost answer
getsRequestedtoo.runtakes a quiet SwapIn up again once the chain's cached fee rate makes
one of itsDustfunds worth refunding, where it used to leave the fund
Dustuntil a manualsteporrefund.- A SwapOut claim that replaces a pending preimage claim or the server's
refund goes through the preimage path even once the server's key is known,
so the replacement pays more in all and is accepted. - A restored swap's
ended_atis the server'stransitioned_atonly up to
the time of the restore. - On wasm32 the driver holds a Web Lock per swap from loading its record to
saving it, wherenavigator.locksexists, so tabs and workers over one
store take turns on a swap. Natively a store still belongs to one process. restore_allstops paging at a page with no swap it has not seen whose
request the wallet signed, where it used to follow the server'shas_next
alone, and reports a swap listed twice once.BitcoinEsploraandLiquidEsploragive up on a request after 30 seconds,
where they used to wait on it without limit;with_timeoutsets another
limit. AChainClientof your own should bound its requests the same way,
since the driver waits on a chain call for as long as it takes.- The driver refunds at most 8 of a SwapIn's funds in one transaction, the
most valuable first, and the rest once that refund is in a block, so funds
can stayRefundablewhile another refund isRefunding. A pass calls
outspendfor as many strays, those in the pending refund first, and for
none stillLocked. subscribeyields a swap's handle again when a pass clears its error,
where a pass that changed nothing else used to stay silent.DriverError::retryableis true for an HTTP 429 from the server or
anything in front of it.
1.3.0
- Breaking: the wallet derives its keys from a seed of its own, so the same
mnemonic gives a differentuser_idand different swap keys. Swaps made
with an earlier SDK are not listed or restored; finish them with the SDK
that made them. - Breaking:
SwapWallet::pubkeyandprivkeyare split into
source_refund_pubkey/source_refund_privkeyand
dest_claim_pubkey/dest_claim_privkey. - Breaking: the driver's
Config::trust_unsignedis removed, sorestore
refuses a swap the server holds no signed request for. - Breaking: the driver has one swap handle type,
Handle, in place of
Swap,SwapInHandleandSwapOutHandle. It keeps no copy of the swap,
sorecord,status,addressandclaim_invoiceread the store and are
async, and a call meant for the other swap type fails withWrongSwapType. - Breaking: the server's status is kept in the swap record as
server_status, so it survives a restart, andServerStatusis now the
status name alone. Updates now also fire when only the server's status
changes. - Breaking: the
Destinationsmethods are async and return aResult;
anErrfails the call asDriverError::Destination. - Breaking:
restore_alltakes no query. It restores every swap the
server lists for the wallet that the store lacks. - Breaking:
ClientError::HeaderandClientError::Jsoncarry a message
instead of the source error, so every error can be cloned. - Breaking: amounts in sats serialize as decimal strings, in the API
types and in the driver'sQuote,SwapRecordandStatus. The Rust
fields are unchanged, but a store written before this holds numbers and no
longer loads; finish or drop those swaps first. - Breaking:
SwapScript::spend_pathreads from an input's witness how it
spent the swap output:SpendPath::Keypath,Preimagewith the verified
preimage, orCsv. The driver'sSpendercarries it aspathin place of
preimageandpays_address, andTx::preimage_at,Tx::paysand
SwapScript::destination_scriptare gone. - Breaking: a SwapOut's claim is a spend of the opening through the
keypath or the preimage leaf, which the server's key alone cannot open. It
used to be any spend paying the claim address. - Breaking: the driver's opening, a SwapIn deposit or a SwapOut opening,
is the oldest output paying exactly the swap's amount, and every other
output is a stray. Two such outputs used to mean none.Observed::unique
isObserved::split, which returns the opening and the strays. - Breaking: a SwapOut sends its preimage once, at the release gate, then
claims every pass until a claim of the opening is in a block, rebuilt at the
current fee rate: by keypath when the server answered with its key, by
preimage once the opening is atmin_confswhen it did not. A spend still in
the mempool is outbid, the server's CSV refund atmax_fee_rate, where the
driver used to wait on it and to resend its own claim unchanged. The
preimage is marked tried and saved before the request, and any answer
counts as tried.CoopKeyandSpendingare oneClaiming,Lostis a
Canceledwith itsopening, andConfig::coop_timeout,
SwapRecord::committed_at,Action::Commit,Spend::Rebroadcastand
Spender::tx_hexare gone. A store holding a SwapOut inCoopKey,
SpendingorLostno longer loads; finish those swaps first. - Breaking: a restored SwapOut no longer takes the server's
Claimedas
its preimage having left. It counts the preimage as out only when the
server's key verifies or a claim of ours on chain shows it, and otherwise
sends it through the release gate like any other.SwapRecord::preimage
holds a SwapOut's own preimage once a claim shows it. - Breaking: a SwapIn's status is worked out from the chain and the
server's key and preimage on every pass, and it endsCompletedor
Canceled.Status::Refundis gone, along with the early returns that
kept a storedCompletedorRefundforever. What under the script is the
user's is the record'sfunds, read withHandle::funds: oneFundper
output,Locked,Refundable,Dust,RefundingorRefunded. Every
pass refunds whatever isRefundablein any status, where strays used to
come back only inRefundor by hand. Whose a spend is reads its path, and
a keypath refund is taken only while our refund key is home.
Handle::refundis a pass with the given destination.Action::Closeis
gone,SwapRecordgainsfundsandended_at, andrefund_timeout
counts from a SwapIn's end.Confirmingno longer carriesmatures_at,
which nothing read. A store holding a SwapIn inRefundno longer loads;
finish those swaps first. - Breaking:
ChainClienthas a new required method,outspend(txid, vout): the transaction spending an output, mempool included, orNone
while it is unspent. Each pass asks it about the opening and, on a SwapIn,
each output worth its refund fee, when the address history shows them
unspent. Only a failure on the opening fails the pass.BitcoinEsploraand
LiquidEsploraanswer it from/tx/:txid/outspend/:vout. - Breaking:
SwapRecordgainsbase_feeandservice_fee, the server's
split ofsend_amount - receive_amountas acceptance checked it. A store
written before this no longer loads. - Breaking:
Status::Canceledcarries areason:ServerCanceledwith
the server'serror_typeandcancel_message,CsvMaturedfor a SwapIn
whose deposit's CSV matured with no word from the server, or
ServerRefundedfor a SwapOut the server's CSV refund took. The server's
cancel is kept in the record asserver_cancelfrom the first pass that
reads it, so a SwapOut canceled before any opening staysCanceledthrough
a pass the server does not answer, where it used to readFundingagain. - Breaking: a restored swap is
Status::Restoringuntil its first pass,
the loop's or astep, where it used to readFundingwhatever it stood
at, so a page could show an ended SwapIn's deposit address as open.
canceltakes it as open, and the server refuses what is past. - Breaking: the driver sends the protocol version built into core,
PROTOCOL_VERSION, the release's major and minor version, where it used to
send back whatever the server's/v1/inforeported. A quote from a server
on another version fails withRefusal::ProtocolVersion, so the SDK and
the server have to share a minor version.Quoteno longer carries
protocol_version. - Breaking: both crates declare
rust-version = "1.91", up from 1.85. - Breaking:
SwapStore::listreturns the stored swap ids instead of the
records. The driver loads each record on its own, so one that fails to load
stops only its own swap. It used to stop every pass ofrunand fail
restore_all.
Minor
- A pass whose message or spend fails still saves what it saw and refunds
what is refundable, then returns the error. A cancel or refund key the
server could not take used to end the pass before the refund, so with the
server gone a SwapIn's stray deposit never came back, even past its CSV,
andHandle::refundfailed the same way.Funding'scancel_sentnow
turns true only once the cancel is delivered. - A pass whose refund fails after it saved a change still announces that
change, where the next pass used to see nothing new and never did. - The driver's
runloop ends onstop, andwait_stoppedresolves once it
has exited;statesays where the loop is.Updatesend once the driver
is stopped and drained. - Creating or restoring a swap wakes the loop, and a second
runis a no-op. PROTOCOL_VERSIONis re-exported, and the wasm crate returns it from
protocolVersion(), for a request built by hand.
1.2.0
- Breaking:
POST /v1/swaptakessend_amountinstead ofswap_fee_limit
and accepts only asend_amountthat buys exactlyreceive_amount.
swap_fee_limitis gone from the swap state and the SDKs. - Breaking: the SDK driver's
quotepins either the amount to receive or
the amount to send. The driver cannot restore swaps created before this
release.
Minor
- The driver no longer fails a step when resending an observed, unconfirmed
spend is refused, as when the chain source lags a block behind the node.
The status staysSpendingwith the observed txid. LiquidEsplorakeeps the transaction bodies it has fetched, so reading an
address history costs one request per pass once its transactions are known,
instead of one more per transaction.
1.2.0-rc.2
- First release on crates.io. Both crates declare
rust-version = "1.85",
checked in CI with every feature on.
1.2.0-rc.1
Core
- Swap scripts, transactions and MuSig2 signing for Bitcoin and Liquid, fee
estimation, and the server API types. Esplora chain backends sit behind the
esplorafeature, OpenAPI derives behindopenapi.
SDK
HttpClientfor the server API (client), a WebSocket subscription that
paces the driver (ws, native only), and the swap driver (driver) that runs
any number of swaps to completion, verifying statuses against the chain rather
than the server's reports.esploraaddsBitcoinEsploraandLiquidEsplora.
Builds for wasm32.