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