Розроблення DEX агрегатора
Розробник інтегрує swap прямо в один Uniswap v3 пул в dApp — і користувачі скаржаться на погані курси. Причина: для великих свопів ($50K+) ліквідність одного пулу не оптимальна. Розділення між кількома джерелами (split routing) може дати покращення ціни на 0.3-0.8%. На $100K своп це $300-800 різниці. Саме це робить агрегатор — знаходить оптимальний маршрут через кілька DEX одночасно.
Технічна складність: алгоритм маршрутизації
Граф ліквідності DEX та пошук шляху
Завдання маршрутизації — це пошук оптимального шляху в спрямованому графі, де:
- Вузли = токени
- Ребра = пулі (кожен пул створює два ребра: token0→token1 та назад)
- Вага ребра = вихідна сума для заданого входу
Для простого свопу A→B потрібен найкоротший шлях (максимізуючи вихід). Для split routing — розділити вхід на K частин та знайти K шляхів, які разом дають максимальний вихід.
Наївний підхід — перелічити всі шляхи довжини 1-3 хопів, порівняти виходи. Працює з кількома пулами. З 10,000+ пулами (Uniswap v3 на mainnet має >8,000 активних пулів) — потрібна оптимізація.
Практичний підхід:
- Передфільтрація: лише пулі з TVL > $100K та об'ємом > $10K за 24h
- Bellman-Ford для пошуку всіх шляхів до 3 хопів
- Для split routing: моделювання кількох пропорцій (100/0, 80/20, 60/40, 50/50) через кожен маршрут, вибір максимуму
Для EVM ланцюгів з високим газом (Ethereum mainnet) 3-способовий поділ вже недоцільний: економія від кращої ціни може бути перекрита додатковим газом. На Arbitrum/Optimism (газ ~$0.01-0.05) split routing вигідний навіть для малих свопів.
Моделювання виходу off-chain
Ключова вимога: розрахувати amountOut для кожного маршруту швидко та точно без on-chain викликів (вони дорогі та повільні).
Uniswap v2 (x*y=k): аналітична формула:
amountOut = (amountIn * 997 * reserveOut) / (reserveIn * 1000 + amountIn * 997)
Дані резервів через getReserves() — один RPC виклик на пул.
Uniswap v3 (зосереджена ліквідність): немає аналітичної формули для довільних сум. Потрібно моделювати тик-за-тиком. QuoterV2.quoteExactInputSingle робить це on-chain, але це RPC виклик з моделюванням газу. Для швидкої маршрутизації — використовувати off-chain реалізацію tick math (@uniswap/v3-sdk) з кешованими даними тиків з subgraph.
Curve: get_dy(i, j, dx) — view функція, статичний виклик. Для кожного Curve пулу потрібен окремий RPC виклик, але вони батчуються через Multicall3.
Застарілість даних та рішення
Дані резервів та тиків застарівають з кожним блоком. Під час волатильних ринків ціна може значно змінитися за 1-2 блоки. Стратегії оновлення:
-
Підписка на події:
Sync(Uniswap v2),Swap(Uniswap v3/Curve) через WebSocket. Оновлювати кеш для конкретного пулу на кожну подію - Періодичний polling: кожні 5-10 секунд для менш ліквідних пулів
- On-demand оновлення: при запиті котування — оновити дані для топ-10 пулів маршруту через Multicall
Наш підхід: WebSocket події для топ-100 пулів за TVL, polling кожні 15 секунд для інших.
Архітектура агрегатора
On-chain vs Off-chain маршрутизація
Повністю off-chain: routing engine розраховує маршрут, повертає готовий calldata для swap router. Smart contract — просто executor, без логіки вибору шляху. Це підхід 1inch v5 Aggregation Router. Мінімальний on-chain газ, але довіра до backend.
Гібридний: маршрутизація off-chain, on-chain верифікація мінімального виходу. Контракт отримує path + amountOutMinimum, виконує через Uniswap/Curve routers, перевіряє require(amountOut >= amountOutMinimum). Revert при невідповідності. Це наш рекомендований підхід.
Контракт Aggregator Router
contract AggregatorRouter {
function swap(
SwapParams calldata params
) external payable returns (uint256 amountOut) {
// Для кожного кроку маршруту
for (uint i = 0; i < params.steps.length; i++) {
amountOut = _executeStep(params.steps[i], amountOut);
}
require(amountOut >= params.minAmountOut, "Insufficient output");
// Трансфер вихідних токенів до отримувача
IERC20(params.tokenOut).safeTransfer(params.recipient, amountOut);
}
}
SwapStep містить: protocol (uniswap_v2/v3/curve/balancer), poolAddress, tokenIn, tokenOut, portion (для split routing — яка частка йде через цей крок).
Комісія агрегатора
Агрегатори беруть комісії двома способами:
- Spread: показувати користувачу котування трохи гірше від реального, залишати різницю. Непрозоро.
- Явна комісія: брати N bps (basis points) від виходу. Прозоро, краще для репутації.
Зазвичай: 5-30 bps (0.05-0.30%) залежно від розміру свопу. Реалізується в контракті як feeAmount = amountOut * feeBps / 10000.
Мультичейн та бридж
Розширення агрегатора на cross-chain своп: користувач відправляє USDC на Ethereum, отримує MATIC на Polygon. Під капотом: своп USDC→bridgeToken на Ethereum, мост через Across/Stargate, своп bridgeToken→MATIC на Polygon.
Інтеграція з Across Protocol v3: SpokePool.deposit() з destination calldata для остаточного свопу. Latency мосту: 1-5 хвилин. Газ: значно вищий за одиничний своп, доцільний від $1000+ суми.
Стек розроблення
Backend routing engine: TypeScript, viem для RPC викликів, Redis для кешування даних пулів, WebSocket для підписки на eventi. Smart contracts: Solidity 0.8.x + Foundry. Frontend: React + wagmi + імпорт токенів через стандарт Uniswap Token Lists.
Для даних subgraph (TVL, volume, тики Uniswap v3): The Graph hosted service або власний subgraph на Graph Node.
Процес роботи
Routing engine (1-2 тижні). Граф пулів, алгоритм пошуку маршруту, моделювання виходів, кешування.
Smart contract (1 тиждень). Aggregator router + тести на mainnet fork.
API та frontend (1-2 тижні). Quote API, swap UI з візуалізацією маршруту.
Тестування. Порівняння котувань з 1inch/Paraswap як еталоном.
Орієнтири по строкам
Агрегатор для 2-3 DEX в одному ланцюзі: 2-3 тижні. Мультичейн агрегатор з cross-chain свопом та власним subgraph: 2-3 місяці.







