Разработка solver для intent-based протоколов
Intent-based архитектура — это сдвиг от «пользователь указывает точный маршрут транзакции» к «пользователь описывает желаемый результат». Вместо swapExactInputSingle(WETH, USDC, 500, 1e18, minOut, deadline) пользователь подписывает intent: «хочу получить не менее 3000 USDC за 1 WETH до завтрашнего утра». Как именно это исполнится — задача solver-а.
CoW Protocol, UniswapX, 1inch Fusion, ERC-7683 (cross-chain intents) — все эти системы требуют кастомных solver-ов для конкурентного исполнения ордеров.
Что делает solver и почему это нетривиально
Solver — это off-chain агент, который:
- Получает intent пользователя (подписанный EIP-712 ордер)
- Находит оптимальный способ его исполнения
- Составляет on-chain транзакцию (или bundle) для settlement
- Конкурирует с другими solver-ами за право исполнить ордер
Конкуренция — ключевое слово. В CoW Protocol solver-ы соревнуются в batch auction: каждые ~30 секунд система принимает решения от нескольких solver-ов и выбирает того, кто предоставил пользователю наибольший surplus (разницу между ожидаемым и реальным исходом).
Проигравшие solver-ы не получают ничего за вычисления. Это создаёт интенсивный стимул к оптимизации скорости и качества решения.
UniswapX: архитектура и механизм исполнения
UniswapX использует Dutch auction: заполнитель (filler/solver) может исполнить ордер в любой момент до истечения времени. Начальная цена выгодна пользователю, постепенно сдвигается в пользу solver-а. Первый solver, который исполняет ордер при приемлемом соотношении — выигрывает.
Структура ордера UniswapX (ExclusiveFillerOrder):
interface ExclusiveFillerOrder {
info: {
reactor: Address // UniswapX Reactor контракт
swapper: Address // Пользователь
nonce: bigint
deadline: bigint
additionalValidationContract: Address
additionalValidationData: Hex
}
exclusiveFiller: Address // Приоритетный filler (если есть)
exclusivityOverrideBps: number
input: {
token: Address
amount: bigint
}
outputs: Array<{
token: Address
startAmount: bigint // Начало Dutch auction (выгодно пользователю)
endAmount: bigint // Конец auction (выгодно solver-у)
recipient: Address
}>
}
Solver получает input.amount от пользователя, должен вернуть минимум currentOutput (значение между startAmount и endAmount в зависимости от timestamp).
Reactor контракт и settlement
UniswapX Reactor — это on-chain контракт, который верифицирует подпись пользователя, проверяет currentOutput по времени, и управляет transfer-ами. Solver вызывает execute(order, signature, fillData).
Ключевой момент: solver получает input токены в начале исполнения и должен вернуть output токены к концу той же транзакции. Между получением и возвратом solver может использовать любые on-chain протоколы — это и есть пространство для оптимизации.
Поиск оптимального пути исполнения
Задача solver-а — максимизировать surplus при заданных input/output. Surplus = actualOutput - minRequiredOutput. Лучший surplus → выше вероятность выиграть auction в batch-системах.
Routing через несколько DEX
Базовый подход — поиск лучшей цены через агрегатор:
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]
}
Это параллельный запрос — latency определяется самым медленным источником, не суммой. Для production timeout каждого источника — 500ms, выбираем лучший из ответивших.
Split routing
Если одного DEX недостаточно для исполнения без большого slippage — разбиваем на части:
// 60% через Uniswap V3, 40% через Curve
const splits = [
{ dex: 'uniswap_v3', fraction: 0.6, amountIn: amountIn * 6n / 10n },
{ dex: 'curve', fraction: 0.4, amountIn: amountIn * 4n / 10n }
]
Split routing эффективен для крупных ордеров, где единый маршрут даёт значительный price impact.
Private liquidity (RFQ)
Помимо on-chain DEX, solver может иметь доступ к приватным маркет-мейкерам через RFQ (Request for Quote). Маркет-мейкер отвечает подписанной котировкой — если она лучше on-chain маршрута, solver использует её.
CoW Protocol поддерживает это через GPv2 interaction: solver включает signed quote от маркет-мейкера как часть settlement.
CoW Protocol solver: batch auction механика
В CoW Protocol batch auction происходит так:
- Orderbook: пользователи подписывают ордера (CoW Swap UI или напрямую), ордера попадают в публичный orderbook API
-
Auction call: каждые ~30 секунд CoW Protocol вызывает
/solveна зарегистрированных solver-ах - Solver computation: solver получает список ордеров в batch, находит оптимальный набор исполнений (включая CoW — совпадение встречных ордеров без DEX)
- Submission: solver отправляет решение с calldata для on-chain settlement
- Winner selection: выбирается solver с наибольшим суммарным surplus для batch
- On-chain settlement: winning solver исполняет транзакцию через GPv2Settlement контракт
CoW (Coincidence of Wants) — особенность: если в batch есть ордер на продажу ETH за USDC и ордер на продажу USDC за ETH — solver может матчировать их напрямую. Нет DEX fee, нет price impact. Обе стороны получают лучшую цену.
Регистрация solver-а в CoW Protocol
Solver должен быть авторизован CoW DAO. Для участия в продакшн аукционах нужен внесённый bond (DAO governance голосование). Для тестирования — staging environment без bond.
Инфраструктура solver-а
Требования к производительности критичны: CoW auction window — 30 секунд, из которых часть уходит на получение ордеров и отправку решения. Реальное время на computation — 10–15 секунд.
Языки: Rust или Go для production solver-а (Python/Node.js приемлемы для простых стратегий). Rust с tokio async runtime позволяет параллельный RPC к десяткам источников за 100–200ms.
Кэш состояния пулов: хранение актуальных резервов/sqrtPrice топ-100 пулов в памяти, обновление через WebSocket subscriptions на события Sync/Swap. Это позволяет рассчитывать маршруты без RPC вызовов — latency microseconds вместо milliseconds.
Симулятор: in-process EVM симулятор (revm) для проверки маршрута без on-chain вызова. Критично для CoW batching, где нужно симулировать N ордеров одновременно.
Стек разработки
Solver off-chain: Rust + alloy (новый ethereum crate, замена ethers-rs). Параллельный routing через tokio tasks.
Settlement контракт (при необходимости кастомного): Solidity 0.8.24 + Foundry fork-тесты против реальных UniswapX/CoW контрактов.
Мониторинг: Prometheus метрики (win rate, avg surplus, latency по источникам), Grafana дашборд, Telegram алерты при win rate < 5%.
Процесс работы
Аналитика (2–3 дня). Выбор протокола (UniswapX, CoW, 1inch Fusion, ERC-7683), анализ конкурентной среды solver-ов, оценка ROI.
MVP solver (1 неделя). Базовый routing через 2–3 DEX, settlement интеграция, регистрация в staging.
Оптимизация (1 неделя). Split routing, RFQ интеграции, кэш состояния пулов, latency оптимизация.
Production деплой. Регистрация в mainnet (для CoW — governance), мониторинг win rate.
Ориентиры по срокам
Базовый UniswapX filler с простым routing — 1 неделя. Полноценный CoW Protocol solver с CoW matching, split routing и RFQ — 3–4 недели.







