Onboarding: CoW Protocol Services (this repo)
April 9, 2026 · View on GitHub
This repository is a Rust workspace containing the core backend services that run the CoW Protocol off-chain system:
- Users submit signed orders to the orderbook
- autopilot periodically creates auctions and sends them to drivers
- Each driver calls its solver(s) for solutions, then simulates + submits the winner to the on-chain Settlement contract
For local end-to-end development, use the playground stack. See playground/README.md.
System context (big picture)
flowchart LR
U["User / Wallet"] -->|signed order| OB["orderbook"]
UI["CoW Swap UI"] -->|quotes / orders| OB
OB <--> DB[("PostgreSQL")]
AP["autopilot"] <--> DB
AP -->|auction| DR["driver"]
AP -->|auction| CO["colocated solvers\n(own driver + solver)"]
DR -->|auction request| IS["internal solvers"]
DR -->|auction request| ES["external solver APIs"]
DR -->|simulate + submit tx| CH[("EVM chain\n+ Settlement contract")]
CO -->|submit tx| CH
AP -->|index events| CH
Core "happy path" flow (order → auction → settlement)
sequenceDiagram
autonumber
participant User
participant Orderbook as orderbook
participant DB as Postgres
participant Autopilot as autopilot
participant Driver as driver
participant Solver as solver(s)
participant Chain as EVM chain + Settlement contract
User->>Orderbook: GET /quote (fee + price estimate)
Orderbook-->>User: quote response
User->>Orderbook: POST /orders (signed order)
Orderbook->>Orderbook: validate (signature, app-data, funding/approval, etc.)
Orderbook->>DB: persist order + order events
Orderbook-->>User: 201 Created (order uid)
loop every new block (~12s on mainnet)
Autopilot->>DB: fetch eligible orders + state
Autopilot->>Autopilot: apply policies (fees, filtering, scoring inputs)
Autopilot->>DB: store current auction + competition metadata
Autopilot->>Driver: send auction (or make it available for fetch)
Driver->>Solver: request solution(s) for auction
Solver-->>Driver: proposed solution(s)
Driver->>Driver: encode calldata + simulate
Driver-->>Autopilot: submit bid(s)
Autopilot->>Autopilot: rank bids, pick winner
Autopilot->>Driver: tell winner to execute
Driver->>Chain: submit transaction (time-bounded)
Chain-->>Chain: execute settle(...) + emit events
Autopilot->>Chain: fetch + index relevant events
Autopilot->>DB: update competition/settlement tables + order events
end
Solver types
- Colocated: External partners run their own driver + solver. Autopilot sends them the auction and they submit solutions independently. Full control, full responsibility.
- Non-colocated: We run the driver, configured with their solver API endpoint. We handle simulation and submission on their behalf.
Responsibilities by service (what to touch for what change)
flowchart TB
subgraph OB["orderbook"]
OB1["HTTP API: orders, quotes, status"]
OB2["Validations: signatures, app-data, funding/approval checks"]
OB3["Persists orders + lifecycle events"]
end
subgraph AP["autopilot"]
AP1["Auction cutting: boundaries + inclusion"]
AP2["Filtering + fee policies + scoring inputs"]
AP3["Event indexing + competition metadata"]
end
subgraph DR["driver"]
DR1["Receive auction + fetch liquidity context"]
DR2["Call internal/external solvers"]
DR3["Encode solution to calldata, simulate"]
DR4["Submit tx, manage retries/time window"]
end
subgraph S["solvers"]
S1["Pure routing/matching math"]
S2["Return solution objects/calldata recipe"]
end
subgraph DBL["database layer"]
DBL1["migrations + schema"]
DBL2["typed query helpers used by services"]
end
AP --> DR
OB --> DBL
AP --> DBL
DR --> S
Key crates (where shared logic lives)
crates/shared: common utilities (order quoting/validation, fee logic, external prices, argument parsing)crates/price-estimation: price estimation strategies (onchain, trade-based, native)crates/gas-price-estimation: gas price estimationcrates/database: schema + DB helpers used byorderbookandautopilotcrates/model: API/data model types used across servicescrates/contracts: Alloy-based contract bindings for on-chain interactioncrates/ethrpc+crates/chain: Ethereum RPC / chain interaction helperscrates/observe: logging/metrics initialization helperscrates/app-data: order app-data validation
Where to start reading code (practical entrypoints)
Each service follows the same pattern: main.rs just sets up the allocator and calls start(), which lives in run.rs. The run.rs file parses CLI arguments, initializes logging/metrics, connects to the database and/or chain, and wires up the service components.
-
Orderbook (HTTP API + order validation)
- Start here:
crates/orderbook/src/run.rs(initialization + service wiring) - Typical changes: API endpoints, order validation, quoting, DB writes
- Start here:
-
Autopilot (auction creation + policies + event indexing)
- Start here:
crates/autopilot/src/run.rs - Typical changes: auction filtering/inclusion, fee policies, competition persistence, chain event indexing
- Start here:
-
Driver (simulation + settlement submission + solver integration)
- Start here:
crates/driver/README.mdfor context, thencrates/driver/src/run.rs - Typical changes: solver API integration, encoding/calldata, simulation logic, submission strategy
- Start here:
-
Solvers (internal solver engines)
- Start here:
crates/solvers/src/run.rs - Typical changes: routing/matching math, solution generation
- Start here:
-
On-chain bindings
- Start here:
crates/contracts/README.md - Typical changes: adding new contract artifacts/bindings, updating ABIs, exposing bindings in
lib.rs
- Start here:
-
Database schema + migrations
- Start here:
database/README.md(schema overview) andcrates/database(query code)
- Start here:
-
End-to-end tests
- Start here:
crates/e2e/tests/e2e/(individual test scenarios) andcrates/e2e/src/setup/(test harness) - The e2e crate spins up a local Anvil node (optionally forking mainnet/Gnosis), deploys contracts, starts services (orderbook, autopilot, driver, solver), and runs full order→settlement flows
- Tests are split into
local_node(clean chain) andforked_node(forking a real network viaFORK_URL_MAINNET/FORK_URL_GNOSIS) - Run local e2e tests:
cargo nextest run -p e2e local_node --test-threads 1 --failure-output final --run-ignored ignored-only - Run forked e2e tests:
cargo nextest run -p e2e forked_node --test-threads 1 --run-ignored ignored-only --failure-output final
- Start here:
Local development (recommended path)
Run the full stack (best for onboarding)
See playground/README.md. The short version is:
docker compose -f playground/docker-compose.fork.yml up --build
You'll need to set ETH_RPC_URL in playground/.env first (an Ethereum RPC endpoint for anvil to fork from). This starts a forked chain + Postgres + services + UI/Explorer components with live-reload behavior.
Fast local compile / test loop (without running the stack)
- Check:
cargo check --workspace --all-targets
- Unit tests (CI-compatible runner):
cargo nextest run
Formatting and linting
This repo formats Rust code with nightly rustfmt (and TOML with Tombi). See README.md for the just commands.
Database mental model (what’s in Postgres)
The DB stores orders, auctions, competitions, and indexed on-chain events.
- For a guided schema overview, see
database/README.md.
flowchart LR
OB["orderbook"] -->|orders + order_events + quotes| DB[("Postgres")]
AP["autopilot"] -->|auctions + competitions + event-derived tables| DB
AP -->|fetch + index chain events| CH[("chain")]
Debugging "why didn’t my order trade"?
When you need to investigate an order lifecycle end-to-end (API → DB → logs → auction inclusion → solver bids → settlement),
see COW_ORDER_DEBUG_SKILL.md.