Skip to main content
A trade that does not settle before its deadline gives everyone their money back. The escrows run the cancel themselves, in permissionless steps that anyone may send. The relayer sends them for you and mirrors the progress onto the trade. This page covers what happens on chain, and the one read route that serves everything you need to send each step from your own wallet. See Cancels and refunds for the concept.

Endpoints

There is no cancel endpoint

No relayer route cancels, refunds or claims. Every one of those is a permissionless contract call that takes the order’s parameters. The relayer sends them as each becomes possible, and any wallet may send them too. GET /v1/trades/:id/cancel hands out what each call needs, proofs included. The trade page offers a button for each step that applies, built on this route. Two settlement routes refuse work once a trade needs the cancel path:

Who is the primary

The AdManager on the ad chain is the primary. Only there does a clock run, and only there is the cancel decided. The OrderPortal on the order chain follows. It has no clock after the deadline: it refunds the bridger only against a proof of the primary’s cancel leaf, and pays the maker against the primary’s settled or forfeit leaf. Nothing on it can refund on time alone, so nothing can get ahead of the primary’s decision. Those proofs are checked against a root of the ad chain published by the anchor service. If no root is anchored yet, the refund waits until one is.

What happens on chain

None of these calls checks who sends it, and none is stopped by a pause. A pause stops only new ads, funding, locks and deposits, never an exit. EVM names first, Stellar names in brackets. The dispute calls (finalizeDispute) are on Disputes. A few things a client needs to know:
  • Payouts keep working into the window, but not equally. The AdManager payout to the bridger is accepted until just before the window ends. The OrderPortal payout to the maker stops shortly before the deadline. So past the deadline the maker cannot settle by co-signature, but the bridger still can until the window closes.
  • The window’s end is a view. cancelFinalizesAt(params) (cancel_finalizes_at) returns it, grace included, or 0 when no window is open. The relayer copies it into the trade’s claimFinalizeAt. When the maker halted settlement on this order, the window gets an extra grace period. See Deadlines and clocks.
  • A payout that fails to push is credited, not lost. The amount waits in claimable(recipient, token) and the recipient pulls it with claim(recipient, token), which works during a pause too.

Every self-serve ending

GET /v1/trades/:id/cancel lists every call a party can send to end the trade: the cancels and refund, the forfeit payout, and the settled evidence. For each it gives the chain and escrow, the order’s parameters, when the chain accepts it, and, for the calls that take a proof, the proof the relayer built. It needs no auth, although the trade itself is party-only. It is the refund’s liveness path: a party who lost its session, or anyone it asks for help, can still send the refund. Every field is public, every call is permissionless, and a refund always pays params.bridger, whoever sends it. The route has a strict per-IP rate limit.

Paths

Step states

Step states come from the two escrows, so a call you sent yourself shows done on the next read. Chain reads are shared between callers for 15 seconds. If a read fails, the states fall back to the relayer’s records and stateFrom is records-fallback: a step may then show ready although it is done. Show that as “status unconfirmed”. Sending a call too early, or twice, only reverts.

Sending each call

The escrow is contractAddress on chainId. On Stellar, the 32-byte fields are BytesN<32>. targetRoot, nullifierHash and proof come from the step’s package.

Keep the packages

The proofs need nothing secret: each proves a leaf already on the other chain, against a root the target chain has already anchored. Only the relayer builds them, and the route serves a package as soon as the chain allows the call and the relayer has proved it. A package does not expire, so download each one when it appears and keep it with the trade: you can still send it if the relayer’s API is unreachable later. claimCancel and finalizeCancel need no proof and work from the saved params alone. Packages are removed 24 hours after the trade ends.

What to poll

Poll GET /v1/trades/:id for the trade’s progress through the cancel, and GET /v1/trades/:id/cancel when you want to send a step yourself. The trade never moves backwards. Once the AdManager has cancelled and the refund is still to land, the trade stays CLAIMED with the window’s end in claimFinalizeAt until the refund lands and it becomes CANCELLED. The cancelReason values are listed on Trades. GET /v1/trades/:id/settlement follows along: Claimed while the trade is CLAIMED, Disputed while DISPUTED, and Cancelled with signaturesCollected: 0 once it is CANCELLED. Both parties also get a TRADE_CANCELLED notification, with text chosen by the reason.