Skip to main content
The non-interactive swap contract settles every route whose endpoints both use arkade (Asset Swaps). The user funds it, and any solver fills it by paying the terms on output 0. It comes in two programs, one for each thing a fill can deliver: @arkade-os/swap ships the two programs as compiled JSON, swap-want-asset.program.json and swap-want-btc.program.json. The want-asset source is the one the SDK’s golden test compiles with arkadec and checks against the shipped program byte for byte (offer.test.ts in arkade-os/ts-sdk at 0ee3161). Both files below add exit, the third leaf the SDK appends in code. Copy the contract without changes. A change to the code, or to the order of the functions, changes the address.

Source

swap_want_asset.ark
swap_want_btc.ark
An offer published with noExit: true has no exit leaf. Delete the exit function and the exitDelay parameter to compile that two-leaf contract. It derives a different address.

Constructor

server is not a parameter. The client binds it to the operator key. The emulator key that cosigns fulfill is the per-network key pinned in @arkade-os/sdk, or the swap client’s emulatorPubkey override. The deposit side is not a parameter. The contract never inspects what it holds, so either program carries BTC, an asset, or an asset for an asset. The maker names are contract positions, not roles. They name the user who funds the swap (The maker Fields).

Functions

fulfill is a covenant. The operator and the emulator cosign it when every require passes, so it needs no signature from the user or the solver. Output 0 must pay makerWP as a version 1 taproot output, with at least wantAmount of the wanted asset or sats. Nothing else in the transaction is checked. cancel needs the user’s signature and no solver signature. It has no covenant and no timelock, so the deposit goes wherever the spend says. exit is the path if the operator is unavailable. After the deposit is unrolled onchain and exitDelay passes, the user alone signs. Neither fulfill nor cancel has a timelock, so the contract sets no fill deadline.

Fund the Swap

client.accept derives the contract and funds its address. The funding transaction carries the encoded offer in an extension packet of type 0x03, which is how solvers learn the terms.

Fill

A solver spends the deposit with fulfill and brings its own coins in the same transaction. The deposit is input 0. The emulator packet carries one entry, for input 0.
With a sponsor, the sponsor’s coins follow the solver’s on the input side. The sponsor’s fare and change outputs sit between output 0 and the solver payout.

Cancel

The user spends the deposit with cancel and pays it back to the wallet’s own address. Any asset on the deposit moves to output 0 with it.
A BTC deposit moves no asset and carries no extension, so the anchor is output 1.

Exit

exit is spendable only onchain, after a unilateral exit has published the deposit’s virtual output. It has no server key and no covenant.
Witness: [userSig, script, controlBlock].

Sources

  • Asset Swaps: the lifecycle and the guarantees of this contract
  • offer.test.ts: the golden addresses and the artifact with exit