Developing Solvers for Intent-Based Protocols
Intent-based architecture is a shift from "the user specifies the exact transaction route" to "the user describes the desired outcome". Instead of swapExactInputSingle(WETH, USDC, 500, 1e18, minOut, deadline), the user signs an intent: "I want to receive at least 3000 USDC for 1 WETH by tomorrow morning". How exactly this executes is the solver's job.
CoW Protocol, UniswapX, 1inch Fusion, ERC-7683 (cross-chain intents) — all these systems require custom solvers for competitive order execution.
What a Solver Does and Why It's Non-Trivial
A solver is an off-chain agent that:
- Receives the user's intent (a signed EIP-712 order)
- Finds the optimal way to execute it
- Builds an on-chain transaction (or bundle) for settlement
- Competes with other solvers for the right to execute the order
Competition is the keyword. In CoW Protocol, solvers compete in batch auctions: every ~30 seconds the system accepts solutions from multiple solvers and chooses the one that provided the user with the greatest surplus (the difference between expected and actual outcome).
Losing solvers get nothing for their computation. This creates intense incentive to optimize speed and solution quality.
UniswapX: Architecture and Execution Mechanism
UniswapX uses Dutch auctions: the filler (solver) can execute the order anytime before expiration. The initial price favors the user, gradually shifting in the solver's favor. The first solver who executes the order at an acceptable ratio wins.
UniswapX order structure (ExclusiveFillerOrder):
interface ExclusiveFillerOrder {
info: {
reactor: Address // UniswapX Reactor contract
swapper: Address // User
nonce: bigint
deadline: bigint
additionalValidationContract: Address
additionalValidationData: Hex
}
exclusiveFiller: Address // Priority filler (if any)
exclusivityOverrideBps: number
input: {
token: Address
amount: bigint
}
outputs: Array<{
token: Address
startAmount: bigint // Dutch auction start (user-favorable)
endAmount: bigint // Auction end (solver-favorable)
recipient: Address
}>
}
The solver receives input.amount from the user and must return at least currentOutput (a value between startAmount and endAmount depending on timestamp).
Reactor Contract and Settlement
The UniswapX Reactor is an on-chain contract that verifies the user's signature, checks currentOutput over time, and manages transfers. The solver calls execute(order, signature, fillData).
Key point: the solver receives input tokens at the beginning of execution and must return output tokens by the end of the same transaction. Between receiving and returning, the solver can use any on-chain protocols — this is the optimization space.
Finding the Optimal Execution Path
The solver's task is to maximize surplus given input/output. Surplus = actualOutput - minRequiredOutput. Better surplus → higher probability to win the auction in batch systems.
Routing Through Multiple DEXes
The basic approach is to find the best price through an aggregator:
async function findOptimalRoute(
tokenIn: Address,
tokenOut: Address,
amountIn: bigint
): Promise<RouteResult> {
const [uniV3Quote, aerodromeQuote, curveQuote, oneInchQuote] = await Promise.all([
quoteUniswapV3(tokenIn, tokenOut, amountIn),
quoteAerodrome(tokenIn, tokenOut, amountIn),
quoteCurve(tokenIn, tokenOut, amountIn),
quote1inch(tokenIn, tokenOut, amountIn)
])
const routes = [uniV3Quote, aerodromeQuote, curveQuote, oneInchQuote]
.filter(r => r.success)
.sort((a, b) => Number(b.amountOut - a.amountOut))
return routes[0]
}
This is parallel querying — latency is determined by the slowest source, not the sum. For production, set each source timeout to 500ms, picking the best among respondents.
Split Routing
If a single DEX isn't enough for execution without significant slippage — split into parts:
// 60% through Uniswap V3, 40% through Curve
const splits = [
{ dex: 'uniswap_v3', fraction: 0.6, amountIn: amountIn * 6n / 10n },
{ dex: 'curve', fraction: 0.4, amountIn: amountIn * 4n / 10n }
]
Split routing is efficient for large orders where a single route creates significant price impact.
Private Liquidity (RFQ)
Beyond on-chain DEXes, a solver may have access to private market makers through RFQ (Request for Quote). The market maker responds with a signed quote — if it's better than the on-chain route, the solver uses it.
CoW Protocol supports this through GPv2 interaction: the solver includes a signed quote from the market maker as part of settlement.
CoW Protocol Solver: Batch Auction Mechanics
In CoW Protocol, batch auctions work like this:
- Orderbook: users sign orders (CoW Swap UI or directly), orders enter the public orderbook API
-
Auction call: every ~30 seconds CoW Protocol calls
/solveon registered solvers - Solver computation: the solver receives a list of orders in the batch, finds the optimal set of executions (including CoW — matching opposite orders without DEX)
- Submission: solver sends the solution with calldata for on-chain settlement
- Winner selection: the solver with the greatest cumulative surplus for the batch is chosen
- On-chain settlement: winning solver executes the transaction through GPv2Settlement contract
CoW (Coincidence of Wants) is a special feature: if the batch has an order to sell ETH for USDC and an order to sell USDC for ETH — the solver can match them directly. No DEX fee, no price impact. Both sides get better prices.
Registering a Solver in CoW Protocol
A solver must be authorized by CoW DAO. To participate in production auctions, a deposited bond is required (DAO governance voting). For testing — staging environment without bond.
Solver Infrastructure
Performance requirements are critical: CoW auction window is 30 seconds, of which part goes to receiving orders and sending solutions. Real computation time is 10–15 seconds.
Languages: Rust or Go for production solvers (Python/Node.js acceptable for simple strategies). Rust with tokio async runtime allows parallel RPC to dozens of sources in 100–200ms.
Pool state cache: storing current reserves/sqrtPrice of top-100 pools in memory, updating via WebSocket subscriptions on Sync/Swap events. This allows calculating routes without RPC calls — latency in microseconds instead of milliseconds.
Simulator: in-process EVM simulator (revm) to verify routes without on-chain calls. Critical for CoW batching where you need to simulate N orders simultaneously.
Development Stack
Solver off-chain: Rust + alloy (new ethereum crate, ethers-rs replacement). Parallel routing through tokio tasks.
Settlement contract (if custom needed): Solidity 0.8.24 + Foundry fork-tests against real UniswapX/CoW contracts.
Monitoring: Prometheus metrics (win rate, avg surplus, latency per source), Grafana dashboard, Telegram alerts when win rate < 5%.
Work Process
Analytics (2–3 days). Choose protocol (UniswapX, CoW, 1inch Fusion, ERC-7683), analyze competitive solver environment, estimate ROI.
MVP solver (1 week). Basic routing through 2–3 DEXes, settlement integration, staging registration.
Optimization (1 week). Split routing, RFQ integrations, pool state cache, latency optimization.
Production deployment. Mainnet registration (for CoW — governance), win rate monitoring.
Timeline Guidelines
A basic UniswapX filler with simple routing — 1 week. A full CoW Protocol solver with CoW matching, split routing, and RFQ — 3–4 weeks.







