Интеграция бота с 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 с ограниченными суммами.







