Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cowprotocol/services/llms.txt

Use this file to discover all available pages before exploring further.

The Driver service is the execution layer between solver engines and the blockchain. It handles everything except the core route-finding logic: fetching liquidity, encoding solutions to calldata, simulating settlements, and submitting transactions on-chain.

Purpose and Responsibilities

The Driver provides a standardized interface for solver engines:
  • Liquidity Fetching: Collects on-chain liquidity from DEXes (Uniswap, Balancer, etc.)
  • Solution Encoding: Converts high-level solutions into settlement contract calldata
  • Simulation: Validates solutions before submission using Tenderly, Enso, or node simulation
  • Transaction Submission: Manages gas pricing, nonce handling, and tx broadcast
  • Mempool Integration: Monitors transaction status and handles replacements
  • Quote Generation: Provides price quotes based on solver solutions
The Driver-Solver architecture separates concerns: Solvers focus on route-finding algorithms, while Drivers handle all blockchain interactions.

Solution Execution Flow

From crates/driver/README.md, the interaction follows this sequence:

Request Flow

1

Receive Auction

Driver receives auction from Autopilot via POST /solve
2

Fetch Liquidity

Driver gathers current on-chain liquidity for relevant tokens
3

Forward to Solver

Auction + liquidity sent to configured solver engine(s)
4

Collect Solutions

Solver engines return proposed solutions
5

Encode & Score

Driver encodes solutions to calldata and calculates objective values
6

Simulate Best

Top solution(s) simulated to verify execution
7

Return to Autopilot

Best solution returned with score
8

Execute Winner

If solution wins, driver receives POST /settle and submits transaction

Liquidity Fetching

The Driver collects on-chain liquidity from multiple DEX protocols:

Supported Liquidity Sources

From crates/driver/example.toml:
[[liquidity.uniswap-v2]]
preset = "uniswap-v2"  # or "sushi-swap", "honeyswap", etc.

[[liquidity.uniswap-v2]]  # Custom configuration
router = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
pool-code = "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"

Base Tokens

Define tokens that can appear as intermediate hops:
[liquidity]
base-tokens = [
  "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB",  # COW
  "0x6B175474E89094C44Da98b954EedeAC495271d0F",  # DAI
]

CoW AMMs

Include CoW Protocol AMM pools:
[[contracts.cow-amms]]
factory = "0x86f3df416979136cb4fdea2c0886301b911c163b"
helper = "0x86f3df416979136cb4fdea2c0886301b911c163b"

Simulation and Settlement

Simulation Options

The Driver supports multiple simulation backends:

1. Ethereum Node (Default)

Simulates using the configured Ethereum RPC:
Simulator::ethereum(eth.to_owned())
  • ✅ No additional configuration
  • ✅ Accurate gas estimation
  • ⚠️ Slower than specialized simulators

2. Tenderly

High-performance simulation with debugging features:
[tenderly]
url = "https://api.tenderly.co/api/v1"
api-key = "YOUR_API_KEY"
user = "your-username"
project = "your-project"
save = false
save-if-fails = true
  • ✅ Fast simulation
  • ✅ Detailed execution traces
  • ✅ Automatic failure debugging
  • ⚠️ Requires Tenderly account

3. Enso

Specialized simulation for complex DeFi interactions:
[enso]
url = "http://localhost:8454"
network-block-interval = "12s"
  • ✅ Optimized for DeFi protocols
  • ✅ Fast execution
  • ⚠️ Requires Enso service

Simulation Tuning

Optimize simulation behavior:
disable-access-list-simulation = true  # Skip access list generation
disable-gas-simulation = "45000000"    # Use fixed gas limit

Settlement Encoding

Driver converts solutions to settlement contract calldata:
// Settlement executes:
// 1. Pre-interactions (incl user pre-hooks)
// 2. Transfer sell tokens in
// 3. Main interactions (swaps/routing)
// 4. Pay out buy tokens
// 5. Post-interactions (incl user post-hooks)

Transaction Submission

Gas Price Management

From crates/driver/example.toml:
[submission]
gas-price-cap = "1000000000000"  # Maximum gas price in wei

Mempool Configuration

Configure multiple mempools for transaction submission:
[[submission.mempool]]
url = "https://your.custom.rpc.endpoint"
name = "custom_name"                   # Optional
max-additional-tip = "5000000000"      # Optional: max extra tip
additional-tip-percentage = 0.05       # Optional: 5% extra tip
mines-reverting-txs = true             # Whether node mines failed txs
Mempool features:
  • Multiple submission endpoints for redundancy
  • Automatic gas price adjustment
  • Transaction replacement logic
  • Nonce management
  • Reorg handling

Account Management

Solvers can use different accounts for submission:
[[solver]]
name = "mysolver"
account = "0x0000000000000000000000000000000000000000000000000000000000000001"

# Or use address for externally-managed key
# account = { address = "0x1234..." }
Private keys in config files should be encrypted or managed via secret management systems in production.

Configuration Options

Command-Line Arguments

From crates/driver/src/infra/cli.rs:
ArgumentEnvironment VariableDefaultDescription
--addrADDR0.0.0.0:11088HTTP server address
--logLOGwarn,driver=debugLog filter
--ethrpcETHRPCRequiredEthereum RPC URL
--ethrpc-max-batch-sizeETHRPC_MAX_BATCH_SIZE20RPC batch size
--ethrpc-max-concurrent-requestsETHRPC_MAX_CONCURRENT_REQUESTS10Concurrent RPC calls
--configCONFIGRequiredPath to TOML config

Configuration File Structure

Complete example from crates/driver/example.toml:
[[solver]]
name = "mysolver"
endpoint = "http://0.0.0.0:7872"
absolute-slippage = "40000000000000000"  # 0.04 ETH
relative-slippage = "0.1"                # 10%
account = "0x0000...0001"                # Private key
merge-solutions = true                   # Combine solutions
response-size-limit-max-bytes = 30000000

[solver.request-headers]
authorization = "Bearer YOUR_TOKEN"

Colocated vs Non-Colocated Solvers

From CLAUDE.md architecture description:

Colocated Solvers

External partners run their own driver + solver:
┌─────────────────────────┐
│ Partner Infrastructure  │
│  ┌────────┐  ┌────────┐ │
│  │ Driver │──│ Solver │ │
│  └────────┘  └────────┘ │
└─────────────────────────┘
  • ✅ Full control over infrastructure
  • ✅ Can optimize driver for specific solver
  • ✅ Keep solver logic private
  • ⚠️ Must maintain driver version
  • ⚠️ Responsible for settlements

Non-Colocated Solvers

We run the driver, configured with solver API:
┌───────────────┐      ┌──────────────────┐
│  Our Driver   │─────▶│ Partner Solver   │
└───────────────┘      │ (API endpoint)   │
                       └──────────────────┘
  • ✅ CoW Protocol handles driver maintenance
  • ✅ Simplified partner integration
  • ✅ Protocol manages settlements
  • ⚠️ Solver must expose HTTP API
  • ⚠️ Less infrastructure control
Non-colocated is recommended for new solvers. It reduces operational burden and lets partners focus on algorithm development.

Running the Service

Basic Setup

1

Create Configuration

Create a driver-config.toml file with your solver(s) and liquidity sources
2

Run Driver

Start the service:
cargo run --bin driver -- \
  --addr 0.0.0.0:11088 \
  --config /path/to/driver-config.toml \
  --ethrpc https://mainnet.infura.io/v3/YOUR_KEY
3

Verify

Check health:
curl http://localhost:11088/metrics

Docker Deployment

FROM ghcr.io/cowprotocol/services:latest

COPY driver-config.toml /config.toml

CMD ["driver", \
     "--addr", "0.0.0.0:11088", \
     "--config", "/config.toml", \
     "--ethrpc", "${ETHRPC_URL}"]

Environment Configuration

export ADDR=0.0.0.0:11088
export CONFIG=/path/to/config.toml
export ETHRPC=https://mainnet.infura.io/v3/YOUR_KEY
export LOG="info,driver=debug"
export USE_JSON_LOGS=true

cargo run --bin driver

API Endpoints

POST /solve

Receive auction and return solutions:
{
  "id": "123456",
  "orders": [...],
  "tokens": {...},
  "liquidity": [...]
}
Response:
{
  "solutions": [
    {
      "id": "1",
      "trades": [...],
      "score": "1000000000000000000"
    }
  ]
}

POST /settle

Execute winning solution:
{
  "solution_id": "1",
  "auction_id": "123456"
}
Response:
{
  "tx_hash": "0xabc123...",
  "status": "submitted"
}

POST /quote

Generate quote for trading:
{
  "sell_token": "0x...",
  "buy_token": "0x...",
  "amount": "1000000000000000000",
  "kind": "sell"
}
See the OpenAPI documentation at /docs endpoint for complete API reference.

Monitoring and Debugging

Metrics

Prometheus metrics available:
  • driver_solve_duration_seconds - Time to process /solve requests
  • driver_simulation_duration_seconds - Simulation latency
  • driver_settlement_submissions - Settlement submission attempts
  • driver_liquidity_fetch_duration_seconds - Liquidity fetch time

Logging

Structured logs with trace IDs:
export LOG="warn,driver=debug,driver::infra::solver=trace,shared=debug"

Tenderly Integration

If using Tenderly simulator:
[tenderly]
save-if-fails = true  # Auto-save failed simulations
Failed simulations appear in Tenderly dashboard with full execution traces.

Performance Optimization

RPC Batching

Batch multiple RPC calls:
--ethrpc-max-batch-size 50

Concurrent Requests

Increase parallelism:
--ethrpc-max-concurrent-requests 20

Liquidity Caching

Pre-initialize pools:
max_pools_to_initialize = 200

Simulation

Use Tenderly for speed:
[tenderly]
url = "..."

Troubleshooting

Solver Connection Failures

Check solver endpoint is accessible:
curl http://solver-endpoint:7872/health

Simulation Failures

Review simulation logs and verify:
  • Token allowances
  • Sufficient balances
  • Valid solution encoding
  • Gas limits

Transaction Submission Errors

Common issues:
  • Nonce conflicts (check mempool state)
  • Gas price too low
  • Insufficient ETH for gas
  • Smart contract reverts

High Latency

Optimize:
  1. Increase RPC batch size
  2. Use Tenderly for simulation
  3. Reduce liquidity sources
  4. Enable request compression

Build docs developers (and LLMs) love