Lifecycle
1
Create the swap
Call
swaps.createSwap with your stable userRef, the input token and amount, and the output token.
OneSwap resolves the { inSymbol, outSymbol } pair to a visible pool and returns a
Swap in status awaiting_deposit with a per-user depositParty and a deadline.2
The user funds the deposit party
Tell your end-user to send
amountIn of inSymbol to swap.depositParty before
swap.deadline. This is a normal token transfer — the user’s wallet never signs a swap.3
OneSwap detects and swaps
Once the deposit lands on-ledger, the swap moves to
deposit_detected, then swapping
while the atomic swap executes.4
Output is returned to sender
On success the swap reaches
returned: amountOut of outSymbol is sent back to
senderParty — the exact party that funded the deposit.Status reference
Terminal statuses arereturned, refunded, expired, failed, and cancelled.
Deposit-amount tolerance
The deposit must be within 1% ofamountIn. If the amount that arrives is outside that band, the swap is refunded — OneSwap never guesses intent from a wrong amount. Show your users the exact amountIn and inSymbol and make it easy to send precisely that.
Deposit deadline
Every swap has a 60-minute deposit window from creation, exposed asdeadline (an ISO timestamp). If no deposit arrives before then, the swap becomes expired and nothing happens — the user was never charged. Surface the countdown to your user and create a fresh swap if they miss the window.
Slippage and minimum output
By default OneSwap applies 2% (200 bps) slippage tolerance. You can override it per swap:slippageBps— set a different tolerance in basis points (e.g.100for 1%).minOut— set a hard floor on the output amount. If the swap would return less thanminOutofoutSymbol, it is refunded instead.
Return-to-sender semantics
The output is always paid back to the party that funded the deposit, reported assenderParty on the returned swap. You do not supply a destination address — there isn’t one to get wrong. This is what makes these swaps safe for fund-transfer-only wallets: the user gets their output at the same party they sent from.
One open swap per user
At most one open (non-terminal) swap peruserRef may exist at a time. If you call createSwap for a userRef that already has an open swap, the call throws OpenSwapExistsError:
this user already has an open swap; finish or let it expire firstYou do not have to wait out the deadline.
swaps.getOpenSwap(userRef) returns that open swap — use it to recover the id when you no longer have it (after a restart, or when the createSwap response was lost) — and swaps.cancel(id) closes it if no deposit has arrived yet:
cancel throws ConflictError (409) in that case, so wait it out instead. See Error handling for how to detect and recover from this.
One pool per swap
Every swap settles against exactly one pool. The{ inSymbol, outSymbol } pair must have a live pool that trades it directly; if it doesn’t, createSwap errors (and quotes.get throws NoDirectPoolError). There is no multi-hop routing — to move between two tokens with no shared pool, run two swaps through an intermediate asset (usually CC), each with its own settlement and fees.
SDK 1.3.0 and later accept poolId in createSwap. Pass the poolId returned by quotes.get
to guarantee that settlement uses the pool you quoted.
Network fee comes from the input
A per-swap network fee is taken from the input token to cover the on-chain settlement cost. It is priced live for every swap — the measured cost of settling the swap on Canton (the swap’s traffic size × the network’s current price per MB, plus a small buffer), converted into the input token — so it tracks the real cost rather than a fixed amount (typically around $1.5–2 at recent network prices, and it moves with the network). Your end-user’s wallet needs no CC or gas of any kind — they only ever send the input token. Account for this when you quote amounts to your users: the output reflects the input minus this network fee and the pool’s 0.30% swap fee.Atomic settlement
Swaps are atomic DvP. The swap either completes and returns the output token, or the input is refunded — funds are never stranded by a partial swap. That means every swap you create ends in a clean terminal state you can act on.Reconciling on your side
Use your ownuserRef as the reconciliation key:
- Store the returned
swap.id(anesc_...id) against youruserRefwhen you create a swap. - One open swap per
userRefmeans there is never ambiguity about which swap a user’s deposit belongs to. - On terminal status, record the outcome:
returned(withamountOut),refunded,expired,cancelled, orfailed(witherror).
Polling for status
PollgetSwap on your own cadence:
Awaiting completion
waitForSwap wraps the polling loop for you and resolves on the first terminal status (or on timeout):
Swaps are live on OneSwap devnet and mainnet — see API keys for
getting your
sk_live_... credential.