@cowprotocol/sdk-trading

中文文档
2.8.1发布于 2026/11/04MITTypeScriptESM + CJS构建来源已验证近 30 天下载 8.3万

CowProtocol trading

原始使用文档
文档目录27 节
  1. Test coverage
  2. Basic Trading Flow
  3. Why Use This SDK?
  4. Installation
  5. TradingSdk Functions
  6. Setup
  7. Usage
  8. Options
  9. getQuote
  10. postSwapOrder
  11. postLimitOrder
  12. postSellNativeCurrencyOrder
  13. Get quote for a smart-contract wallet
  14. Create an order with smart-contract wallet
  15. Sign an order externally (signer-less flow)
  16. Optional parameters
  17. Advanced swap order creation
  18. Order Management
  19. getOrder
  20. offChainCancelOrder
  21. onChainCancelOrder
  22. Token Approval
  23. getCowProtocolAllowance
  24. approveCowProtocol
  25. Custom Contract Addresses
  26. settlementContractOverride / ethFlowContractOverride
  27. Custom Order-Book API Endpoint

Trading SDK

Test coverage

StatementsBranchesFunctionsLines
StatementsBranchesFunctionsLines

CoW Protocol is intent based, decentralized trading protocol that allows users to trade ERC-20 tokens. This SDK makes it easier to interact with CoW Protocol by handling order parameters, calculating amounts, and signing orders.

Basic Trading Flow

  1. 🔎 Get a quote (price) for a trade
  2. ✍️ Sign the order
  3. ✅ Post the order to the order-book

The CoW Protocol provides very flexible and powerful trading capabilities. However, this flexibility comes with a cost: the complexity of the protocol. This SDK serves to simplify the interaction with the CoW Protocol. It will put all necessary parameters to your order, calculates proper amounts, and signs the order.

Why Use This SDK?

  • App-data - Order metadata handling
  • Order signing - EIP-712 signature management
  • Network costs - Automatic fee and slippage calculations
  • Order parameters - Validity, partial fills, etc.
  • Quote API settings - Price quality, signing scheme, etc.
  • Order types - Market, limit, on-chain trades, etc.

See the examples for usage.

Installation

npm install @cowprotocol/sdk-trading
or
pnpm add @cowprotocol/sdk-trading
or
yarn add @cowprotocol/sdk-trading

TradingSdk Functions

Main functions:

  • postSwapOrder - Get a quote and create a swap order.
  • postLimitOrder - Create a limit order.
  • getQuote - Fetch a quote for a swap order.
  • getQuoteOnly - Fetch a quote with only an owner address, no signer needed.
  • getOrderToSubmit - Build the order to submit with an external signature.
  • postSignedOrder - Submit an order signed externally (see signer-less flow).

Order Management:

  • getOrder - Retrieve order details by UID.
  • offChainCancelOrder - Cancel an order off-chain (soft cancel, free and fast).
  • onChainCancelOrder - Cancel an order on-chain (hard cancel, requires gas).

Token Approval:

  • getCowProtocolAllowance - Check current token allowance for CoW Protocol.
  • approveCowProtocol - Approve CoW Protocol to spend tokens.

Special cases:

  • setTraderParams - In case if you work with different chains and need to switch between them in runtime.
  • postSellNativeCurrencyOrder - Sell blockchain native tokens (e.g., ETH on Ethereum).
  • getPreSignCallData - Build unsigned pre-sign calldata for an external wallet, multisig, or custody stack.
  • getPreSignTransaction - Build a pre-sign transaction with a signer-based gas estimate.

Setup

You need:

  • chainId - Supported chain ID (see list).
  • appCode - Unique app identifier for tracking orders.
  • signer - Private key, ethers signer, or Eip1193 provider (optional - will use global adapter's signer if not provided).

Usage

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'

// There are EthersV5Adapter and EthersV6Adapter as well
// @cowprotocol/sdk-ethers-v5-adapter, @cowprotocol/sdk-ethers-v6-adapter
const adapter = new ViemAdapter({
  provider: createPublicClient({
    chain: sepolia,
    transport: http('YOUR_RPC_URL')
  }),
  // You also can set `walletClient` instead of `signer` using `useWalletClient` from wagmi
  signer: privateKeyToAccount('YOUR_PRIVATE_KEY' as `0x${string}`)
})

// Initialize the SDK
const sdk = new TradingSdk(
  {
    appCode: 'YOUR_APP_CODE',
  },
  {
    chainId: SupportedChainId.SEPOLIA,
  },
  adapter, // Pass the adapter
)

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

// Post the order
const orderId = await sdk.postSwapOrder(parameters)
console.log('Order created, id: ', orderId)

Options

For detailed information about trading steps you can enable the SDK logging:

import { SupportedChainId, TradingSdk, TradingSdkOptions } from '@cowprotocol/cow-sdk'
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')
  }),
  // You also can set `walletClient` instead of `signer` using `useWalletClient` from wagmi
  signer: privateKeyToAccount('YOUR_PRIVATE_KEY' as `0x${string}`)
})

const traderParams = {
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
  signer: '<privateKeyOrEthersSigner>', // signer is optional - will use global adapter's signer if not provided
}

const sdkOptions: TradingSdkOptions = {
  enableLogging: true, // enables detailed logging of trading steps
  disableUtm: false, // set to true to disable UTM tracking completely
}

const sdk = new TradingSdk(traderParams, sdkOptions, adapter)

getQuote

In case if you want to get a quote and only then create an order, you can use the getQuote function.

The parameters required are the same as for the postSwapOrder function.

The function returns quoteResults object with the following properties:

  • tradeParameters - trade type, assets, amounts and other optional parameters
  • amountsAndCosts - the order sell/buy amounts including network costs, fees and slippage
  • orderToSign - order parameters to sign (see order signing)
  • quoteResponse - DTO from quote API
  • appDataInfo - order's metadata
  • orderTypedData - EIP-712 typed data for signing

Another parameter is returned by this function is postSwapOrderFromQuote. It can be used to create an order from the received quote.

Example

import { SupportedChainId, OrderKind, TradeParameters, TradingSdk } from '@cowprotocol/cow-sdk'
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')
  }),
  // You also can set `walletClient` instead of `signer` using `useWalletClient` from wagmi
  signer: privateKeyToAccount('YOUR_PRIVATE_KEY' as `0x${string}`)
})

// Proper adapter initialization (see setup example above)
const sdk = new TradingSdk({
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
}, {}, adapter)

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

const { quoteResults, postSwapOrderFromQuote } = await sdk.getQuote(parameters)

const buyAmount = quoteResults.amountsAndCosts.afterSlippage.buyAmount

if (confirm(`You will get at least: ${buyAmount}, ok?`)) {
  const orderId = await postSwapOrderFromQuote()

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

postSwapOrder

This function fetches a quote for a swap order and just creates the order.

The parameters required are:

  • kind - the order kind (sell/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

When sell token is a blockchain native token (ETH for Ethereum), then order will be created as an on-chain transaction. See the postSellNativeCurrencyOrder method below for more details.

Example

import { SupportedChainId, OrderKind, TradeParameters, TradingSdk } from '@cowprotocol/cow-sdk'
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')
  }),
  // You also can set `walletClient` instead of `signer` using `useWalletClient` from wagmi
  signer: privateKeyToAccount('YOUR_PRIVATE_KEY' as `0x${string}`)
})

// Proper adapter initialization (see setup example above)
const sdk = new TradingSdk({
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
}, {}, 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)

postLimitOrder

This main difference between this function and postSwapOrder is that here you need to specify both sell and buy amounts.

You need to provide the following parameters:

  • kind - the order kind (sell/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

And optional parameters:

  • quoteId - id of the quote from the quote API (see getQuote function)
  • validTo - the order expiration time in seconds
import { SupportedChainId, OrderKind, LimitTradeParameters, TradingSdk } from '@cowprotocol/cow-sdk'
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')
  }),
  // You also can set `walletClient` instead of `signer` using `useWalletClient` from wagmi
  signer: privateKeyToAccount('YOUR_PRIVATE_KEY' as `0x${string}`)
})

// Proper adapter initialization (see setup example above)
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)

postSellNativeCurrencyOrder

CoW Protocol supports on-chain trades for selling blockchain native tokens (ETH for Ethereum). In this case, the order is created as an on-chain transaction. You don't have to think about the case when you use postSwapOrder function, it will be handled automatically. But if you need more flexible way to create an order to sell native token, you can use the postSellNativeCurrencyOrder function.

We consider the order as native token selling order if the sell token has '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' address.

import { SupportedChainId, OrderKind, TradeParameters, TradingSdk } from '@cowprotocol/cow-sdk'
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}`)
})

// Proper adapter initialization (see setup example above)
const sdk = new TradingSdk({
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
}, {}, adapter)

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

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

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

Get quote for a smart-contract wallet

If you want to use a smart-contract wallet to sign the order, you should specify the signingScheme parameter in order to get more accurate quote in terms of gas efficiency. Smart-contract wallets are supported by using a different signing scheme - SigningScheme.PRESIGN.

Example

import {
  SupportedChainId,
  OrderKind,
  TradeParameters,
  SwapAdvancedSettings,
  SigningScheme,
  TradingSdk,
} from '@cowprotocol/cow-sdk'
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}`)
})

// Proper adapter initialization (see setup example above)
const sdk = new TradingSdk({
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
}, {}, adapter)

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

const advancedParameters: SwapAdvancedSettings = {
  quoteRequest: {
    // Specify the signing scheme
    signingScheme: SigningScheme.PRESIGN,
  },
}

const { quoteResults } = await sdk.getQuote(parameters)

console.log('Quote:', quoteResults)

Create an order with smart-contract wallet

If you want to create an order with a smart-contract wallet, specify the PRESIGN signing scheme when posting the order. After the order is created, use getPreSignCallData to submit the pre-sign transaction through your own wallet stack, or getPreSignTransaction when you have an SDK signer and want a gas estimate included.

Example of Swap order

import { SupportedChainId, OrderKind, TradeParameters, TradingSdk } from '@cowprotocol/cow-sdk'
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}`)
})

// Proper adapter initialization (see setup example above)
const sdk = new TradingSdk({
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
}, {}, adapter)

const smartContractWalletAddress = '0x<smartContractWalletAddress>'

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

const advancedParameters: SwapAdvancedSettings = {
  quoteRequest: {
    // Specify the signing scheme
    signingScheme: SigningScheme.PRESIGN,
  },
}

const { orderId } = await sdk.postSwapOrder(parameters, advancedParameters)
const preSignTransaction = await sdk.getPreSignTransaction({ orderUid: orderId })

console.log('Order created with "pre-sign" state, id: ', orderId)
console.log('Execute the transaction to sign the order', preSignTransaction)

Example of Limit order

import {
  SupportedChainId,
  OrderKind,
  LimitTradeParameters,
  LimitOrderAdvancedSettings,
  SigningScheme,
  TradingSdk,
} from '@cowprotocol/cow-sdk'
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}`)
})

// Proper adapter initialization (see setup example above)
const sdk = new TradingSdk({
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
}, {}, adapter)

const smartContractWalletAddress = '0x<smartContractWalletAddress>'

const limitOrderParameters: LimitTradeParameters = {
  kind: OrderKind.BUY,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  sellAmount: '120000000000000000',
  buyAmount: '66600000000000000000',
  owner: smartContractWalletAddress, // See note bellow why you need to specify the parameter
}

const advancedParameters: LimitOrderAdvancedSettings = {
  additionalParams: {
    signingScheme: SigningScheme.PRESIGN,
  },
}

const { orderId } = await sdk.postLimitOrder(limitOrderParameters, advancedParameters)
const preSignTransaction = await sdk.getPreSignTransaction({ orderUid: orderId })

console.log('Order created with "pre-sign" state, id: ', orderId)
console.log('Execute the transaction to sign the order', preSignTransaction)

Note: it's important to specify the owner parameter if you create an order with a smart-contract wallet, and it differs from the signer (for example Safe). CoW Protocol will use owner in order to check the order owner balance, allowance and other things.

Build pre-sign calldata without a signer

If the transaction will be proposed or submitted by a Safe, multisig, or custody stack, request the raw transaction data from the already configured SDK:

const preSignCallData = sdk.getPreSignCallData({ orderUid: orderId })

// Returns { to, data, value }; pass it to your own transaction stack.
await yourMultisigOrCustodyStack.submitTransaction(preSignCallData)

getPreSignCallData still requires a configured adapter because ABI encoding is adapter-specific. The adapter may be signer-less; provider-based adapters such as ViemAdapter still require a provider or RPC URL during initialization, but this helper does not access the signer, call the provider, or estimate gas. The external stack should estimate gas in its own execution context. The final transaction must be executed by the order owner encoded in the order UID—for a Safe-owned order, the Safe itself must call the settlement contract.

Sign an order externally (signer-less flow)

If the signing key can't be handed to the SDK — cold wallets (Tangem), MPC/custody services (Fireblocks), or any setup where signing happens in a separate environment — you can complete a swap with only the owner address and an externally-produced signature:

  1. getQuoteOnly({ owner, ... }) — get a quote for the owner account, no signer needed
  2. getOrderToSubmit({ quoteResults }) — build the order body, everything except the signature
  3. Sign quoteResults.orderTypedData in your own environment (eth_signTypedData_v4)
  4. postSignedOrder({ orderToSubmit, signature }) — upload the app-data and submit the order

Example

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

// The adapter carries NO signer — it is only used for hashing utilities when
// building app-data. The private key never enters the SDK.
setGlobalAdapter(new EthersV6Adapter({ provider: new JsonRpcProvider('YOUR_RPC_URL') }))

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

const quoteResults = await sdk.getQuoteOnly({
  owner: '0x<ownerAddress>', // the account that will sign the order
  kind: OrderKind.SELL,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  amount: '120000000000000000',
})

// Everything sendOrder needs, except the signature
const orderToSubmit = sdk.getOrderToSubmit({ quoteResults })

// Produce the signature in your own environment, e.g. with a raw JSON-RPC call:
//   eth_signTypedData_v4(owner, JSON.stringify(quoteResults.orderTypedData))
// or with a signing library (see the note about EIP712Domain below):
//   const { EIP712Domain: _, ...types } = quoteResults.orderTypedData.types
//   const signature = await coldWallet.signTypedData(quoteResults.orderTypedData.domain, types, quoteResults.orderTypedData.message)
const signature = await signInYourEnvironment(quoteResults.orderTypedData)

const { orderId } = await sdk.postSignedOrder({ orderToSubmit, signature })

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

Runnable versions (with a local wallet playing the cold wallet) are in examples/nodejs/ethers6/src/signerless.ts and examples/nodejs/viem/src/signerless.ts.

Note: the signature must come from the owner account — the order book recovers the signer and rejects the order if it doesn't match. owner also needs the sell-token balance and a Vault Relayer approval.

A few things specific to this flow:

  • Sign orderToSign verbatim: network costs and slippage are already folded in and feeAmount is 0, so the typed-data amounts won't match the headline quote. Nothing can be changed without re-quoting.
  • Native-token sells aren't supported here — they need an on-chain transaction (see postSellNativeCurrencyOrder).
  • orderTypedData.types includes EIP712Domain so it works as-is with raw eth_signTypedData_v4. ethers throws if it's present — drop it from types first (see the example); viem accepts either form.
  • getOrderToSubmit defaults to the EIP712 signing scheme (sign orderTypedData via eth_signTypedData_v4). To sign with eth_sign/personal_sign instead, compute the EIP-712 digest of the order and personal_sign that, then pass sdk.getOrderToSubmit({ quoteResults, signingScheme: SigningScheme.ETHSIGN }) — the scheme must match how you signed. PRESIGN (on-chain flow) isn't part of this flow, and EIP1271 (smart-account) support is planned for a later milestone.

Optional parameters

Both postSwapOrder and postLimitOrder functions have optional parameters. See TradeOptionalParameters type for more details.

ParameterTypeDefault ValueDescription
envEnvprodThe environment to use (prod or staging).
partiallyFillablebooleanfalseIndicates whether the order is fill-or-kill or partially fillable.
slippageBpsnumber50Slippage tolerance applied to the order to get the limit price. Expressed in Basis Points (BPS). One basis point is equivalent to 0.01% (1/100th of a percent).
receiverstringorder creatorThe address that will receive the order's tokens.
validFornumber30 minsThe order expiration time in seconds.
partnerFeePartnerFee-Partners of the protocol can specify their fee for the order, including the fee in basis points (BPS) and the fee recipient address. Read more
Example
import { SupportedChainId, OrderKind, TradeParameters, TradingSdk } from '@cowprotocol/cow-sdk'
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}`)
})

// Proper adapter initialization (see setup example above)
const sdk = new TradingSdk({
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
}, {}, adapter)

const parameters: TradeParameters = {
  kind: OrderKind.BUY,
  sellToken: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14',
  sellTokenDecimals: 18,
  buyToken: '0x0625afb445c3b6b7b929342a04a22599fd5dbb59',
  buyTokenDecimals: 18,
  amount: '120000000000000000',
  // Optional parameters
  slippageBps: 200, // 2%
  validFor: 1200, // 20 mins
  receiver: '0xdef1ca1fb7f1232777520aa7f396b4e015f497ab', // Just a random address, don't use it!
}

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

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

Advanced swap order creation

By default, the SDK requires only the basic parameters to create an order. However, you can provide additional parameters to customize the order creation.

Swap

  1. quoteRequest - the quote request object. It is used to get a quote from the quote API (read more)

    priceQuality defaults to verified: the backend simulates quotes and prefers verified ones over higher unverified ones. Pass optimal to get the highest quote without simulation (faster, but a higher risk the order turns out unfillable).

  2. appData - the order's metadata (read more)

Example
import {
  SupportedChainId,
  OrderKind,
  TradeParameters,
  TradingSdk,
  SwapAdvancedSettings,
  PriceQuality,
} from '@cowprotocol/cow-sdk'
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}`)
})

// Proper adapter initialization (see setup example above)
const sdk = new TradingSdk({
  chainId: SupportedChainId.SEPOLIA,
  appCode: '<YOUR_APP_CODE>',
}, {}, adapter)

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

const advancedSettings: SwapAdvancedSettings = {
  quoteRequest: {
    priceQuality: PriceQuality.FAST,
    validFor: 120,
  },
  appData: {
    hooks: {
      version: 1,
      pre: [
        {
          target: '0xdef1ca1fb7fbcdc777520aa7f396b4e015f497ab',
          callData: '0x70a08231000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045',
          gasLimit: 21000,
        },
      ],
    },
  },
}
const { orderId } = await sdk.postSwapOrder(parameters, advancedSettings)

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

Limit order

Same as for the swap order but without the quoteRequest parameter.

Order Management

The SDK provides methods to manage existing orders, including retrieving order details and canceling orders.

getOrder

Fetches details about an existing order by its UID.

Parameters:

  • orderUid - The unique identifier of the order
  • chainId - (Optional) Chain ID, uses trader params if not provided

Returns: Promise<EnrichedOrder> - Full order details including status, amounts, and metadata

Example

import { TradingSdk } from '@cowprotocol/sdk-trading'

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

const orderUid = '0xd64389693b6cf89ad6c140a113b10df08073e5ef3063d05a02f3f42e1a42f0ad...'

const order = await sdk.getOrder({ orderUid })

console.log('Order status:', order.status)
console.log('Sell amount:', order.sellAmount)
console.log('Buy amount:', order.buyAmount)

offChainCancelOrder

Cancels an order off-chain by sending a signed cancellation request to the order book API. This is a "soft cancel" that is faster and doesn't require gas, but requires order book support.

You always can cancel orders using CoW Swap, see the tutorial for more details.

Parameters:

  • orderUid - The unique identifier of the order to cancel
  • chainId - (Optional) Chain ID, uses trader params if not provided
  • signer - (Optional) Custom signer, uses trader params signer if not provided

Returns: Promise<boolean> - True if cancellation was successful

Example

import { TradingSdk } from '@cowprotocol/sdk-trading'

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

const orderUid = '0xd64389693b6cf89ad6c140a113b10df08073e5ef3063d05a02f3f42e1a42f0ad...'

const success = await sdk.offChainCancelOrder({ orderUid })

if (success) {
  console.log('Order cancelled successfully (off-chain)')
}

onChainCancelOrder

Cancels an order on-chain by sending a transaction to invalidate it. This is a "hard cancel" that requires gas but guarantees cancellation. Automatically detects whether to use the Settlement contract or EthFlow contract based on order type.

Parameters:

  • orderUid - The unique identifier of the order to cancel
  • chainId - (Optional) Chain ID, uses trader params if not provided
  • signer - (Optional) Custom signer, uses trader params signer if not provided

Returns: Promise<string> - Transaction hash of the cancellation

Example

import { TradingSdk } from '@cowprotocol/sdk-trading'

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

const orderUid = '0xd64389693b6cf89ad6c140a113b10df08073e5ef3063d05a02f3f42e1a42f0ad...'

const txHash = await sdk.onChainCancelOrder({ orderUid })

console.log('Cancellation transaction:', txHash)

Token Approval

Before trading ERC-20 tokens, you need to approve the CoW Protocol to spend them. The SDK provides methods to check and manage token approvals.

getCowProtocolAllowance

Checks the current allowance for the CoW Protocol Vault Relayer to spend an ERC-20 token.

Parameters:

  • tokenAddress - The ERC-20 token contract address
  • owner - The address of the token owner
  • chainId - (Optional) Chain ID, uses trader params if not provided

Returns: Promise<bigint> - Current allowance amount

Example

import { TradingSdk } from '@cowprotocol/sdk-trading'

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

const tokenAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC
const owner = '0x...' // Your wallet address

const allowance = await sdk.getCowProtocolAllowance({
  tokenAddress,
  owner,
})

console.log('Current allowance:', allowance.toString())

approveCowProtocol

Approves the CoW Protocol Vault Relayer to spend a specified amount of an ERC-20 token. This creates an on-chain approval transaction.

Parameters:

  • tokenAddress - The ERC-20 token contract address
  • amount - The amount to approve (as bigint)
  • chainId - (Optional) Chain ID, uses trader params if not provided
  • signer - (Optional) Custom signer, uses trader params signer if not provided

Returns: Promise<string> - Transaction hash of the approval

Example

import { TradingSdk } from '@cowprotocol/sdk-trading'
import { parseUnits } from 'viem' // or ethers

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

const tokenAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC
const amount = parseUnits('1000', 6) // 1000 USDC (6 decimals)

const txHash = await sdk.approveCowProtocol({
  tokenAddress,
  amount,
})

console.log('Approval transaction:', txHash)

Smart Approval Flow

It's recommended to check the current allowance before approving to avoid unnecessary transactions:

import { TradingSdk } from '@cowprotocol/sdk-trading'
import { parseUnits } from 'viem'

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

const tokenAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC
const owner = '0x...' // Your wallet address
const requiredAmount = parseUnits('1000', 6) // 1000 USDC

// Check current allowance
const currentAllowance = await sdk.getCowProtocolAllowance({
  tokenAddress,
  owner,
})

// Only approve if needed
if (currentAllowance < requiredAmount) {
  const txHash = await sdk.approveCowProtocol({
    tokenAddress,
    amount: requiredAmount,
  })
  console.log('Approval transaction:', txHash)
} else {
  console.log('Sufficient allowance already exists')
}

Custom Contract Addresses

For advanced use cases such as testing, custom deployments, or chains where CoW Protocol contracts are deployed at non-standard addresses, you can override the contract addresses used by the SDK.

Both parameters accept an AddressPerChain object (Record<SupportedChainId, Address>), so they apply per-chain and persist across all operations when set in traderParams.

settlementContractOverride / ethFlowContractOverride

Overrides the address of the CoW Protocol Settlement contract. This affects:

  • Order domain signing (EIP-712 verifyingContract)
  • On-chain order cancellation via onChainCancelOrder
  • Pre-sign transactions via getPreSignTransaction
import { SupportedChainId, OrderKind, TradeParameters, TradingSdk, COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS, ETH_FLOW_ADDRESSES } from '@cowprotocol/cow-sdk'
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>',
  // Override the settlement contract address for MAINNET
  settlementContractOverride: {
    ...COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS,
    [SupportedChainId.MAINNET]: '0x<custom_settlement_contract>',
  } as AddressPerChain,
  // Override the eth-flow contract address for GNOSIS_CHAIN
  ethFlowContractOverride: {
    ...ETH_FLOW_ADDRESSES,
    [SupportedChainId.GNOSIS_CHAIN]: '0x<custom_eth_flow_contract>',
  } as AddressPerChain,
}, {}, adapter)

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

const { quoteResults, postSwapOrderFromQuote } = await sdk.getQuote(parameters)
const orderId = await postSwapOrderFromQuote()

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

You can also pass settlementContractOverride / ethFlowContractOverride per-call to override only for that operation:

const { quoteResults, postSwapOrderFromQuote } = await sdk.getQuote({
  ...parameters,
  settlementContractOverride: {
    [SupportedChainId.MAINNET]: '0x<custom_settlement_contract>',
  } as AddressPerChain,
})

// or

const { orderId } = await sdk.postSwapOrder({
  ...parameters,
  settlementContractOverride: {
    [SupportedChainId.MAINNET]: '0x<custom_settlement_contract>',
  } as AddressPerChain,
})

Custom Order-Book API Endpoint

By default the SDK uses the public CoW Protocol API endpoints. You can point the SDK at a custom or self-hosted order-book by creating an OrderBookApi instance with custom baseUrls and passing it as the orderBookApi option.

This is useful for:

  • Running a local order-book node during development
  • Using a private/dedicated API deployment
  • Connecting to a forked or testnet environment with a custom backend
import { SupportedChainId, TradingSdk, OrderKind, TradeParameters } from '@cowprotocol/sdk-trading'
import { OrderBookApi } from '@cowprotocol/sdk-order-book'
import { AddressPerChain } from '@cowprotocol/sdk-config'
import { ViemAdapter } from '@cowprotocol/sdk-viem-adapter'
import { createPublicClient, http, privateKeyToAccount } from 'viem'
import { mainnet } from 'viem/chains'

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

// 1. Create an OrderBookApi instance with custom base URLs
const orderBookApi = new OrderBookApi({
  chainId: SupportedChainId.MAINNET,
  // Provide a base URL for each chain you intend to use
  baseUrls: {
    // ...
    [SupportedChainId.MAINNET]: 'https://your-custom-orderbook.example.com/mainnet',
  },
})

// 2. Pass it to TradingSdk via the options object
const sdk = new TradingSdk(
  {
    chainId: SupportedChainId.MAINNET,
    appCode: '<YOUR_APP_CODE>',
  },
  {
    orderBookApi, // All order-book requests will go to your custom endpoint
  },
  adapter,
)

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

const { orderId } = await sdk.postSwapOrder(parameters)
console.log('Order created via custom endpoint, id:', orderId)

版本与发布记录

@cowprotocol/sdk-trading 共发布 101 个版本,首次发布于 2025/08/02;过去 12 个月发布了 72 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.8.1latest2026/11/046 天前
2.8.02026/11/046 天前
2.7.112026/11/037 天前
2.7.102026/10/2615 天前
2.7.92026/10/2318 天前
2.7.82026/10/1328 天前

其他发布通道:next → 0.2.1-beta.0。

关于 @cowprotocol/sdk-trading 的常见问题

@cowprotocol/sdk-trading 是什么?

CowProtocol trading

如何安装 @cowprotocol/sdk-trading?

在项目目录运行 npm install @cowprotocol/sdk-trading,或使用 pnpm add / yarn add / bun add。

@cowprotocol/sdk-trading 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cowprotocol/sdk-trading 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@cowprotocol/sdk-trading 可以商用吗?

@cowprotocol/sdk-trading 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cowprotocol/sdk-trading 的下载量有多少?

根据 npm 官方下载统计,@cowprotocol/sdk-trading 在 2026/10/11 – 2026/11/09 这 30 天内被下载 82,885 次,日均约 2,763 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cowprotocol/sdk-trading 还在维护吗?

最新版本 2.8.1 发布于 2026/11/04(6 天前);至今共发布 101 个版本,其中过去 12 个月发布了 72 个;首次发布于 2025/08/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。