Skip to main content
The Autopilot service is the central coordinator of CoW Protocol. It orchestrates batch auctions by gathering orders, running solver competitions, selecting winners, and managing settlement execution.

Purpose and Responsibilities

Autopilot acts as the protocol’s auctioneer and coordinator:
  • Auction Management: Runs auctions every ~12-15 seconds (eventually every block)
  • Order Filtering: Selects solvable orders from the orderbook based on validity and balances
  • Fee Policy Application: Applies protocol fee policies to orders
  • Solver Competition: Distributes auctions to drivers and collects solutions
  • Winner Selection: Ranks solutions and picks the best settlement(s)
  • Settlement Monitoring: Tracks on-chain execution and settlement outcomes

Auction Management

Auction Cycle

Autopilot runs a continuous loop with the following phases:
// From crates/autopilot/src/run_loop.rs
pub struct Config {
    pub submission_deadline: u64,
    pub max_settlement_transaction_wait: Duration,
    pub solve_deadline: Duration,
    pub max_run_loop_delay: Duration,
    pub max_winners_per_auction: NonZeroUsize,
    pub max_solutions_per_solver: NonZeroUsize,
    pub enable_leader_lock: bool,
    pub compress_solve_request: bool,
}
Typical auction timeline (~12-15 seconds):
  1. Block synchronization (0-2s): Wait for new block
  2. Maintenance (0-5s): Update prices, indexed events, and CoW AMMs
  3. Order preparation (0-1s): Fetch and filter solvable orders
  4. Solver competition (12-15s): Send auction to drivers, collect solutions
  5. Winner selection (0-1s): Rank solutions and pick winner(s)
  6. Settlement execution (1-60s): Winning driver(s) submit to chain
The solve_deadline parameter controls how long solvers have to compute solutions. Default is 15 seconds.

Auction Creation

The autopilot creates auctions from solvable orders:
let solvable_orders_cache = SolvableOrdersCache::new(
    args.min_order_validity_period,
    persistence.clone(),
    infra::banned::Users::new(
        eth.contracts().chainalysis_oracle().clone(),
        config.banned_users.addresses,
        config.banned_users.max_cache_size.get().to_u64().unwrap(),
    ),
    balance_fetcher.clone(),
    deny_listed_tokens.clone(),
    competition_native_price_updater.clone(),
    *eth.contracts().weth().address(),
    domain::ProtocolFees::new(
        &config.fee_policies,
        args.shared.volume_fee_bucket_overrides.clone(),
        args.shared.enable_sell_equals_buy_volume_fee,
    ),
    cow_amm_registry.clone(),
    args.run_loop_native_price_timeout,
    *eth.contracts().settlement().address(),
    args.disable_order_balance_filter,
);

Order Inclusion Logic

The autopilot filters orders to include in each auction:

Filtering Criteria

Valid orders must meet:
  • ✅ Valid signature
  • ✅ Not expired (valid until timestamp not reached)
  • ✅ Sufficient balance (unless disable_order_balance_filter is set)
  • ✅ Not from banned addresses
  • ✅ Not using denied tokens
  • ✅ Minimum validity period remaining
  • ✅ Compatible with current auction ID

Order Types

The autopilot handles multiple order types:
  • Market orders: Fill-or-kill orders seeking immediate execution
  • Limit orders: Partial-fill allowed, can remain in orderbook
  • EthFlow orders: Orders created via ETH deposits
  • CoW AMM orders: Automated market maker orders

Solver Competition Coordination

Driver Communication

Autopilot distributes auctions to all configured drivers:
let drivers_futures = config
    .drivers
    .into_iter()
    .map(|driver| async move {
        infra::Driver::try_new(driver.url, driver.name.clone(), driver.submission_account)
            .await
            .map(Arc::new)
            .expect("failed to load solver configuration")
    })
    .collect::<Vec<_>>();

let drivers: Vec<_> = futures::future::join_all(drivers_futures).await;

Competition Process

1

Auction Distribution

Autopilot sends the auction to all drivers via HTTP POST to /solve endpoint
2

Solution Collection

Drivers have solve_deadline seconds to return solutions
3

Solution Validation

Autopilot validates each solution meets requirements
4

Winner Selection

Solutions are ranked by objective value and winner(s) selected
5

Settlement Request

Winning driver(s) receive /settle request with execution details

Request Compression

For large auctions, autopilot can compress /solve request bodies:
--compress-solve-request true

Fee Policies

Autopilot applies protocol fee policies to orders based on their characteristics:

Fee Policy Types

From crates/autopilot/src/config/fee_policy.rs:
pub enum FeePolicyKind {
    /// How much of the order's surplus should be taken as a protocol fee.
    Surplus {
        factor: FeeFactor,
        max_volume_factor: FeeFactor,
    },
    /// How much of the order's price improvement should be taken as a protocol fee
    /// where price improvement is the difference between executed price and best quote.
    PriceImprovement {
        factor: FeeFactor,
        max_volume_factor: FeeFactor,
    },
    /// How much of the order's volume should be taken as a protocol fee.
    Volume { factor: FeeFactor },
}

Fee Configuration

Fee policies are configured per order class:
[[policies]]
kind.surplus = { factor = 0.5, max-volume-factor = 0.01 }
order-class = "market"

Partner Fees

The protocol supports partner fee caps:
max-partner-fee = 0.01  # Maximum 1% partner fee

Upcoming Fee Changes

Fee policies can be scheduled for future activation:
[upcoming-policies]
effective-from-timestamp = "2025-06-01T00:00:00Z"

[[upcoming-policies.policies]]
kind.volume = { factor = 0.002 }
order-class = "any"

Configuration Options

Command-Line Arguments

Key parameters from crates/autopilot/src/arguments.rs:
ArgumentEnvironment VariableDefaultDescription
--configCONFIGRequiredPath to TOML config
--metrics-addressMETRICS_ADDRESS0.0.0.0:9589Metrics server address
--api-addressAPI_ADDRESS0.0.0.0:12088API server address
--db-write-urlDB_WRITE_URLpostgresql://Database URL
--solve-deadlineSOLVE_DEADLINE15sSolver time limit
--submission-deadlineSUBMISSION_DEADLINE5Max blocks for settlement
--max-settlement-transaction-waitMAX_SETTLEMENT_TRANSACTION_WAIT1mSettlement wait time
--max-auction-ageMAX_AUCTION_AGE5mMax time since last auction
--max-winners-per-auctionMAX_WINNERS_PER_AUCTION20Max parallel winners
--max-solutions-per-solverMAX_SOLUTIONS_PER_SOLVER3Solutions per solver
--max-run-loop-delayMAX_RUN_LOOP_DELAY2sMax delay before resync
--enable-leader-lockENABLE_LEADER_LOCKfalseEnable HA leader election
--compress-solve-requestCOMPRESS_SOLVE_REQUESTfalseCompress auction data
--skip-event-syncSKIP_EVENT_SYNCfalseSkip historical events

Configuration File

The autopilot requires a TOML configuration file:
[[drivers]]
name = "solver-1"
url = "http://solver-1.example.com:11088"
submission-account = "address:0x1234..."  # or "private-key:0xabcd..."

[[drivers]]
name = "solver-2"
url = "http://solver-2.example.com:11088"
submission-account = "private-key:0x5678..."

Running the Service

Basic Setup

1

Start Dependencies

Start PostgreSQL and ensure an Ethereum node is available:
docker compose up -d
2

Create Configuration

Create a configuration file with drivers and fee policies
3

Run Autopilot

Start the service:
cargo run --bin autopilot -- \
  --config /path/to/config.toml \
  --db-write-url postgresql://user:pass@localhost/db \
  --node-url https://mainnet.infura.io/v3/YOUR_KEY \
  --solve-deadline 15s \
  --max-winners-per-auction 20
4

Monitor

Check metrics and logs:
curl http://localhost:9589/metrics

Shadow Mode

For testing without actual settlements:
cargo run --bin autopilot -- \
  --config /path/to/config.toml \
  --shadow https://api.cow.fi/mainnet
Shadow mode pulls auctions from an upstream CoW Protocol deployment and simulates competition without submitting settlements.

High Availability

Enable leader election for multiple autopilot instances:
--enable-leader-lock true
Only the leader instance will cut auctions; followers will remain on standby.

Database Schema Usage

Autopilot interacts with several PostgreSQL tables:

Core Tables

  • orders: Stores all submitted orders
  • order_events: Tracks order lifecycle events
  • trades: Records executed trades
  • settlements: Stores settlement transaction data
  • solver_competitions: Archives competition results
  • auction_prices: Caches native token prices

Event Indexing

Autopilot indexes on-chain events:
let settlement_event_indexer = EventUpdater::new(
    boundary::events::settlement::GPv2SettlementContract::new(
        web3.provider.clone(),
        *eth.contracts().settlement().address(),
    ),
    boundary::events::settlement::Indexer::new(
        db_write.clone(),
        settlement_contract_start_index,
    ),
    block_retriever.clone(),
    skip_event_sync_start,
);
Indexed events:
  • Settlement events from GPv2Settlement contract
  • EthFlow order creation and refunds
  • CoW AMM pool deployments and updates

Cleanup Tasks

Periodic database maintenance:
let order_events_cleaner = crate::periodic_db_cleanup::OrderEventsCleaner::new(
    order_events_cleaner_config,
    db_write.clone(),
);

Observability

Metrics

Prometheus metrics available at http://localhost:9589/metrics:
  • autopilot_auction_duration_seconds - Time to complete auction
  • autopilot_solutions_received - Solutions per auction
  • autopilot_settlement_submissions - Settlement submission attempts
  • autopilot_last_auction_timestamp - Last successful auction time

Liveness Checks

The service implements liveness checking:
impl LivenessChecking for Liveness {
    async fn is_alive(&self) -> bool {
        let last_auction_time = self.last_auction_time.read().unwrap();
        let auction_age = last_auction_time.elapsed();
        auction_age <= self.max_auction_age
    }
}
Kubernetes liveness probe will fail if no auction runs within max_auction_age.

Logging

Structured logging with contextual information:
export LOG_FILTER="info,autopilot=debug,run_loop=trace"
export USE_JSON_LOGS=true

Advanced Features

CoW AMM Integration

Autopilot can index and include CoW AMM pools:
--cow-amm-configs "0xfactory|0xhelper|12345678"
Format: factory_address|helper_address|start_block

EthFlow Support

Enable EthFlow order handling:
--ethflow-contracts 0xEthFlowContract1,0xEthFlowContract2 \
--ethflow-indexing-start 17000000

Archive Node

For historical event indexing:
--archive-node-url https://archive.node.example.com

Performance Tuning

Solver Deadline

Balance between solution quality and auction frequency:
--solve-deadline 12s

Maintenance Timeout

Limit maintenance time to avoid stalling:
--max-maintenance-timeout 5s

Database Pool

Tune connection pool for load:
--db-max-connections 20

Request Compression

Enable for large auctions:
--compress-solve-request true

Troubleshooting

Auctions Not Running

Check:
  1. Database connectivity
  2. Ethereum node sync status
  3. Driver availability
  4. Liveness check status

No Solvable Orders

Common causes:
  • All orders expired
  • Insufficient balances
  • Token deny list blocking trades
  • Price estimation failures

Settlement Failures

Investigate:
  1. Driver logs for error details
  2. On-chain transaction status
  3. Gas price estimation
  4. Smart contract event logs
  • Orderbook - Provides orders to Autopilot
  • Driver - Executes settlements from Autopilot
  • Solver - Computes solutions for auctions