Разработка системы управления concentrated liquidity
Uniswap V3 запустился в мае 2021 с идеей, которая казалась очевидной только после объяснения: зачем размазывать ликвидность по всему ценовому диапазону от 0 до бесконечности, если реальная торговля происходит в диапазоне ±10–20% от текущей цены? Concentrated liquidity позволяет LP выбрать диапазон [tickLower, tickUpper] и обеспечить в нём в 100–1000x больше глубины при том же капитале.
Проблема: позиция зарабатывает fee только пока цена в диапазоне. Как только цена выходит за границы — LP полностью конвертируется в один актив и перестаёт приносить доход. Управление такими позициями вручную — занятие для ботов, не для людей.
Почему пассивная позиция в V3 убыточна на волатильных парах
Классический backtesting по данным Uniswap V3 (2021–2024) показывает неприятную картину: LP в широком диапазоне на ETH/USDC зарабатывает на fee меньше, чем теряет на impermanent loss при типичной волатильности ETH. Hold обоих активов outperforms пассивного LP.
Почему? При движении цены на 20% от центра диапазона позиция начинает испытывать accelerated IL — эффект усиленного impermanent loss по сравнению с V2. Тот же капитал, сконцентрированный в 5x узкий диапазон, зарабатывает в 5x больше fee, но гораздо чаще оказывается out-of-range.
Единственный способ выйти в плюс — активное управление: перемещать диапазон следом за ценой, балансируя между fee APR и газовыми затратами на ребалансировку. Это и есть задача системы управления.
Архитектура системы: три компонента
1. On-chain Vault контракт
Vault — это смарт-контракт, который владеет NFT позициями Uniswap V3 (ERC-721) от имени пользователей. Пользователи депонируют tokenA и tokenB, получают shares vault-а. Vault самостоятельно управляет позицией.
interface IConcentratedLiquidityVault {
function deposit(uint256 amount0, uint256 amount1, address recipient)
external returns (uint256 shares);
function withdraw(uint256 shares, address recipient)
external returns (uint256 amount0, uint256 amount1);
function rebalance(
int24 newTickLower,
int24 newTickUpper,
uint256 swapAmount,
bool zeroForOne
) external;
function collectFees() external returns (uint256 fees0, uint256 fees1);
}
Ключевое: функция rebalance вызывается внешним keeper-ботом. Она:
- Удаляет всю ликвидность из текущей позиции (
decreaseLiquidity+collectчерез NonfungiblePositionManager) - Опционально свапает часть активов для балансировки в нужное соотношение
- Создаёт новую позицию в новом диапазоне (
mint)
Авторизация на вызов rebalance — через whitelist keeper адресов с Gnosis Safe мультисиг для управления списком.
2. Off-chain стратегический движок
Это Node.js (или Python) сервис, который непрерывно мониторит состояние позиции и принимает решения о ребалансировке.
Входные данные:
- Текущая цена (из Uniswap V3 pool
slot0.sqrtPriceX96) - Текущий диапазон позиции (
tickLower,tickUpper) - Накопленные fees (ещё не собраны)
- Isторические данные по волатильности (для расчёта оптимальной ширины диапазона)
Стратегии ребалансировки:
Пороговая стратегия — ребалансировка когда цена отклонилась от центра диапазона на X%. Просто, предсказуемо, но не учитывает volatility regime.
Volatility-based стратегия — ширина диапазона = N * σ (стандартное отклонение цены за последние K дней). При высокой волатильности диапазон шире (меньше ребалансировок, больше IL protection), при низкой — уже (больше fee). N обычно от 1.5 до 3 стандартных отклонений.
Backtesting по историческим данным обязателен перед деплоем. Берём исторические цены из The Graph или Uniswap V3 subgraph, симулируем стратегию, считаем:
- Суммарные fee за период
- Суммарный IL
- Gas costs на ребалансировки
- Net P&L vs hold
interface RebalanceSignal {
shouldRebalance: boolean
newTickLower: number
newTickUpper: number
swapAmount: bigint
zeroForOne: boolean
reason: 'out_of_range' | 'drift' | 'volatility_change'
}
function evaluateRebalance(
currentTick: number,
tickLower: number,
tickUpper: number,
volatility30d: number
): RebalanceSignal {
const rangeWidth = tickUpper - tickLower
const center = (tickLower + tickUpper) / 2
const drift = Math.abs(currentTick - center) / (rangeWidth / 2)
// Ребалансировка если цена ушла за 80% от центра к краю диапазона
if (drift > 0.8 || currentTick < tickLower || currentTick > tickUpper) {
const optimalRange = Math.round(volatility30d * 2 * 10000) // ticks
return {
shouldRebalance: true,
newTickLower: Math.round(currentTick - optimalRange / 2),
newTickUpper: Math.round(currentTick + optimalRange / 2),
// ... swap calculation
}
}
return { shouldRebalance: false, ... }
}
3. Keeper инфраструктура
Keeper — это сервис, который вызывает rebalance() на-чейне при получении сигнала от стратегического движка. Требования к keeper:
- Высокая uptime (99.9%+). Позиция out-of-range не приносит fee.
- Atomicity: ребалансировка должна завершиться или целиком откатиться. Нельзя оказаться в состоянии «ликвидность удалена, новая позиция не создана».
- MEV protection: ребалансировка включает swap, который виден в mempool. Нужно использовать Flashbots private relay чтобы не быть sandwich-атакованным.
Отправка через Flashbots:
const bundle = await flashbotsProvider.sendBundle(
[{ signer: keeperWallet, transaction: rebalanceTx }],
targetBlock,
{ minTimestamp: 0, maxTimestamp: Math.floor(Date.now() / 1000) + 30 }
)
Gas оптимизация ребалансировки
Одна ребалансировка на Ethereum mainnet стоит 300,000–500,000 gas (удаление + сбор fees + swap + новая позиция). При цене gas 20 gwei и ETH $3000 — $18–30 за операцию.
Для маленьких позиций (<$10,000) это делает ребалансировку нерентабельной при высокой частоте. Решение: поддержка L2 (Arbitrum, Optimism, Base) с Uniswap V3 deployment. На Arbitrum gas в 100x дешевле — ребалансировка стоит $0.20–0.50.
Дополнительная оптимизация: компаундинг собранных fees обратно в позицию в рамках той же ребалансировки транзакции — вместо отдельного collect + mint.
Uniswap V4 и Hooks
Uniswap V4 вводит Hooks — возможность встроить логику управления прямо в пул через hook контракт. beforeSwap и afterSwap хуки позволяют динамически изменять fee в зависимости от условий. Для системы управления ликвидностью это открывает возможность реализовать динамический fee range: более широкий диапазон с меньшей комиссией при высокой волатильности, узкий с высокой — при низкой.
Это архитектурно чище, чем off-chain keeper, но требует написания hook контракта и аудита отдельно от vault логики.
Процесс работы
Исследование стратегий (3–5 дней). Backtesting нескольких стратегий на исторических данных выбранной пары. Оценка оптимальных параметров ширины диапазона и триггеров ребалансировки.
Разработка vault контракта (2–3 недели). Solidity, Foundry тесты с fork-тестированием на реальных Uniswap V3 mainnet данных.
Off-chain движок (1–2 недели). Стратегический движок, keeper бот, мониторинг.
Фронтенд (1–2 недели). Deposit/withdraw UI, отображение текущей позиции и исторической доходности.
Аудит. Рекомендуем внешний аудит vault контракта перед привлечением значимой ликвидности.
Ориентиры по срокам
Базовый vault для одной пары с пороговой стратегией — 4–6 недель. Мультипарный vault с volatility-based стратегией, Arbitrum/Optimism поддержкой и аналитическим дашбордом — 10–14 недель.







