Skip to main content

Programmatic Orders

The CoW Protocol Composable SDK enables sophisticated trading strategies through conditional orders that execute automatically when specified conditions are met. This allows you to build advanced trading logic without constant monitoring.

Installation

npm install @cowprotocol/sdk-composable

Core Components

ConditionalOrderFactory

Registry-based factory for creating different types of conditional orders:
import { ConditionalOrderFactory } from '@cowprotocol/sdk-composable'

const factory = new ConditionalOrderFactory(registry, adapter)
const conditionalOrder = factory.fromParams(orderParams)

Multiplexer

Manages batches of conditional orders using merkle trees:
import { Multiplexer } from '@cowprotocol/sdk-composable'

const multiplexer = new Multiplexer(chainId, orders, root, location)
const proofs = multiplexer.dumpProofsAndParams()

ConditionalOrder

Base class for implementing custom conditional order types:
import { ConditionalOrder } from '@cowprotocol/sdk-composable'

class CustomOrder extends ConditionalOrder<DataType, StaticType> {
  // Implement custom conditional logic
}

Basic Usage

Standalone Setup

import {
  ConditionalOrderFactory,
  Multiplexer,
  ConditionalOrder,
  ProofLocation
} from '@cowprotocol/sdk-composable'
import { EthersV6Adapter } from '@cowprotocol/sdk-ethers-v6-adapter'
import { JsonRpcProvider, Wallet } from 'ethers'

// Configure the adapter
const provider = new JsonRpcProvider('YOUR_RPC_URL')
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider)
const adapter = new EthersV6Adapter({ provider, signer: wallet })

// Create a conditional order factory
const registry = {
  twap: TWAPOrderFactory,
  dca: DCAOrderFactory,
  // ... other order types
}

const factory = new ConditionalOrderFactory(registry, adapter)

// Create conditional orders
const twapOrder = factory.fromParams({
  handler: TWAP_HANDLER_ADDRESS,
  salt: '0x...',
  staticInput: encodedTWAPData,
})

// Create multiplexer for batch management
const orders = {
  order1: twapOrder,
  // ... more orders
}

const multiplexer = new Multiplexer(
  SupportedChainId.MAINNET,
  orders,
  merkleRoot,
  ProofLocation.PRIVATE
)

// Generate proofs for off-chain storage
const proofs = multiplexer.dumpProofsAndParams()

With CoW SDK

import {
  CowSdk,
  ConditionalOrderFactory,
  Multiplexer,
  ProofLocation
} from '@cowprotocol/cow-sdk'
import { EthersV6Adapter } from '@cowprotocol/sdk-ethers-v6-adapter'
import { JsonRpcProvider, Wallet } from 'ethers'

// Configure the adapter
const provider = new JsonRpcProvider('YOUR_RPC_URL')
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider)
const adapter = new EthersV6Adapter({ provider, signer: wallet })

// Initialize the unified SDK
const sdk = new CowSdk({
  chainId: SupportedChainId.MAINNET,
  adapter,
  composableOptions: {
    registry: orderTypeRegistry,
    orders: initialOrders,
    root: merkleRoot,
    location: ProofLocation.PRIVATE,
  },
})

// Access composable functionality
const factory = sdk.composable.factory
const multiplexer = sdk.composable.multiplexer

// Create conditional orders
const conditionalOrder = factory.fromParams(orderParams)

Order Types

Stop-Loss Orders

Automatically sell when price drops below a threshold:
const stopLossOrder = new StopLossOrder({
  handler: STOP_LOSS_HANDLER,
  sellToken: '0x...', // ETH
  buyToken: '0x...', // USDC
  sellAmount: '1000000000000000000', // 1 ETH
  strikePrice: '2000000000', // Trigger at $2000
})

Limit Orders

Execute trades at specific price points:
const limitOrder = new LimitOrder({
  handler: LIMIT_ORDER_HANDLER,
  sellToken: '0x...', // USDC
  buyToken: '0x...', // ETH
  sellAmount: '2000000000', // $2000 USDC
  buyAmount: '1000000000000000000', // 1 ETH minimum
  validTo: Math.floor(Date.now() / 1000) + 3600, // Valid for 1 hour
})

DCA (Dollar Cost Averaging)

Regularly buy or sell assets at predetermined intervals:
const dcaOrder = new DCAOrder({
  handler: DCA_HANDLER,
  sellToken: '0x...', // USDC
  buyToken: '0x...', // ETH
  sellAmount: '100000000', // $100 USDC
  timeInterval: 86400, // Daily
  numOfParts: 30, // For 30 days
})
See the TWAP Orders page for detailed information about Time-Weighted Average Price orders.

Merkle Tree Management

Conditional orders are stored in merkle trees for efficient on-chain verification:
// Create multiplexer with multiple orders
const multiplexer = new Multiplexer(
  SupportedChainId.MAINNET,
  conditionalOrders,
  undefined, // Will generate merkle root
  ProofLocation.PRIVATE,
)

// Get merkle root for on-chain storage
const root = multiplexer.getOrGenerateTree().root

// Generate proofs for specific orders
const proofs = multiplexer.dumpProofsAndParams((order) => {
  return order.isActive // Only include active orders
})

Order Validation

Validate conditional orders before execution:
// Check if conditional order is valid
const validationResult = await conditionalOrder.isValid({
  owner: userAddress,
  ctx: contextData,
})

if (validationResult.isValid) {
  // Order can be executed
  const tradeableOrder = await conditionalOrder.poll({
    owner: userAddress,
    proof: merkleProof,
    provider: provider,
  })
}

Context Dependencies

Orders can depend on external data sources:
// Orders that depend on external data
const conditionalOrder = new PriceBasedOrder({
  handler: PRICE_HANDLER,
  // ... order parameters
})

// Get context dependency (e.g., price oracle)
const contextDependency = conditionalOrder.getContextDependency()

// Poll with off-chain input
const [orderData, signature] = await ConditionalOrder.poll(
  owner,
  proofWithParams,
  chainId,
  provider,
  async (owner, params) => {
    // Fetch off-chain data (prices, etc.)
    return await fetchOffChainInput(params)
  },
)

Order Registry Management

Register custom order types:
// Register custom order types
const registry = {
  'custom-twap': CustomTWAPOrder,
  'limit-order': LimitOrder,
  'bracket-order': BracketOrder,
}

const factory = new ConditionalOrderFactory(registry, adapter)

// Register new order type dynamically
Multiplexer.registerOrderType('new-order-type', NewOrderClass)

Smart Contract Integration

ComposableCoW Contract

// Set merkle root on ComposableCoW contract
const composableCowContract = adapter.getContract(
  COMPOSABLE_COW_CONTRACT_ADDRESS[chainId],
  ComposableCowABI
)

// Set root with context
await composableCowContract.setRootWithContext(
  root,
  contextFactory,
  contextData
)

Proof Generation and Storage

// Generate proofs for watchtowers/indexers
const proofsData = multiplexer.dumpProofs((order) => {
  // Filter criteria for proof inclusion
  return order.status === 'active'
})

// Store proofs off-chain (IPFS, etc.)
await uploadProofs(proofsData)

// Verify proofs on-chain when executing
const isValidProof = multiplexer.getOrGenerateTree().verify(proof, leafData)

Complete Example

Here’s a complete example setting up a stop-loss order:
import {
  ConditionalOrderFactory,
  Multiplexer,
  ProofLocation,
  SupportedChainId
} from '@cowprotocol/sdk-composable'
import { EthersV6Adapter } from '@cowprotocol/sdk-ethers-v6-adapter'

// 1. Initialize adapter and factory
const adapter = new EthersV6Adapter({ provider, signer: wallet })
const factory = new ConditionalOrderFactory(registry, adapter)

// 2. Create stop-loss order
const stopLoss = new StopLossOrder({
  sellToken: WETH_ADDRESS,
  buyToken: USDC_ADDRESS,
  sellAmount: parseEther('10'),
  strikePrice: '2000000000', // $2000
})

// 3. Create multiplexer
const multiplexer = new Multiplexer(SupportedChainId.MAINNET)
multiplexer.addOrder('stop-loss-1', stopLoss)

// 4. Set root on ComposableCoW
const root = multiplexer.getOrGenerateTree().root
await composableCowContract.setRoot(root)

// 5. Generate proofs for watchtower
const proofs = multiplexer.dumpProofsAndParams()
await storeProofsOffChain(proofs)

console.log('Stop-loss order created and activated')

Best Practices

Always validate orders before submission

Use the isValid() method to catch configuration errors early:
const validation = await order.isValid({ owner, ctx })
if (!validation.isValid) {
  throw new Error(`Invalid order: ${validation.reason}`)
}

Store proofs off-chain

Generate and store merkle proofs off-chain to enable watchtowers to execute your orders:
const proofs = multiplexer.dumpProofsAndParams()
await uploadToIPFS(proofs)

Use appropriate context factories

Set context factories for orders that need on-chain data:
const order = new TWAPOrder({
  // ... parameters
})
// TWAP automatically uses CurrentBlockTimestampFactory when needed

Next Steps

  • TWAP Orders: Learn about Time-Weighted Average Price orders
  • Hooks: Execute custom logic with pre and post hooks
Last modified on March 4, 2026