Розробка системи автоматичного ребалансування LP Uniswap v3
Концентрована ліквідність у Uniswap v3 має подвійну природу. LP-провайдер з вузьким діапазоном збирає в 10-50 разів більше комісій, ніж v2. Але як тільки ціна виходить за діапазон — позиція стає 100% в одному активі та перестає заробляти. ETH/USDC позиція з діапазоном $1800-$2200 при ціні ETH $2500 — це чистий USDC мішок, ноль комісій. Без автоматичного управління провайдер втрачає дохід на кожному крупному русі.
Завдання системи автоматичного ребалансування: відслідковувати позиції, визначати момент выходу ціни за діапазон, збирати комісії, закривати позицію, відкривати нову навколо поточної ціни — атомарно або через keeper.
Механіка позиції Uniswap v3
NFT-позиції та NonfungiblePositionManager
Кожна LP-позиція в v3 — це ERC-721 токен, керований NonfungiblePositionManager (адреса 0xC36442b4a4522E871399CD717aBDD847Ab11FE88 на mainnet). Основні операції:
-
mint()— відкриття позиції в заданому діапазоні[tickLower, tickUpper] -
increaseLiquidity()— додавання ліквідності в існуючу позицію -
decreaseLiquidity()— частковий або повний вивід ліквідності -
collect()— збір накопичених fee токенів
Для автоматичного ребалансування контракт-менеджер повинен володіти NFT-позиціями (або мати approval) — це дозволяє йому викликати всі операції атомарно.
Tick математика та діапазони
Ціна в v3 зберігається в sqrtPriceX96 — квадратний корінь ціни у Q64.96 fixed-point форматі. Для розрахунку поточного тику: tick = floor(log(price) / log(1.0001)). Кожен тик відповідає шагу ціни в 0,01%.
Діапазон позиції задається в тиках та повинен бути кратен tickSpacing пулу. Для пулу 0,05% fee — tickSpacing 10, для 0,3% — 60, для 1% — 200. Позиція з шириною 200 тиків навколо поточної ціни покриває приблизно ±1% руху.
Стратегії ребалансування
Пасивне ребалансування (після выходу за межі діапазону)
Найпростіша стратегія: чекаємо поки ціна вийде за діапазон, збираємо комісії, закриваємо позицію, відкриваємо нову з центром на поточній ціні. Мінус: impermanent loss зафіксований, позиція була out-of-range частину часу.
Активне ребалансування (перед выходом за межі діапазону)
Ребалансуємо коли ціна наближається до краю діапазону — наприклад, коли залишилось 20% ширини до границі. Це дозволяє залишатися in-range та продовжувати заробляти комісії. Мінус: часті ребалансування на нестійкому ринку — високі газ витрати та втрати на свопах.
Асиметричні діапазони
Замість симетричного діапазону [price * 0.9, price * 1.1] — асиметричний з врахуванням тренду. На бичачому ринку для ETH/USDC: [price * 0.95, price * 1.20] — більший діапазон вгору. Параметри тренду беремо з EMA off-chain та передаємо в keeper як performData.
Реінвестиція комісій
Зібрані комісії автоматично реінвестуються в ту ж позицію (compound). Це вимагає попереднього свопу fee-токенів у правильне соотношення для поточного діапазону — off-chain розрахунок соотношення через Uniswap SDK, on-chain виконання через exactInputSingle.
Архітектура контракту
AutoLPManager
├── positionsByUser: mapping(address => uint256[]) — tokenIds
├── strategyByToken: mapping(uint256 => RebalanceStrategy)
├── rebalance(uint256 tokenId, RangeParams calldata newRange) — виклик keeper
├── collect(uint256 tokenId) — збір комісій
└── compound(uint256 tokenId) — реінвестиція комісій
Ключова проблема: своп перед відкриттям позиції. Для відкриття позиції в діапазоні [tickLower, tickUpper] потрібно точне соотношення token0/token1. Якщо після закриття позиції у вас 100% USDC (ціна зросла), а для нової позиції потрібно 50/50 ETH/USDC — потрібен попередній своп. Своп змінює соотношення, що може зсунути тик, що змінює потрібне соотношення... ітераційний розрахунок off-chain, та тільки потім on-chain виконання.
Альтернатива: використовувати готові vault-рішення як основу. Arrakis Finance v2 та Gamma Strategies — open source vault контракти із саме такою логікою. Форкнути та кастомізувати під потрібну стратегію швидше, ніж писати з нуля.
Моніторинг та keeper
Off-chain сервіс (Node.js + viem) стежить за:
- Поточним тиком пулу:
slot0()→sqrtPriceX96→ конвертація в тик - Тиками позиції:
positions(tokenId)→tickLower,tickUpper - Накопичениями комісіями: симуляція
collect()черезeth_call
При срабатыванні умови ребалансування — виклик через Chainlink Automation або собственний keeper EOA з достатньою gas буферністю.
Оцінки газу на mainnet:
| Операція | Gas |
|---|---|
| collect() комісії | ~90k |
| decreaseLiquidity() 100% | ~120k |
| Своп token0 → token1 (v3) | ~150k |
| mint() нова позиція | ~180k |
| Итого полний ребаланс |
На L2 (Arbitrum, Base) ті ж операції коштують в 20-50 разів дешевше, що робить часті ребалансування економічно осмисленими.
Процес розробки
Аналітика стратегії (2-3 дні). Backtesting обраної стратегії на історичних даних Uniswap v3. Для ETH/USDC 0,05% пулу — дані доступні через The Graph, Dune Analytics.
Контракти (1-2 тижні). AutoLPManager + keeper-сумісні інтерфейси. Foundry fork-тесты на mainnet: симулюємо кілька ребалансувань через крупні ценові руху.
Off-chain компоненти (4-5 днів). Моніторинг позицій, розрахунок оптимального ratio для свопу перед mint, Chainlink Automation setup.
Тестування (3-5 днів). Порівняння APY при різних параметрах стратегії на історичних даних.
Оцінки за часом
Базова система з однією стратегією на один пул — 1-2 тижні. Multi-pool, multi-strategy vault з governance — 3-4 тижні.
Вартість розраховується після вибору цільових пулів та стратегій ребалансування.







