Skip to main content

Creating Swap Orders

Swap orders are market orders that automatically fetch a quote and create an order in one step. The SDK handles all the complexity of parameters, calculations, and signing.

Prerequisites

Before creating a swap order, make sure the following conditions are met:
  • Token approval: The sell token must be approved to the CoW Protocol Vault Relayer contract before the order can settle. Without approval, solvers cannot pull tokens from your wallet. See Token Approvals for full details.
  • Sufficient balance: Your wallet must hold enough of the sell token to cover the trade amount.
  • Buy order amounts: For buy orders, the actual sell amount will be higher than the raw exchange rate because it includes protocol fees and slippage tolerance. Always check the quote’s amountsAndCosts to see the real cost.
Use the check-and-approve pattern before posting an order:
// Check current allowance
const allowance = await sdk.getCowProtocolAllowance({ tokenAddress: sellToken, owner })

// Approve if needed
if (allowance < requiredAmount) {
  await sdk.approveCowProtocol({ tokenAddress: sellToken, amount: requiredAmount })
}
If you skip the approval step, the order will be created successfully but solvers will not be able to settle it. The order will eventually expire unfilled.

Basic Flow

The basic trading flow consists of three steps:
1

Get a quote (price) for a trade

The SDK fetches the current market price from the CoW Protocol API
2

Sign the order

Sign the order using EIP-712 signature
3

Post the order to the order-book

Submit the signed order to the CoW Protocol order book

Using postSwapOrder

The postSwapOrder method combines all three steps into one convenient function.

Required Parameters

  • kind - The order kind (OrderKind.SELL or OrderKind.BUY)
  • sellToken - The sell token address
  • sellTokenDecimals - The sell token decimals
  • buyToken - The buy token address
  • buyTokenDecimals - The buy token decimals
  • amount - The amount to sell/buy in atoms (smallest unit)

Example

import { SupportedChainId, OrderKind, TradeParameters, TradingSdk } from '@cowprotocol/sdk-trading'
import { ViemAdapter } from '@cowprotocol/sdk-viem-adapter'
import { createPublicClient, http, privateKeyToAccount } from 'viem'
import { sepolia } from 'viem/chains'

const adapter = new ViemAdapter({
  provider: createPublicClient({
    chain: sepolia,
    transport: http('YOUR_RPC_URL')
  }),
  signer: privateKeyToAccount('YOUR_PRIVATE_KEY' as `0x${string}`)
})

const sdk = new TradingSdk(
  {
    appCode: 'YOUR_APP_CODE',
  },
  {
    chainId: SupportedChainId.SEPOLIA,
  },
  adapter,
)

const parameters: TradeParameters = {
  kind: OrderKind.BUY,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  amount: '120000000000000000',
}

const { orderId } = await sdk.postSwapOrder(parameters)

console.log('Order created, id: ', orderId)

Optional Parameters

You can customize your swap order with these optional parameters:
ParameterTypeDefaultDescription
envEnvprodThe environment to use (prod or staging)
partiallyFillablebooleanfalseWhether the order can be partially filled
slippageBpsnumber50Slippage tolerance in basis points (BPS). One basis point = 0.01%
receiverstringorder creatorThe address that will receive the tokens
validFornumber1800 (30 mins)Order expiration time in seconds
partnerFeePartnerFee-Partner fee configuration (fee in BPS and recipient address)

Example with Optional Parameters

const parameters: TradeParameters = {
  kind: OrderKind.BUY,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  amount: '120000000000000000',
  // Optional parameters
  slippageBps: 200, // 2% slippage
  validFor: 1200, // 20 minutes
  receiver: '0xdef1ca1fb7f1232777520aa7f396b4e015f497ab',
  partiallyFillable: true,
}

const { orderId } = await sdk.postSwapOrder(parameters)
Slippage is expressed in basis points (BPS). For example:
  • 50 BPS = 0.5%
  • 100 BPS = 1%
  • 200 BPS = 2%

Advanced Settings

For more control over the order creation process, use SwapAdvancedSettings:

Quote Request Customization

import { SwapAdvancedSettings, PriceQuality } from '@cowprotocol/sdk-trading'

const advancedSettings: SwapAdvancedSettings = {
  quoteRequest: {
    priceQuality: PriceQuality.FAST,
    validFor: 120,
  },
}

const { orderId } = await sdk.postSwapOrder(parameters, advancedSettings)

Adding Hooks

You can add pre-hooks that execute before your order is settled:
const advancedSettings: SwapAdvancedSettings = {
  appData: {
    hooks: {
      version: 1,
      pre: [
        {
          target: '0xdef1ca1fb7fbcdc777520aa7f396b4e015f497ab',
          callData: '0x70a08231000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045',
          gasLimit: 21000,
        },
      ],
    },
  },
}

const { orderId } = await sdk.postSwapOrder(parameters, advancedSettings)

Two-Step Process: getQuote + postSwapOrderFromQuote

If you want to show the quote to users before creating an order, use the two-step approach:
// Step 1: Get quote
const { quoteResults, postSwapOrderFromQuote } = await sdk.getQuote(parameters)

const buyAmount = quoteResults.amountsAndCosts.afterSlippage.buyAmount

console.log(`You will get at least: ${buyAmount}`)

// Show quote to user and wait for confirmation
if (confirm(`You will get at least: ${buyAmount}, ok?`)) {
  // Step 2: Create order from quote
  const orderId = await postSwapOrderFromQuote()

  console.log('Order created, id: ', orderId)
}

Quote Results

The quoteResults object contains:
  • tradeParameters - Trade type, assets, amounts and optional parameters
  • amountsAndCosts - Order sell/buy amounts including network costs, fees and slippage
  • orderToSign - Order parameters ready for signing
  • quoteResponse - Raw DTO from the Quote API
  • appDataInfo - Order’s metadata
  • orderTypedData - EIP-712 typed data for signing
Quotes are time-sensitive and typically valid for 30 minutes. Make sure to post the order within the validity period.

Order Kinds

The SDK supports two order kinds:
Sell orders specify the exact amount you want to sell:
const parameters: TradeParameters = {
  kind: OrderKind.SELL,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  amount: '1000000000000000000', // Selling exactly 1 token
}
You’ll receive at least the quoted buy amount (minus slippage).

After Order Creation

Once postSwapOrder returns successfully, the order has been signed and submitted to the CoW Protocol order book. Here is what happens next:
  1. Solvers compete: The order enters the CoW Protocol auction where solvers compete to find the best execution path for your trade.
  2. Settlement: The winning solver settles the order on-chain, transferring tokens between parties.
  3. Surplus: If solvers find a better price than your limit, the surplus goes back to you.

Checking Order Status

Use the order UID returned by postSwapOrder to check the current status:
const order = await sdk.getOrder({ orderUid: orderId })

console.log('Status:', order.status)
Order status values:
StatusMeaning
openOrder is in the order book, waiting to be filled
fulfilledOrder has been fully executed on-chain
cancelledOrder was cancelled by the owner
expiredOrder passed its validTo timestamp without being filled
presignaturePendingOrder requires an on-chain pre-signature (smart contract flow)

Polling for Completion

If you need to wait for the order to fill:
const { orderId } = await sdk.postSwapOrder(parameters)

const pollInterval = 5000 // 5 seconds

const checkOrder = async () => {
  const order = await sdk.getOrder({ orderUid: orderId })

  if (order.status === 'fulfilled') {
    console.log('Order filled! TX hash:', order.executedTransactionHash)
    return
  }

  if (order.status === 'cancelled' || order.status === 'expired') {
    console.log('Order did not fill. Status:', order.status)
    return
  }

  console.log('Order still open, checking again...')
  setTimeout(checkOrder, pollInterval)
}

checkOrder()

Cancelling an Order

If you need to cancel a pending order, use off-chain cancellation:
await sdk.offChainCancelOrder({ orderUid: orderId })

console.log('Order cancelled')
Off-chain cancellation asks solvers to stop filling the order. It takes effect almost immediately but is not enforced on-chain. For guaranteed cancellation of smart contract orders, see Order Management.

Pre-Flight Checklist

Before calling postSwapOrder, verify:
  • Sell token approved to the Vault Relayer contract
  • Wallet has sufficient sell token balance
  • Token addresses are correct for the target chain
  • Amount is in the token’s smallest unit (atoms, e.g. wei for 18-decimal tokens)
  • slippageBps is set appropriately (default 50 = 0.5%)

Troubleshooting

Common issues when creating swap orders:
ProblemLikely CauseFix
InsufficientAllowance errorSell token not approved to Vault RelayerCall sdk.approveCowProtocol() before posting the order
InsufficientBalance errorWallet doesn’t hold enough sell tokenCheck balance before posting
Order created but never fillsLow liquidity or tight slippage toleranceIncrease slippageBps, try more common token pairs
Order expires immediatelyvalidFor too shortUse at least 300 seconds (5 minutes)
Quote fails with NoLiquidityToken pair not supported or no available poolsVerify token addresses are correct, try larger amounts

Next Steps

Last modified on March 18, 2026