Інтеграція бота з Uniswap SDK
Uniswap SDK існує в двох несумісних поколіннях: v2 SDK (застарілий, але ще живий в екосистемі) та v3 SDK (поточний стандарт з підтримкою Uniswap v3 та v4 через розширення). Більшість проблем з інтеграцією починаються саме тут — коли розробник змішує концепції або використовує застарілий код з туторіалів трьохрічної давності.
Ключова різниця між v2 та v3 SDK
У v2 SDK пул — це просто Pair з двома токенами та reserve0/reserve1. Ціна розраховується тривіально. У v3 SDK пул — це Pool з sqrtPriceX96, liquidity та tickCurrent. Ціна представлена в Q64.96 fixed-point форматі. Розрахунок output amount вимагає ітерації по tick-масиву з урахуванням concentrated liquidity в кожному діапазоні.
Це означає, що для точного розрахунку amountOut для великого свопу в v3 потрібно емулювати весь tick traversal — саме це робить @uniswap/v3-sdk через SwapMath та TickMath утиліти.
Отримання актуального стану пулу
Типова помилка: брати sqrtPriceX96 та liquidity з одного eth_call, а ticks з іншого. Між вивізитами пул може змінити стан. Для торгового бота це приводить до розрахунку неправильного amountOut та ревертів на-чейні.
Правильний підхід — Multicall: отримувати slot0, liquidity та потрібні ticks в одній атомарній транзакції через IMulticall.
import { Pool, Route, Trade, SwapQuoter } from '@uniswap/v3-sdk'
import { Token, CurrencyAmount, TradeType, Percent } from '@uniswap/sdk-core'
import { ethers } from 'ethers'
const poolContract = new ethers.Contract(poolAddress, IUniswapV3PoolABI, provider)
// Атомарний multicall для стану пулу
const [slot0, liquidity] = await Promise.all([
poolContract.slot0(),
poolContract.liquidity()
])
const pool = new Pool(
tokenA,
tokenB,
fee,
slot0.sqrtPriceX96.toString(),
liquidity.toString(),
slot0.tick
)
Для мультихоп маршрутів потрібен окремий крок — маршрутизація. SDK надає AlphaRouter з пакета @uniswap/smart-order-router, який перебирає всі можливі шляхи через відомі пули та знаходить оптимальний split.
AlphaRouter vs ручна маршрутизація
AlphaRouter — зручно для UI, але для торгового бота часто надмірно та повільно. Він робить десятки RPC-вивізитів для оцінки маршрутів. Для бота з жорсткими latency вимогами краще або кешувати маршрути заздалегідь, або реалізувати власний lightweight router тільки для потрібних пар.
На практиці ми робимо так: pre-computed route кеш для топ-10 торговельних пар (оновлюється кожні 30 секунд), при запиті свопу — прямий розрахунок за кешованим маршрутом без вивізиту AlphaRouter.
Permit2 та approvals
З версії Uniswap Universal Router перехід з безмежних approve на Permit2 (EIP-2612 розширення) — стандарт. Permit2 — це окремий контракт, який діє як єдиний менеджер allowances. Користувач один раз одобрює Permit2 для токена, а далі всі протоколи запитують transferFrom через Permit2 з signature.
Для бота це змінює схему роботи: замість прямого token.approve(router, amount) потрібно підписувати PermitSingle структуру через EIP-712 та передавати підпис у swap транзакцію. SDK надає AllowanceTransfer.getPermitData() для генерації даних підпису.
Slippage та deadline
const slippageTolerance = new Percent(50, 10_000) // 0.5%
const deadline = Math.floor(Date.now() / 1000) + 60 * 20 // 20 хвилин
const { calldata, value } = SwapRouter.swapCallParameters(trade, {
slippageTolerance,
deadline: deadline.toString(),
recipient: walletAddress
})
Для арбітражних ботів slippage tolerance повинен бути мінімальним (0.1% та нижче) — інакше атакуючий може вставити sandwich у момент виконання арбітража. Deadline — короткий (1–2 хвилини): якщо ціна сдвинулась настільки, що транзакція не включалась 2 хвилини, умови арбітража скоріше за все вже застарілі.
Gas оптимізація в боті
callStatic перед відправкою: перед відправкою swap транзакції виконуємо provider.call() з тими ж даними. Якщо ревертується — не тратимо gas на реверт у блоці.
Gas estimation: estimateGas() повертає приблизний gas limit. Додаємо 10–20% buffer. Занадто малий limit → реверт через out of gas; занадто великий → неоптимальний tip для builders.
Priority fee: для арбітражних ботів важливо потрапити в блок вовремя. Динамічно розраховуємо maxPriorityFeePerGas на основі останніх блоків через eth_maxPriorityFeePerGas або Flashbots eth_gasFees.
Інтеграція з Uniswap v4 Hooks
Uniswap v4 (mainnet 2025) вводить архітектуру Hooks — довільна логіка, виконувана до/після свопу та додавання ліквідності. Для ботів важливо: хук може змінити effective amount out або заблокувати своп при певних умовах (наприклад, якщо пул захищений від MEV через хук динамічної комісії).
SDK v4 (в розробці) надає V4Router з підтримкою нового формату PoolKey. При роботі з v4 пулами потрібно передавати hookData — дані для хука. Без цього своп може ревертуватися.
Стек та рекомендовані залежності
| Пакет | Версія | Призначення |
|---|---|---|
@uniswap/v3-sdk |
^3.x | Розрахунки V3 пулів |
@uniswap/sdk-core |
^5.x | Token, CurrencyAmount |
@uniswap/smart-order-router |
^3.x | AlphaRouter |
viem |
^2.x | RPC, типобезопасність |
ethers |
^6.x | Підписання, відправка |
Переважаємо viem для read-only операцій (швидше, кращий TypeScript inference) та ethers.js для підписання транзакцій — більш зріла екосистема для wallet management.
Процес розробки
Аналітика (1 день). Визначаємо цільові пари, тип бота (арбітраж, MM, реалізація стратегії), вимоги до latency.
Розробка (3–5 днів). Інтеграція SDK, маршрутизатор, gas management, backtest на історичних даних через Foundry fork.
Тестування та деплой. Тест на Sepolia testnet, потім mainnet з обмеженими сумами.







