Розробка хуків Uniswap v4
Uniswap v4 перевертає архітектуру DEX: замість тисяч окремих пул-контрактів — один singleton PoolManager та нескінченно розширювана логіка через хуки. Це не просто refactor — це платформа, де кастомний хук може реалізувати динамічні комісії, вбудований TWAP-oracle, автоматичний rebalancing або permissioned систему, не форкуючи ядро протоколу. Ми розробляємо production-ready хуки з повним покриттям тестами та готовою до аудиту документацією.
Архітектура хуків: що важливо розуміти до першої строки коду
Адреса хука як конфігурація
У v4 адреса хука — це його конфігурація. Останні 14 бітів адреси кодують, які callback-функції реалізує хук: beforeSwap, afterSwap, beforeAddLiquidity, afterAddLiquidity та інші — всього 14 флагів. PoolManager при реєстрації пула читає адресу хука і знає, які callback викликати, без додаткових on-chain запитів.
Наслідок: не можна просто задеплоїти контракт і отримати потрібну адресу. Потрібен mining — перебір salt в CREATE2, поки адреса не матиме правильні біти. Foundry це автоматизує:
bytes32 salt = HookMiner.find(deployer, flags, creationCode, constructorArgs);
При неправильних флагах PoolManager.initialize робить revert з HookAddressNotValid. Це перше, на чому спотикаються при переході з v3.
BeforeSwap та AfterSwap: асиметрія контролю
beforeSwap може повернути (bytes4 selector, BeforeSwapDelta delta, uint24 lpFeeOverride). Через delta хук може змінити кількість токенів, які беруть участь в свапі — по суті перехопити частину потоку. Через lpFeeOverride — встановити динамічну комісію в конкретному хопі замість статичної, заданої при ініціалізації пулу.
afterSwap отримує BalanceDelta — результат свапу — і може додати власну логіку поверху. Типовий кейс: rebate хук, який повертає частину fee активним LP у вигляді токенів.
Важливий нюанс: хуки працюють в контексті транзакції PoolManager. Усі операції з токенами йдуть через flash accounting — реальні ERC-20 трансфери відбуваються тільки в кінці через settle/take. Якщо хук пробує зробити прямий transfer усередину callback — це ламає flash accounting і викликає revert або, гірше, некоректний стан балансу.
Reentrancy у v4: нові правила
PoolManager захищений Lock модифікатором — тільки один lock-виклик активний одночасно. Хук, який пробує викликати PoolManager.swap усередину beforeSwap, отримає revert. Це означає, що архітектури, де хук повинен ініціювати вторинний свап (наприклад, автоматичний rebalancing), потребують відкладеного виконання — через чергу у зовнішньому контракті або через afterSwap з наступним окремим викликом.
Як ми розробляємо хуки
Типові кейси з практики
Динамічні комісії на основі волатильності. Хук читає TWAP із власного акумулятора (оновлюється в afterSwap), обчислює σ за останні N блоків, маппить σ на fee tier: низька волатильність → 0.01%, висока → 1%. lpFeeOverride повертається в beforeSwap. LP автоматично отримують захист при різких рухах ринку без ручного втручання.
Whitelist хук для permissioned пулу. В beforeSwap та beforeAddLiquidity перевіряємо merkleProof або ERC-721 balance свипера. Адреси без доступу отримують revert. Використовується для інституціональних пулів з KYC-обмеженнями.
LVR mitigation через аукціон. Before-swap хук реалізує commit-reveal схему: MEV-боти повинні зробити ставку за право першого свапу в блоці. Виручка від аукціону йде в LP. Зменшує Loss-Versus-Rebalancing для пасивних провайдерів ліквідності.
Стек та інструменти
Розробка — Foundry з v4-template від Uniswap. Тести — fork на Ethereum Sepolia (v4 вже задеплоєн на тестнеті). HookTest базовий контракт надає deployFreshManagerAndRouters — не потрібно настроювати mock PoolManager вручну.
Для mining адреси хука — HookMiner з v4-periphery. У CI це крок перед тестами: майнимо salt, передаємо в deployment script.
Верифікація правильності флагів — окремий тест:
assertEq(uint160(address(hook)) & HookFlags.ALL_FLAGS, expectedFlags);
Упавший тест одразу показує, що адреса смайнена неправильно.
Аудит-специфіка хуків
Стандартні Slither детектори не знають про v4 callback-контракт. Пишемо кастомні детектори під конкретні паттерни:
- прямий ERC-20 transfer усередину callback (порушення flash accounting)
- читання
slot0напрямки замість через PoolManager (застарілий паттерн з v3) - відсутність перевірки
msg.sender == address(poolManager)в callback-функціях
Останній пункт критичний: якщо хук не перевіряє, хто викликає beforeSwap, будь-хто може викликати його напрямки з довільними параметрами. Залежно від логіки це може привести до маніпуляції станом хука без реального свапу.
Процес роботи
Аналітика (2-3 дні). Формалізуємо логіку хука: які callback потрібні, чи є власне storage, потрібен ли доступ до oracle. Перевіряємо сумісність з існуючою архітектурою пулу.
Проектування (2-3 дні). Схема взаємодії хука з PoolManager, визначення storage layout (мінімізуємо SLOAD в гарячих шляхах), інтерфейс для конфігурування хука owner-ом.
Розробка (1-2 тижні). Реалізація callback-функцій, тести на fork Sepolia, fuzz-тести на граничні значення вхідних параметрів.
Аудит. Кастомні Slither детектори + ручний review всіх шляхів, де хук змінює BeforeSwapDelta. Документація інваріантів для зовнішнього аудитора.
Деплой. HookMiner у CI, deployment script через Foundry з верифікацією флагів. Моніторинг через подійниковий лог PoolManager перші 72 години після деплоєму.
Орієнтири по срокам
Простий хук (single callback, тільки читання) — 4-6 днів. Хук з динамічними комісіями та власним оракулом — 1-2 тижні. Комплексний хук з аукціонною механікою або власною системою учіту LP-позицій — 3-4 тижні.
Вартість розраховується після аналізу технічного завдання.







