Агрегатор 1inch показал простую идею: если ты ищешь лучшую цену только на одном DEX — ты оставляешь деньги на столе. С тех пор системы маршрутизации ордеров выросли до сложных решений с split routing, multi-hop и специализированными алгоритмами. Мы проектируем и внедряем такие системы под ключ — с нуля или как расширение существующей инфраструктуры.
Собственная система маршрутизации ордеров нужна, когда стандартные агрегаторы (1inch, Paraswap, 0x) не поддерживают нужный чейн; требуется интеграция кастомных протоколов; нужен контроль над источниками ликвидности; или существующие API слишком медленны для торгового бота. Наш опыт — 5+ лет в блокчейн-разработке и 30+ проектов в DeFi.
Как работает система маршрутизации ордеров через несколько DEX?
Маршрутизация — это задача поиска пути в взвешенном направленном графе. Вершины — токены. Рёбра — пулы (каждый пул создаёт два направленных ребра: A→B и B→A с ценой в данном направлении).
Для поиска лучшего пути при фиксированном amountIn — задача поиска пути с максимальным произведением обменных курсов (или эквивалентно — минимальной суммой отрицательных логарифмов). Это модификация алгоритма Беллмана-Форда или Дейкстры.
Но есть нюанс, который делает задачу сложнее: цена в пуле зависит от объёма. Для amountIn = 100 USDC лучший маршрут может быть Uniswap V3 пул 0.05%. Для amountIn = 1 000 000 USDC тот же пул даст 3% slippage, а split между несколькими пулами даст 0.3%. Это превращает задачу из поиска пути в граф с фиксированными весами в оптимизационную задачу с объёмо-зависимыми весами.
Как split routing снижает проскальзывание на крупных ордерах?
Для крупных ордеров оптимальное решение — не единый маршрут, а распределение объёма по нескольким путям. Подход через бинарный поиск оптимального split для двух маршрутов:
function findOptimalSplit(
routeA: Route,
routeB: Route,
totalAmount: bigint,
steps: number = 20
): { splitA: bigint; splitB: bigint; totalOut: bigint } {
let bestSplit = { splitA: 0n, splitB: totalAmount, totalOut: 0n }
for (let i = 0; i <= steps; i++) {
const fraction = i / steps
const amountA = BigInt(Math.floor(Number(totalAmount) * fraction))
const amountB = totalAmount - amountA
const outA = amountA > 0n ? simulateRoute(routeA, amountA) : 0n
const outB = amountB > 0n ? simulateRoute(routeB, amountB) : 0n
const totalOut = outA + outB
if (totalOut > bestSplit.totalOut) {
bestSplit = { splitA: amountA, splitB: amountB, totalOut }
}
}
return bestSplit
}
Для N маршрутов задача становится N-мерной оптимизацией — применяют gradient descent или Nelder-Mead с ограничениями (сумма долей = 1, все доли ≥ 0).
Симуляция пулов: точность vs скорость
Uniswap V2: точная формула — разработка системы маршрутизации
function getAmountOutV2(amountIn: bigint, reserveIn: bigint, reserveOut: bigint): bigint {
const amountInWithFee = amountIn * 997n
const numerator = amountInWithFee * reserveOut
const denominator = reserveIn * 1000n + amountInWithFee
return numerator / denominator
}
Uniswap V2 Whitepaper
Uniswap V3: tick traversal
V3 требует итерации по tick bitmap для нахождения ближайших активных tick-ов. Полная симуляция точна, но медленна — несколько миллисекунд на крупный своп с traversal через множество tick-ов.
Для быстрой оценки (при скриннинге маршрутов) используем приближение через текущий sqrtPriceX96 и liquidity без tick traversal — точно для малых объёмов, с погрешностью для крупных. Точную симуляцию запускаем только для финальных кандидатов.
Curve StableSwap: итерационная формула
Curve использует инвариант A * n^n * sum(x_i) + D = A * D * n^n + D^(n+1) / (n^n * prod(x_i)). Расчёт amountOut — итерационный (Newton's method). Для JavaScript/TypeScript — BigInt арифметика с 18-decimal precision.
Balancer WeightedPool
Balancer с весовыми пулами (например, 80/20 BAL/ETH) использует другой инвариант. getAmountOut зависит от весов токенов в пуле — более сложная формула, чем V2.
On-chain vs off-chain маршрутизация
Маршрутизация может происходить полностью on-chain (смарт-контракт находит маршрут прямо в транзакции) или off-chain (вычисления вне чейна, результат передаётся в контракт).
On-chain маршрутизация: полная прозрачность, невозможность манипуляции со стороны aggregator-а. Проблема: ограниченный gas, нельзя перебрать все маршруты. Применяется для простых случаев (2–3 пула maximum).
Off-chain маршрутизация (подход 1inch, Paraswap): вычисления в backend, контракту передаётся готовый маршрут. Контракт только исполняет. Gas эффективнее, маршрут сложнее. Риск: backend может вернуть субоптимальный маршрут. Защита через slippage protection: minAmountOut в транзакции гарантирует пользователю минимум.
Как устроен router контракт?
Контракт должен поддерживать гетерогенные маршруты: часть через Uniswap V2, часть через V3, часть через Curve.
struct SwapStep {
address pool;
address tokenIn;
address tokenOut;
uint24 fee; // Для V3
uint8 dexType; // 0=V2, 1=V3, 2=Curve, 3=Balancer
bytes extraData; // Дополнительные параметры под тип DEX
}
function multiSwap(
SwapStep[] calldata steps,
uint256 amountIn,
uint256 minAmountOut,
address recipient
) external returns (uint256 amountOut) {
IERC20(steps[0].tokenIn).transferFrom(msg.sender, address(this), amountIn);
uint256 currentAmount = amountIn;
for (uint256 i = 0; i < steps.length; i++) {
currentAmount = _executeStep(steps[i], currentAmount);
}
require(currentAmount >= minAmountOut, "Slippage exceeded");
IERC20(steps[steps.length-1].tokenOut).transfer(recipient, currentAmount);
return currentAmount;
}
_executeStep диспатчит к конкретной DEX-реализации по dexType. Каждая реализация — отдельная библиотека (Solidity library pattern) для экономии bytecode size.
Почему кэш пулов критичен для скорости?
Для быстрой маршрутизации без RPC-вызовов на каждый запрос нужен кэш актуального состояния пулов: WebSocket subscriptions на события Sync (V2 пулы) и Swap (V3 пулы) через eth_subscribe("logs"). При каждом событии обновляем reserves/sqrtPrice в памяти.
Для 500–1000 активных пулов это ~50–100 событий/блок на Ethereum mainnet. Обработка через event-driven архитектуру (Node.js EventEmitter или Rust tokio channel) с ≤1ms задержкой обновления.
Cold start: при запуске сервиса нужно загрузить текущее состояние всех пулов через multicall. Для 1000 пулов — 5–10 multicall транзакций (до 200 calls каждый), занимает 1–3 секунды.
Сравнение архитектурных подходов
| Подход | Когда подходит | Сложность | Latency |
|---|---|---|---|
| Простой multi-hop | 3–5 чейнов, топ-5 DEX | Низкая | 200–500ms |
| Split routing | Крупные ордера ($50K+) | Средняя | 500ms–1s |
| С кэшем пулов | Торговый бот, < 50ms | Высокая | 10–50ms |
| On-chain router | Максимальная прозрачность | Средняя | 1 блок |
Ориентировочные сроки разработки
| Этап | Время |
|---|---|
| Аналитика (список DEX, требования к latency) | 1–2 дня |
| Разработка routing engine (граф, алгоритм, симуляция) | 5–7 дней |
| Router контракт (multi-step, fork-тесты) | 3–5 дней |
| Кэш пулов (WebSocket + in-memory) | 3–5 дней |
| Интеграция, тестирование, документация | 2–3 дня |
Этапы разработки в виде пошаговой инструкции
- Анализ пулов и графа ликвидности — составляем карту токенов и пулов для ваших чейнов.
- Разработка алгоритма поиска пути — реализация модифицированного Дейкстры с учётом объёмной зависимости.
- Интеграция симуляций — пишем симуляторы для Uniswap V2/V3, Curve, Balancer.
- Тестирование на mainnet fork — прогоняем ордера разных объёмов, сверяем с эталоном.
- Развёртывание и мониторинг — запуск в тестовой сети и mainnet, настройка алертов.
Что входит в работу
- Архитектурная документация: описание графа пулов, схема кэширования, спецификация контракта.
- Routing engine: реализация поиска пути и split routing с поддержкой V2/V3/Curve/Balancer.
- Router контракт: multi-step исполнение с защитой от slippage.
- Кэш пулов (опционально): WebSocket подписки + in-memory хранилище.
- Тестирование: fork-тесты Foundry, фаззинг Echidna.
- Интеграция: развёртывание в тестовой сети и mainnet, настройка мониторинга.
- Обучение команды: внутренняя документация, code review.
Закажите консультацию — пришлём технико-коммерческое предложение через 1 день после брифа. Получите детальный анализ вашей текущей инфраструктуры и рекомендации по оптимизации маршрутизации. Свяжитесь с нами, чтобы обсудить ваш проект.







