Skip to main content

Limit Orders

Limit orders allow you to specify an exact buy amount you want to receive for selling your tokens. Unlike market orders, limit orders won’t execute until the price reaches your specified level.

What are Limit Orders?

A limit order lets you:
  • Set a specific price (buy amount) for your trade
  • Wait for favorable market conditions
  • Avoid slippage from market movements
  • Have orders valid for extended periods (up to 1 year)

Basic Limit Order

import { TradingSdk, OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk'

const sdk = new TradingSdk({
  chainId: SupportedChainId.MAINNET,
  appCode: 'MyApp',
  signer: wallet,
})

// Post a limit order
const result = await sdk.postLimitOrder({
  chainId: SupportedChainId.MAINNET,
  kind: OrderKind.SELL,
  sellToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
  sellTokenDecimals: 18,
  buyToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
  buyTokenDecimals: 6,
  sellAmount: '1000000000000000000', // 1 WETH
  buyAmount: '2000000000', // 2000 USDC (minimum)
  slippageBps: 0, // No slippage for limit orders
})

console.log('Limit order created:', result.orderId)

Complete Example with Ethers

import { JsonRpcProvider, Wallet } from 'ethers'
import {
  setGlobalAdapter,
  SupportedChainId,
  TradingSdk,
  OrderKind,
} from '@cowprotocol/cow-sdk'
import { EthersV6Adapter } from '@cowprotocol/sdk-ethers-v6-adapter'

const RPC_URL = 'https://eth.llamarpc.com'
const PRIVATE_KEY = '0x...'

async function createLimitOrder() {
  const chainId = SupportedChainId.MAINNET

  // Setup
  const provider = new JsonRpcProvider(RPC_URL, chainId)
  const wallet = new Wallet(PRIVATE_KEY, provider)
  const adapter = new EthersV6Adapter({ provider, signer: wallet })
  setGlobalAdapter(adapter)

  const sdk = new TradingSdk({
    chainId,
    appCode: 'LimitOrderExample',
    signer: wallet,
  })

  const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
  const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'

  // Create limit order: Sell 1 WETH for at least 2000 USDC
  const result = await sdk.postLimitOrder({
    chainId,
    kind: OrderKind.SELL,
    sellToken: WETH,
    sellTokenDecimals: 18,
    buyToken: USDC,
    buyTokenDecimals: 6,
    sellAmount: '1000000000000000000', // 1 WETH
    buyAmount: '2000000000', // 2000 USDC minimum
    slippageBps: 0,
  })

  console.log('Limit order ID:', result.orderId)
  console.log('View at: https://explorer.cow.fi/orders/' + result.orderId)
}

createLimitOrder()

Advanced Settings

Custom Validity Period

Set how long the order should remain valid:
const result = await sdk.postLimitOrder(
  {
    // ... order parameters
  },
  {
    validTo: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7, // Valid for 7 days
  }
)

Partially Fillable Orders

Allow your order to be filled in multiple transactions:
const result = await sdk.postLimitOrder(
  {
    // ... order parameters
  },
  {
    additionalParams: {
      partiallyFillable: true,
    },
  }
)

App Data Metadata

Add custom metadata to your order:
const result = await sdk.postLimitOrder(
  {
    // ... order parameters
  },
  {
    appData: {
      metadata: {
        quote: {
          slippageBips: 0,
        },
        orderClass: {
          orderClass: 'limit',
        },
      },
    },
  }
)

Key Differences from Swaps

FeatureMarket Order (Swap)Limit Order
ExecutionImmediateWhen price condition is met
SlippageMay have slippageNo slippage (fixed price)
Buy AmountEstimatedExact minimum
ValidityMinutesUp to 1 year
Order Typemarketlimit

Checking Order Status

After creating a limit order, monitor its status:
import { OrderBookApi } from '@cowprotocol/sdk-order-book'

const orderBookApi = new OrderBookApi({ chainId })
const order = await orderBookApi.getOrder(result.orderId)

console.log('Status:', order.status) // 'open', 'filled', 'cancelled', 'expired'
console.log('Executed amount:', order.executedSellAmount)

Cancelling a Limit Order

Off-chain Cancellation (Free)

const cancellation = await sdk.offChainCancelOrder({
  chainId,
  orderUid: result.orderId,
})

console.log('Order cancelled')

On-chain Cancellation

For presigned orders, you need an on-chain transaction:
const tx = await sdk.cancelOrderOnChain({
  chainId,
  orderUid: result.orderId,
})

await tx.wait()
console.log('Order cancelled on-chain')

Best Practices

  1. Set Realistic Prices: Ensure your limit price is achievable based on market conditions
  2. Check Allowances: Verify token approval before posting the order
  3. Monitor Orders: Track order status to know when they execute
  4. Use Appropriate Validity: Don’t set overly long validity periods for volatile markets
  5. Consider Fees: Factor in network costs when setting buy amounts

Example: Buy Order

Create a limit order to buy tokens:
const result = await sdk.postLimitOrder({
  chainId,
  kind: OrderKind.BUY, // Buying exact amount
  sellToken: USDC,
  sellTokenDecimals: 6,
  buyToken: WETH,
  buyTokenDecimals: 18,
  sellAmount: '2000000000', // Max 2000 USDC to spend
  buyAmount: '1000000000000000000', // Buy exactly 1 WETH
  slippageBps: 0,
})

Error Handling

try {
  const result = await sdk.postLimitOrder(params)
  console.log('Order created:', result.orderId)
} catch (error) {
  if (error.message.includes('InsufficientAllowance')) {
    console.error('Need to approve tokens first')
  } else if (error.message.includes('InsufficientBalance')) {
    console.error('Not enough tokens')
  } else {
    console.error('Order creation failed:', error)
  }
}

Next Steps

  • Learn about order management
  • Explore React integration
  • Read about creating limit orders
Last modified on March 4, 2026