Programmatic Orders
The CoW Protocol Composable SDK enables sophisticated trading strategies through programmatic orders that execute automatically when specified conditions are met. The ComposableCoW contract implements these orders, allowing 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 programmatic orders:
import { ConditionalOrderFactory } from '@cowprotocol/sdk-composable'
const factory = new ConditionalOrderFactory(registry, adapter)
const conditionalOrder = factory.fromParams(orderParams)
Multiplexer
Manages batches of programmatic 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 programmatic 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 programmatic order factory
const registry = {
twap: TWAPOrderFactory,
dca: DCAOrderFactory,
// ... other order types
}
const factory = new ConditionalOrderFactory(registry, adapter)
// Create programmatic 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 programmatic 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)
DCA strategies are implemented using TWAP orders. A TWAP order splits a total amount into equal parts executed at regular intervals — which is exactly what DCA does.
For example, to DCA 3,000USDCintoETHover30days(100/day):
import { Twap, SupportedChainId } from '@cowprotocol/cow-sdk'
const dcaOrder = new Twap(SupportedChainId.MAINNET, {
sellToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
buyToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
sellAmount: '3000000000', // Total: 3000 USDC (6 decimals)
numOfParts: 30, // 30 parts = 30 days
timeInterval: 86400, // 1 day between parts (in seconds)
span: 0, // Each part valid for full interval
})
Each part sells 100 USDC for WETH once per day. See the TWAP Orders guide for full configuration options including price protection.
Merkle Tree Management
Programmatic 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 programmatic orders before execution:
// Check if programmatic 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 12, 2026