Order Management
The SDK provides methods to retrieve order details and cancel orders both off-chain and on-chain.
Overview
After creating an order, you can:
- Retrieve order details - Get full information about an order
- Cancel off-chain - Free and fast soft cancellation
- Cancel on-chain - Gas-required hard cancellation
All order management methods require an order UID (unique identifier) returned when creating an order.
Retrieving Order Details
Use getOrder to fetch complete information about an order:
Method Signature
getOrder(params: {
orderUid: string
chainId?: SupportedChainId
}): Promise<EnrichedOrder>
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, SupportedChainId } from '@cowprotocol/sdk-trading'
import { ViemAdapter } from '@cowprotocol/sdk-viem-adapter'
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)
console.log('Creation time:', new Date(order.creationDate))
console.log('Expiration:', new Date(order.validTo * 1000))
Order Status Values
The status field can be one of:
open - Order is active and waiting to be filled
fulfilled - Order has been completely filled
cancelled - Order has been cancelled
expired - Order has passed its expiration time
presignaturePending - Order is waiting for pre-signature (smart contract wallets)
EnrichedOrder Properties
interface EnrichedOrder {
uid: string
status: OrderStatus
owner: string
creationDate: string
sellToken: string
sellAmount: string
sellAmountBeforeFee: string
buyToken: string
buyAmount: string
validTo: number
appData: string
feeAmount: string
kind: 'sell' | 'buy'
partiallyFillable: boolean
signature: string
signingScheme: SigningScheme
receiver: string
// ... and more fields
}
Tracking Order Progress
async function trackOrder(sdk: TradingSdk, orderUid: string) {
const order = await sdk.getOrder({ orderUid })
console.log(`Order ${orderUid}:`)
console.log(` Status: ${order.status}`)
console.log(` Sell Token: ${order.sellToken}`)
console.log(` Sell Amount: ${order.sellAmount}`)
console.log(` Buy Token: ${order.buyToken}`)
console.log(` Buy Amount: ${order.buyAmount}`)
// Check if order is partially filled
if (order.partiallyFillable && order.status === 'open') {
const executedAmount = BigInt(order.sellAmount) - BigInt(order.sellAmountBeforeFee)
console.log(` Executed: ${executedAmount}`)
}
// Check time until expiration
const now = Math.floor(Date.now() / 1000)
const timeLeft = order.validTo - now
if (timeLeft > 0) {
console.log(` Time remaining: ${timeLeft} seconds`)
} else {
console.log(` Order expired`)
}
return order
}
Off-Chain Order Cancellation
Off-chain cancellation is the recommended way to cancel orders. It’s free, fast, and doesn’t require gas.
Method Signature
offChainCancelOrder(params: {
orderUid: string
chainId?: SupportedChainId
signer?: SignerLike
}): Promise<boolean>
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, SupportedChainId } from '@cowprotocol/sdk-trading'
const sdk = new TradingSdk({
chainId: SupportedChainId.MAINNET,
appCode: 'YOUR_APP_CODE',
}, {}, adapter)
const orderUid = '0xd64389693b6cf89ad6c140a113b10df08073e5ef3063d05a02f3f42e1a42f0ad...'
try {
const success = await sdk.offChainCancelOrder({ orderUid })
if (success) {
console.log('Order cancelled successfully (off-chain)')
}
} catch (error) {
console.error('Failed to cancel order:', error)
}
How It Works
Sign cancellation message
The SDK creates and signs a cancellation message using EIP-712
Send to order book
The signed cancellation is sent to the CoW Protocol order book API
Order removed
The order book marks the order as cancelled and stops including it in solutions
Soft cancel: Off-chain cancellation is a “soft” cancel. While the order book will stop trying to fill the order, the order signature remains valid on-chain. For complete security, use on-chain cancellation.
When to Use Off-Chain Cancellation
- ✅ Regular orders that you want to cancel quickly
- ✅ When you need to update order parameters (cancel and recreate)
- ✅ When minimizing costs is important
- ❌ Not suitable if you need absolute guarantee the order won’t be filled
On-Chain Order Cancellation
On-chain cancellation provides a hard guarantee that the order cannot be filled. It requires gas but is the most secure method.
Method Signature
onChainCancelOrder(params: {
orderUid: string
chainId?: SupportedChainId
signer?: SignerLike
}): Promise<string>
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, SupportedChainId } from '@cowprotocol/sdk-trading'
const sdk = new TradingSdk({
chainId: SupportedChainId.MAINNET,
appCode: 'YOUR_APP_CODE',
}, {}, adapter)
const orderUid = '0xd64389693b6cf89ad6c140a113b10df08073e5ef3063d05a02f3f42e1a42f0ad...'
try {
const txHash = await sdk.onChainCancelOrder({ orderUid })
console.log('Cancellation transaction:', txHash)
// Wait for transaction confirmation
await publicClient.waitForTransactionReceipt({ hash: txHash })
console.log('Order cancelled on-chain')
} catch (error) {
console.error('Failed to cancel order on-chain:', error)
}
How It Works
The SDK automatically detects the order type and uses the appropriate contract:
- Regular orders: Calls
invalidateOrder() on the Settlement contract
- ETH-Flow orders: Calls
invalidateOrder() on the EthFlow contract
Gas Costs
On-chain cancellation costs gas:
- Regular orders: ~45,000-60,000 gas
- ETH-Flow orders: ~50,000-70,000 gas
At 50 gwei gas price and $2000 ETH:
- Regular: ~4.50−6.00
- ETH-Flow: ~5.00−7.00
When to Use On-Chain Cancellation
- ✅ When you need absolute certainty the order won’t execute
- ✅ For high-value orders where security is paramount
- ✅ When you suspect your off-chain cancellation might not be respected
- ✅ For orders that others might try to fill maliciously
- ❌ Not cost-effective for small orders
Comparing Cancellation Methods
Advantages:
- Free (no gas cost)
- Instant
- Simple to use
- Recommended for most cases
Disadvantages:
- “Soft” cancel only
- Requires order book cooperation
- Signature remains valid on-chain
Best for:
- Regular order cancellations
- Cost-sensitive applications
- Quick order updates
Advantages:
- “Hard” cancel with on-chain guarantee
- Cannot be bypassed
- Most secure method
- Works without order book
Disadvantages:
- Requires gas payment
- Slower (must wait for tx confirmation)
- More complex
Best for:
- High-value orders
- Security-critical situations
- When off-chain cancel fails
Complete Example: Order Lifecycle
Here’s a complete example showing order creation, tracking, and cancellation:
import {
TradingSdk,
SupportedChainId,
OrderKind,
TradeParameters
} from '@cowprotocol/sdk-trading'
import { parseUnits } from 'viem'
import { ViemAdapter } from '@cowprotocol/sdk-viem-adapter'
const sdk = new TradingSdk({
chainId: SupportedChainId.MAINNET,
appCode: 'YOUR_APP_CODE',
}, {}, adapter)
// Step 1: Create an order
const parameters: TradeParameters = {
kind: OrderKind.SELL,
sellToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
sellTokenDecimals: 6,
buyToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
buyTokenDecimals: 18,
amount: parseUnits('1000', 6).toString(), // 1000 USDC
validFor: 3600, // 1 hour
}
const { orderId } = await sdk.postSwapOrder(parameters)
console.log('Order created:', orderId)
// Step 2: Monitor the order
const checkOrder = async () => {
const order = await sdk.getOrder({ orderUid: orderId })
console.log('Order status:', order.status)
return order
}
// Check order status every 30 seconds
const intervalId = setInterval(async () => {
const order = await checkOrder()
if (order.status === 'fulfilled') {
console.log('Order filled!')
clearInterval(intervalId)
} else if (order.status === 'expired') {
console.log('Order expired')
clearInterval(intervalId)
}
}, 30000)
// Step 3: Cancel the order if needed
const cancelOrder = async () => {
try {
// Try off-chain cancellation first (free)
console.log('Attempting off-chain cancellation...')
const success = await sdk.offChainCancelOrder({ orderUid: orderId })
if (success) {
console.log('Order cancelled (off-chain)')
clearInterval(intervalId)
}
} catch (error) {
console.error('Off-chain cancellation failed, trying on-chain...')
// Fall back to on-chain cancellation
const txHash = await sdk.onChainCancelOrder({ orderUid: orderId })
console.log('On-chain cancellation transaction:', txHash)
await publicClient.waitForTransactionReceipt({ hash: txHash })
console.log('Order cancelled (on-chain)')
clearInterval(intervalId)
}
}
// Call cancelOrder() when user clicks cancel button
Batch Order Monitoring
Monitor multiple orders efficiently:
interface OrderTracker {
orderId: string
status: string
checkCount: number
}
async function monitorOrders(
sdk: TradingSdk,
orderIds: string[]
): Promise<Map<string, OrderTracker>> {
const trackers = new Map<string, OrderTracker>()
for (const orderId of orderIds) {
trackers.set(orderId, {
orderId,
status: 'unknown',
checkCount: 0,
})
}
const updateStatuses = async () => {
for (const [orderId, tracker] of trackers) {
try {
const order = await sdk.getOrder({ orderUid: orderId })
tracker.status = order.status
tracker.checkCount++
console.log(`Order ${orderId.slice(0, 10)}... - ${order.status}`)
} catch (error) {
console.error(`Failed to get order ${orderId}:`, error)
}
}
}
// Check every minute
const intervalId = setInterval(updateStatuses, 60000)
// Initial check
await updateStatuses()
return trackers
}
// Usage
const orderIds = [
'0xabc123...',
'0xdef456...',
'0xghi789...',
]
const trackers = await monitorOrders(sdk, orderIds)
Best Practices
- Always store order IDs: Save order UIDs for future reference
- Monitor important orders: Track order status for large trades
- Try off-chain first: Start with off-chain cancellation to save gas
- Handle errors gracefully: Orders might already be filled when you try to cancel
- Set reasonable expiration: Don’t set validFor too long if you might want to cancel
- Check status before operations: Verify order state before cancelling
- Use appropriate cancellation: Choose based on order value and security needs
Common Issues and Solutions
Order Not Found
Problem: getOrder throws “Order not found” error.
Solution:
- Verify the order UID is correct
- Ensure the order has been created (wait a few seconds after posting)
- Check you’re using the correct chain ID
Cancellation Fails
Problem: Off-chain cancellation returns false or throws error.
Solution:
- Check if the order is already filled or expired
- Verify you’re using the same signer that created the order
- Try on-chain cancellation as a fallback
Order Still Executes After Cancellation
Problem: Order filled despite cancellation.
Solution:
- This can happen with off-chain cancellation if there’s a race condition
- Use on-chain cancellation for critical orders
- Always wait for confirmation before assuming cancellation succeeded
Next Steps