Development of batch auction system (CoW-style)
CoW Protocol solved a problem that AMM doesn't handle: when user A wants to sell ETH for USDC and user B wants to sell USDC for ETH — why go to the pool and pay LP fees when you can match the orders directly? Coincidence of Wants (CoW) — this is direct settlement without AMM hop. Batch auction is a mechanism that aggregates orders over a period of time and finds optimal execution. Implementing such a system is more complex than AMM, but the mechanics protect users from front-running and MEV sandwich attacks.
How batch auction works: mechanics inside
Batch period and uniform clearing price
Every N seconds (in CoW Protocol — ~30 seconds) a batch closes. All orders submitted during this period are executed at a uniform clearing price — one price for all orders in the batch.
This is fundamentally different from continuous trading: you can't front-run a specific order if all orders execute simultaneously at one price. MEV sandwich is impossible — there's no before/after a specific transaction, there's a single settlement moment.
Uniform clearing price is determined as the price that maximizes trading volume: the maximum number of sell and buy orders that can be matched at the given price.
Solver architecture
Finding the optimal clearing price and routing is an NP-hard problem with many orders. CoW Protocol solves this through open competition among solvers: anyone can run a solver that proposes a solution for the current batch. The best solution (maximum surplus for users) wins.
For your own batch auction system you can:
- Simplified on-chain solver — implement a basic algorithm directly in the contract. Works for small batches (< 50 orders), limited by gas.
- Off-chain solver + on-chain settlement — solver computes off-chain, submits solution to the contract. The contract verifies correctness (orders executed at no worse than limit prices) and executes transfers. This is CoW's approach.
- Hybrid with AMM fallback — CoW matching for crossing orders, remainder routed to Uniswap/Curve.
Order structure and signature
Off-chain limit order in CoW style: user signs a structure (EIP-712), doesn't pay gas for the order itself. Settlement contract executes a batch of orders for one gas payment from the solver.
struct Order {
address sellToken;
address buyToken;
address receiver;
uint256 sellAmount;
uint256 buyAmount; // minimum buy amount (limit)
uint32 validTo; // deadline
bytes32 appData; // metadata
uint256 feeAmount; // gas compensation for solver
bytes32 kind; // SELL or BUY order
bool partiallyFillable;
bytes32 sellTokenBalance; // erc20 / internal / external
bytes32 buyTokenBalance;
}
Signature through EIP-712 + EIP-1271 (for contract wallets). Settlement contract verifies signature through isValidSignature when executing batch.
Surplus capture: how users win
If clearing price is better than the user specified in their limit order — the excess (surplus) returns to the user. Example: user wants to sell 1 ETH for minimum 3000 USDC. Clearing price — 3050 USDC. User gets 3050, not 3000. 50 USDC surplus.
In CoW Protocol part of the surplus goes to the solver as incentive. This creates right incentives: solver maximizes user surplus, gets a share.
Settlement contract implementation
On-chain verification of solution
Contract receives from solver an array of order executions and list of transfers. Verification:
- For each order:
executedSellAmount * buyPrice >= order.buyAmount(user received not less than limit) - Conservation law:
sum(sellAmounts) >= sum(buyAmounts)in base token (balance preserved) - All order signatures are valid
-
validTohasn't expired
If verification passes — settlement: transfers of all tokens through GPv2SafeERC20.transfer (special safe wrapper from CoW).
Flash accounting
CoW Protocol uses flash accounting for settlement: instead of sequential transfers with intermediate storage, all balances are computed as net flow. Settlement contract only needs to know final transfer sums, not intermediate states. This reduces gas 2-3x compared to naive implementation.
Implementation: internal ledger in mapping(address token => mapping(address account => int256 balance)). Positive = must pay out, negative = must receive. After all net calculations — final ERC-20 transfers only for non-zero balances.
Development stack
Solidity 0.8.x for settlement contract + OpenZeppelin for signature verification (ECDSA, EIP-1271). TypeScript for solver logic — npm package @cowprotocol/cow-sdk as reference. Foundry for testing with fuzz on surplus calculation correctness.
For off-chain orderbook storage: PostgreSQL + REST API. WebSocket for real-time updates of pending orders.
Work process
Design (3-5 days). Order structure, solver architecture (on-chain vs off-chain), fee model.
Settlement contract (2-3 weeks). Order verification, flash accounting, AMM fallback integration.
Off-chain components (1-2 weeks). Orderbook API, basic solver algorithm, signature relay.
Testing (1 week). Fuzz tests on solver outputs, integration tests with Uniswap v3 fallback.
Timeline estimates
Simplified batch auction with on-chain solver (small volume): 2-3 weeks. Full system with off-chain solver competition and AMM fallback: 4-6 weeks.







