> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cow.bleu.builders/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating Limit Orders

> How to create limit orders with specific price targets using the CoW Protocol SDK

# Creating Limit Orders

Limit orders allow you to specify both the sell and buy amounts, creating an order that will only execute at your desired price or better.

## Overview

Unlike swap orders that execute at market price, limit orders give you precise control over the exchange rate. The order will only be filled when the market price reaches your specified rate.

<Note>
  Limit orders are "good-til-cancelled" by default and remain in the order book until filled or cancelled.
</Note>

## Prerequisites

Before creating a limit order, make sure:

1. **Token approval**: The sell token must be approved to the CoW Protocol Vault Relayer contract. Without this, the protocol cannot move your tokens when the order fills. See [Token Approvals](/cow-sdk/guides/token-approvals) for full details.

2. **Sufficient balance**: Your wallet must hold enough of the sell token to cover the `sellAmount`. The order will fail at submission if balance is insufficient.

3. **For buy limit orders**: The `sellAmount` you specify is the *maximum* you will pay. You may end up paying less if solvers find a better route.

### Check and Set Approval

```typescript theme={null}
// Check current allowance
const allowance = await sdk.getCowProtocolAllowance({ tokenAddress: sellToken, owner })

// Approve if needed
if (allowance < BigInt(sellAmount)) {
  await sdk.approveCowProtocol({ tokenAddress: sellToken, amount: BigInt(sellAmount) })
}
```

### Pre-Flight Checklist

Before submitting your limit order, verify:

* Sell token approved to Vault Relayer
* Wallet has sufficient sell token balance
* Token addresses are correct for the target chain
* Amounts are in token atoms (smallest unit) — watch decimal differences (USDC = 6 decimals, WETH = 18 decimals)
* Limit price is reasonable relative to the current market
* `validTo` gives enough time for the market to reach your price

## Using postLimitOrder

The `postLimitOrder` method creates a limit order with your specified amounts.

### 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
* `sellAmount` - The amount to sell in atoms
* `buyAmount` - The amount to buy in atoms

### Basic Example

<CodeGroup>
  ```typescript Viem Adapter theme={null}
  import {
    SupportedChainId,
    OrderKind,
    LimitTradeParameters,
    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({
    chainId: SupportedChainId.SEPOLIA,
    appCode: 'YOUR_APP_CODE',
  }, {}, adapter)

  const limitOrderParameters: LimitTradeParameters = {
    kind: OrderKind.BUY,
    sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
    sellTokenDecimals: 18,
    buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
    buyTokenDecimals: 18,
    sellAmount: '120000000000000000',
    buyAmount: '66600000000000000000',
  }

  const { orderId } = await sdk.postLimitOrder(limitOrderParameters)

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

  ```typescript Ethers v6 theme={null}
  import {
    SupportedChainId,
    OrderKind,
    LimitTradeParameters,
    TradingSdk
  } from '@cowprotocol/sdk-trading'
  import { EthersV6Adapter } from '@cowprotocol/sdk-ethers-v6-adapter'
  import { ethers } from 'ethers'

  const provider = new ethers.JsonRpcProvider('YOUR_RPC_URL')
  const signer = new ethers.Wallet('YOUR_PRIVATE_KEY', provider)

  const adapter = new EthersV6Adapter({ provider, signer })

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

  const limitOrderParameters: LimitTradeParameters = {
    kind: OrderKind.BUY,
    sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
    sellTokenDecimals: 18,
    buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
    buyTokenDecimals: 18,
    sellAmount: '120000000000000000',
    buyAmount: '66600000000000000000',
  }

  const { orderId } = await sdk.postLimitOrder(limitOrderParameters)

  console.log('Order created, id: ', orderId)
  ```
</CodeGroup>

## Optional Parameters

| Parameter           | Type         | Default       | Description                                          |
| ------------------- | ------------ | ------------- | ---------------------------------------------------- |
| `quoteId`           | `number`     | -             | ID of a quote from the Quote API to use as reference |
| `validTo`           | `number`     | -             | Order expiration timestamp in seconds since epoch    |
| `env`               | `Env`        | `prod`        | The environment to use (`prod` or `staging`)         |
| `partiallyFillable` | `boolean`    | `false`       | Whether the order can be partially filled            |
| `receiver`          | `string`     | order creator | The address that will receive the tokens             |
| `partnerFee`        | `PartnerFee` | -             | Partner fee configuration                            |

### Example with Optional Parameters

```typescript theme={null}
const limitOrderParameters: LimitTradeParameters = {
  kind: OrderKind.SELL,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  sellAmount: '1000000000000000000',
  buyAmount: '2000000000000000000',
  validTo: Math.floor(Date.now() / 1000) + 86400, // Valid for 24 hours
  partiallyFillable: true,
}

const { orderId } = await sdk.postLimitOrder(limitOrderParameters)
```

## Calculating Limit Price

The limit price is determined by the ratio of `sellAmount` to `buyAmount`.

### Example: Setting a Limit Price

```typescript theme={null}
// You want to sell 1 WETH for at least 3000 USDC
const wethDecimals = 18
const usdcDecimals = 6

const limitOrderParameters: LimitTradeParameters = {
  kind: OrderKind.SELL,
  sellToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
  sellTokenDecimals: wethDecimals,
  buyToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
  buyTokenDecimals: usdcDecimals,
  sellAmount: '1000000000000000000', // 1 WETH (18 decimals)
  buyAmount: '3000000000', // 3000 USDC (6 decimals)
}

const { orderId } = await sdk.postLimitOrder(limitOrderParameters)
```

<Note>
  **Price calculation:**

  * Limit price = buyAmount / sellAmount (in token units)
  * In this example: 3000 USDC / 1 WETH = 3000 USDC per WETH
</Note>

## Using Quote ID

You can reference a previous quote when creating a limit order:

```typescript theme={null}
// First, get a quote
const { quoteResults } = await sdk.getQuote({
  kind: OrderKind.SELL,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  amount: '1000000000000000000',
})

const quoteId = quoteResults.quoteResponse.id
const sellAmount = quoteResults.orderToSign.sellAmount
const buyAmount = quoteResults.orderToSign.buyAmount

// Create limit order with quote ID
const limitOrderParameters: LimitTradeParameters = {
  kind: OrderKind.SELL,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  sellAmount,
  buyAmount,
  quoteId, // Reference the quote
}

const { orderId } = await sdk.postLimitOrder(limitOrderParameters)
```

## Advanced Settings

Customize limit order behavior with `LimitOrderAdvancedSettings`:

```typescript theme={null}
import { LimitOrderAdvancedSettings, SigningScheme } from '@cowprotocol/sdk-trading'

const advancedSettings: LimitOrderAdvancedSettings = {
  additionalParams: {
    signingScheme: SigningScheme.EIP712,
  },
  appData: {
    metadata: {
      quote: {
        slippageBips: '0', // No slippage for limit orders
      },
    },
  },
}

const { orderId } = await sdk.postLimitOrder(
  limitOrderParameters,
  advancedSettings
)
```

## Order Kinds for Limit Orders

<Tabs>
  <Tab title="SELL Limit Orders">
    Sell orders guarantee you receive **at least** the specified `buyAmount` for your `sellAmount`:

    ```typescript theme={null}
    const limitOrderParameters: LimitTradeParameters = {
      kind: OrderKind.SELL,
      sellAmount: '1000000000000000000', // Selling exactly 1 token
      buyAmount: '2000000000000000000',  // Must receive at least 2 tokens
      // ... other parameters
    }
    ```

    **Use case:** "I want to sell 1 WETH and receive at least 3000 USDC"
  </Tab>

  <Tab title="BUY Limit Orders">
    Buy orders guarantee you pay **at most** the specified `sellAmount` for your `buyAmount`:

    ```typescript theme={null}
    const limitOrderParameters: LimitTradeParameters = {
      kind: OrderKind.BUY,
      sellAmount: '3000000000', // Pay at most 3000 USDC
      buyAmount: '1000000000000000000', // To receive exactly 1 WETH
      // ... other parameters
    }
    ```

    **Use case:** "I want to buy 1 WETH and pay at most 3000 USDC"
  </Tab>
</Tabs>

## Partially Fillable Orders

By default, limit orders are "fill-or-kill" (must be completely filled). Enable partial fills to allow incremental execution:

```typescript theme={null}
const limitOrderParameters: LimitTradeParameters = {
  kind: OrderKind.SELL,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  sellAmount: '10000000000000000000', // 10 tokens
  buyAmount: '20000000000000000000', // 20 tokens
  partiallyFillable: true, // Allow partial fills
}

const { orderId } = await sdk.postLimitOrder(limitOrderParameters)
```

<Warning>
  Partially fillable orders may be executed in multiple transactions over time. Monitor the order status to track fills.
</Warning>

## When Will My Order Fill?

Limit orders fill when the market price reaches your specified rate or better. Unlike swap orders that execute immediately, limit orders may take hours, days, or never fill depending on market conditions.

Here is what happens after you submit:

1. **Your order enters the order book.** CoW Protocol solvers continuously scan the book for profitable orders to execute.
2. **Solvers evaluate your order each batch.** If your limit price is at or better than the current market price, solvers will include it in the next settlement.
3. **If your price is far from market**, the order sits in the book waiting for the market to move to your price.
4. **When conditions are met**, a solver executes your order on-chain. You may even receive surplus (a better price than you specified).

<Note>
  Use `sdk.getQuote()` to check the current market price before setting your limit. This helps you understand how far your limit is from the market and set realistic expectations for fill time.
</Note>

## Monitoring Your Order

After creating a limit order, you will want to track its status.

### Check Order Status

```typescript theme={null}
const order = await sdk.getOrder({ orderUid: orderId })

console.log('Status:', order.status)
// Possible values: open, fulfilled, cancelled, expired, presignaturePending
```

### Track Partial Fill Progress

For partially fillable orders, inspect how much has been executed so far:

```typescript theme={null}
const order = await sdk.getOrder({ orderUid: orderId })

console.log('Executed sell amount:', order.executedSellAmount)
console.log('Executed buy amount:', order.executedBuyAmount)
```

### Cancel an Order

If you want to cancel an open limit order:

```typescript theme={null}
await sdk.offChainCancelOrder({ orderUid: orderId })
```

For full details on querying, cancelling, and managing orders, see [Order Management](/cow-sdk/guides/order-management).

## Comparing Swap vs Limit Orders

| Feature       | Swap Orders                     | Limit Orders                 |
| ------------- | ------------------------------- | ---------------------------- |
| **Price**     | Current market price            | Your specified price         |
| **Amount**    | One amount (sell OR buy)        | Both amounts (sell AND buy)  |
| **Execution** | Immediate (if liquidity exists) | When price target is reached |
| **Slippage**  | Applies automatically           | Controlled by your price     |
| **Use Case**  | Quick trades at market price    | Price-specific trades        |

## Best Practices

1. **Set realistic prices**: Orders too far from market price may never fill
2. **Use validTo wisely**: Set appropriate expiration times for your strategy
3. **Consider partial fills**: For large orders, partial fills can improve execution
4. **Monitor order status**: Check if your order has been filled or partially filled
5. **Handle slippage**: Limit orders typically use 0 slippage since price is explicit

## Troubleshooting

| Problem                                        | Likely Cause                                                    | Fix                                                                        |
| ---------------------------------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `InsufficientAllowance` error                  | Sell token not approved to Vault Relayer                        | Call `sdk.approveCowProtocol()` before placing the order                   |
| `InsufficientBalance` error                    | Wallet does not hold enough sell token                          | Verify your balance covers `sellAmount`                                    |
| Order never fills                              | Limit price is too far from the current market                  | Check current market price with `sdk.getQuote()` and adjust                |
| Order fills at a different price than expected | Solvers found a better execution route                          | This is expected — CoW Protocol gives you surplus (better than your limit) |
| `TooManyLimitOrders` error                     | Too many open limit orders                                      | Cancel old or stale orders first                                           |
| Partial fill stuck at partial                  | Remaining amount is too small for solvers to profitably execute | Cancel the order and create a new one for the remainder                    |

## Next Steps

* Learn about [Order Management](/cow-sdk/guides/order-management) to track and cancel limit orders
* See [Token Approvals](/cow-sdk/guides/token-approvals) for managing ERC-20 approvals
* Explore [Smart Contract Wallets](/cow-sdk/guides/smart-contract-wallets) for advanced signing
