Skip to main content
SODAX has supported cross-network limit orders for about eight months. They live in the same sodax.swaps module you already use for swaps, so if your app swaps through SODAX today, you are one method call away from letting users set a price on any network you support and walk away.

What a limit order is in SODAX

In SODAX, a limit order is not a separate product with its own contracts. It is a regular swap intent with one field changed: deadline = 0n. A normal swap intent carries a deadline. If it is not filled in time, it expires. A limit order has no deadline, so it stays open until one of two things happens:
  1. It is filled at or above the minOutputAmount you set.
  2. The creator cancels it.
That design has a nice consequence. Everything you already know about swap intents applies: the same parameters, the same cross-network routing through the SODAX liquidity layer, the same status calls, the same partner fee handling. Your minOutputAmount is your limit price.

The API surface

All limit order methods live on sodax.swaps: Both create methods take CreateLimitOrderParams, which is CreateIntentParams with deadline made optional. Whatever you pass for deadline, the SDK forces it to 0n. For React apps, @sodax/dapp-kit wraps the same calls in useCreateLimitOrder and useCancelLimitOrder. If you integrate over HTTP instead of the SDK, the Swaps API exposes POST /swaps/limit-orders to build a limit order intent.

Place a limit order

1

Pick your limit price

Call sodax.swaps.getQuote() to see what the market gives today, then set minOutputAmount to the amount you actually want to receive. For a buy below market, that is a higher output than the current quote.
2

Check the allowance

Like swap(), createLimitOrder() does not approve the input token for you. Call isAllowanceValid() and approve() first on EVM chains (and check the trustline on Stellar).
3

Create the order

Call createLimitOrder() with the intent params and the user’s wallet provider.
createLimitOrder() returns the same SwapResponse as swap(), wrapped in a Result. Store the intent object: you need it to cancel later. intentDeliveryInfo.dstTxHash is the hub transaction where the intent lives, and it is the hash you use to track the order. Source and destination do not have to match. The example above sells on BNB Chain and receives on Arbitrum, and the docs confirm limit orders work from Solana through the same createLimitOrder call.
Set your partner fee once in the constructor with new Sodax({ swaps: { partnerFee: { address, percentage } } }), or per call through the extras.partnerFee slot. Limit orders carry it exactly like swaps do.

How orders fill

Once the order is live on the hub, the SODAX liquidity layer can fill it whenever it can deliver at least minOutputAmount of the output token to dstAddress. Until then, the order simply waits. There is no keeper for you to run and no expiry to refresh. allowPartialFill controls whether the order can be filled in pieces. Leave it false for all-or-nothing orders. Set it to true if you are happy for a large order to fill in several steps while input remains. To show order state in your UI, poll sodax.swaps.getStatus({ intent_tx_hash }) with the hub transaction hash. A filled order reports SolverIntentStatusCode.SOLVED and includes fill_tx_hash. If you only hold the source chain transaction hash, sodax.swaps.getDetailedStatus({ srcChainKey, srcTxHash }) resolves the status from there.

Cancel an order

Because a limit order never expires, cancelling is how users get their funds back from an order they no longer want.
A few rules from the docs to build around:
  • You pass srcChainKey explicitly. Intent.srcChain is a relay chain ID, so the SDK needs the key to type the wallet provider, and it checks at runtime that the two match.
  • Only the creator can cancel an open limit order.
  • An intent with pending fills cannot be cancelled until those fills settle.
  • cancelLimitOrder returns Result<TxHashPair, Error | unknown>, not the SodaxError family the create methods use. Read error.message for diagnostics instead of switching on error.code.

Raw mode for custodial and server flows

If your backend builds transactions and a separate signer broadcasts them, use the intent only variant:
This returns the chain specific raw transaction without relaying it. You then relay it yourself, ideally through sodax.api.swaps.submitTx, with submitIntent as the fallback. createCancelIntent({ params, raw: true }) gives you the matching raw cancel transaction.

What to build with it

Limit orders turn a swap screen into a trading surface. A few ideas that need nothing beyond the methods above:
  • Buy the dip, any network. Let a user on Sui or Solana park a bid for an asset on another network and walk away.
  • Take profit. Pair an open position with a standing sell order at the user’s target.
  • Agent strategies. Orders persist with no deadline, so an AI agent can place, monitor with getStatus and cancel without babysitting expiries.
The full reference, including error codes and raw cancel relay details, lives in the Swaps module docs.