Хук и антиснайп
Хук Uniswap v4 — это контракт, который PoolManager вызывает в определённые моменты свопа.
Текущая имплементация StockFunHook использует шесть разрешений: beforeInitialize,
beforeAddLiquidity, beforeSwap, afterSwap и два разрешения на дельты, которые
позволяют ему забирать свою долю. С 2026-10-02 его адрес несёт все 14 разрешений v4;
колбэки, которые он не использует, просто пропускаются.
Адрес кодирует разрешения
v4 читает младшие биты адреса хука, чтобы понять, когда его вызывать. Поэтому адрес не выбирается: он майнится через CREATE2, пока не найдётся значение, биты которого совпадают с заявленными разрешениями.
С 2026-10-02 майнится адрес прокси, со всеми 14 выставленными битами разрешений. Апгрейд заменяет имплементацию за этим адресом, не меняя его, поэтому заново майнить его никогда не нужно, а будущая имплементация может использовать любой колбэк. Текущая пропускает колбэки, которые не использует: они возвращают свой селектор и, там, где ожидается дельта, ноль. Инициализация прокси проверяет, что его адрес несёт каждый бит.
Практическое следствие: намайненный адрес зависит от байт-кода прокси и аргументов его
конструктора, которые содержат адрес имплементации. Новый деплой придётся майнить заново.
По этой же причине foundry.toml задаёт bytecode_hash = "none" — без этого намайненный
адрес больше не совпадает с задеплоенным контрактом.
Разрешение beforeAddLiquidity, добавленное 2026-10-01, изменило сами биты: адрес был
намайнен заново, и любой деплой, сделанный до этой даты, устарел. Прокси от 2026-10-02
снова их изменил: любой деплой, сделанный до этой даты, тоже устарел.
Взимание комиссии
При покупке комиссия взимается в beforeSwap из входящего ETH, до того как произойдёт
своп. Хук забирает свою долю из PoolManager и возвращает дельту, которая списывает её с
покупателя. Роутер StockFun и лок ликвидности вносят ETH покупателя в PoolManager до
свопа, поэтому их покупки никогда не задействуют ETH, который PoolManager уже держит.
Любой другой роутер v4 платит налог по той же ставке. Но у роутера, который вносит ETH
покупателя после свопа, как это делает V4Router из v4-periphery с кодированием по
умолчанию, налог берётся из ETH, который PoolManager уже держит, и его покупка не
проходит, если налог больше этой суммы. Это может случиться, когда у PoolManager мало
ETH, например в тестнете. Интегратору следует вносить ETH покупателя до свопа, как это
делает официальный роутер. Продажи это не затрагивает. Это ограничение задокументировал
пайплайн безопасности от 2026-10-01. Если вместо этого взимать налог в виде claims
PoolManager, ограничение снялось бы для любого роутера, но 2 % казны перешли бы из
выплачиваемых во время сделки в начисляемые и выплачиваемые позже: 2026-10-05 владелец
решил оставить налог таким, каким он взимается сегодня.
При продаже она взимается в afterSwap из исходящего ETH, когда сумма уже известна.
В обоих случаях хук сразу делит комиссию: казна, создатель, команда, байбэк. Во время сделки уходит только строка казны, которая отправляется в волт рынка. Остальные три строки начисляются на хуке и выплачиваются вне сделок.
С 2026-10-05 волт, который не принимает строку казны, больше не срывает сделку: хук
сохраняет сумму как долг перед этим волтом (treasuryOwed, событие TreasuryOwed), и все
покупки и продажи продолжаются. Любой выплачивает этот долг волту через payTreasury,
который не проходит и сохраняет долг, пока волт по-прежнему не принимает средства; кипер
пытается в каждом цикле. Излишек антиснайпа подчиняется тому же правилу. До этого отправка
падала с ошибкой: волт, который не мог принять средства, например после неудачного
апгрейда, срывал каждую сделку на своём рынке, включая продажи.
Доля создателя работает по pull-модели: она накапливается на хуке, рынок за рынком, и
создатель клеймит её, когда захочет, одной транзакцией на каждый рынок (claimCreatorFees).
С 2026-10-05 создатель, который сам не может принять ETH, — контракт без способа его
получить, — клеймит на другой адрес (claimCreatorFeesTo); это может сделать только
создатель.
С 2026-10-01 доли команды и байбэка начисляются так же, по одному балансу на каждую, и
выплачиваются через claimTeamFees() и claimBuybackFees(). Вызвать их может любой; они
платят только кошелькам команды и байбэка, которые фабрика указывает на момент клейма.
BuybackBurner сам забирает свой баланс в начале каждого сжигания. Кошелёк, который
отказывается принимать ETH, лишь задерживает собственную выплату: его клейм не проходит, и
баланс остаётся на хуке.
До этого эти две доли отправлялись во время сделки, с запасным вариантом через эскроу, если
отправка не проходила. Аудит безопасности от 2026-09-29 показал, что кошелёк, который
принимал отправку, а затем вызывал PoolManager, мог остановить торговлю во всех пулах.
Эскроу больше нет.
То, что хук держит между сделками, кому-то причитается: балансы создателей, балансы
команды и байбэка и долги перед волтами. ETH, отправленный ему кем-либо, кроме
PoolManager, учитывается отдельно, как случайные поступления (strayEth). С 2026-10-05
владелец StockFun может выводить случайные поступления (rescue): не больше этой суммы
ETH, и любой токен, поскольку хук никогда не держит токенов. Ничто из того, что хук должен,
не может уйти этим путём. ETH, зачисленный принудительно, без вызова, не учитывается и ждёт
апгрейда.
Ликвидность добавляет только лок
С 2026-10-01 beforeAddLiquidity отклоняет любое добавление ликвидности в пул StockFun,
кроме добавления от лока ликвидности.
Позиция, размещённая вплотную к текущей цене, работает как лимитный ордер: своп трейдера пересекает её и конвертирует, и налог платит трейдер, тогда как владелец позиции добавляет и изымает её, так и не заплатив ни 5 %, ни, в первые десять блоков, антиснайп-налога. Аудит безопасности от 2026-09-29 это воспроизвёл. Пулы по умолчанию не взимают LP-комиссию, поэтому ни одному легитимному сценарию сторонняя позиция не нужна.
Собственные сборы комиссий лока, с дельтой ликвидности, равной нулю, проходят через путь изъятия ликвидности, который текущая имплементация пропускает: их это не затрагивает. Не затрагивает это и вывод ликвидности в режиме завершения, который забирает позиции через тот же путь: см. Запуск с двумя позициями.
Убывающий антиснайп
Пул v4 начинает работать в момент инициализации. Без защиты первые блоки после создания забрали бы боты. С 2026-09-28 в этих блоках действует повышенный налог, который снижается с каждым блоком, одинаково на покупках и продажах. С настройками по умолчанию:
| Блок с момента запуска | Налог |
|---|---|
| 1 | 80 % |
| С 2 по 10 | 72, 64, 56, 48, 40, 32, 24, 16, 8 % |
| 11+ | Обычный режим, 5 % |
Бот, который покупает в открывающем блоке, сразу платит 80 %: снайпинг убыточен.
Три момента заслуживают пояснения.
Покупке создателя при запуске не нужна идентификация. Единственный своп, который
когда-либо выполняет LiquidityLock, — необязательная покупка создателя внутри его
собственного колбэка создания. Поэтому «вызывающий — это лок» означает «мы внутри
транзакции создания», и эта покупка платит обычные 5 %.
У излишка своё назначение. Обычные 5 % сохраняют привычную разбивку. Часть сверх них
идёт в казну рынка, а значит, холдерам при следующем аирдропе. На рынке $STOCKFUN она
идёт на баланс команды на хуке, который выплачивается через claimTeamFees().
А вот вайтлисту идентификация нужна, и в этом вся тонкость. Хук видит роутер, а не
покупателя. Поэтому роутер StockFun передаёт адрес вызывающего в данных хука, и хук доверяет
этому полю, только если вызывающий — официальный роутер, то есть тот, что записан в
фабрике и который владелец может сменить в любой момент (принято 2026-09-28). tx.origin
нигде в этом протоколе не используется.
Задокументированное ограничение: адрес из вайтлиста, который в первые десять блоков идёт через сторонний агрегатор, не получает исключения.
Вайтлист
Задаётся создателем рынка. Адреса из него в течение блоков антиснайпа платят обычные 5 %. До 2026-09-28 список вёл владелец, и он был общим для всех рынков — именно для того, чтобы он не мог стать инсайдерским преимуществом; теперь создатель может освободить от антиснайп-налога собственные кошельки. Утверждено 2026-09-28: список фиксируется в транзакции создания, публичен, неизменяем и по умолчанию ограничен 20 адресами.
Рынок $STOCKFUN
Убывающий налог действует и здесь. У $STOCKFUN нет внешнего создателя: его излишек идёт в
комиссии команды, доступные для клейма, а его вайтлист задаёт владелец при запуске.
Настройки
С 2026-10-05 каждое число на этой странице — настройка владельца StockFun, которая
меняется на хуке через setTaxSettings: налог, по умолчанию 5 %; его строки, 2 / 2 / 0,5
на запущенном рынке и 2 / 2,5 на $STOCKFUN, причём байбэк получает остаток; налог
антиснайпа в открывающем блоке, 80 %; его снижение за блок, 8 пунктов; число блоков, в
течение которых он действует, включая блок создания, 10; и наибольший вайтлист,
20 адресов.
Изменение применяется со следующего свопа, в каждом пуле, включая пул, который ещё находится в блоках антиснайпа: убывание рассчитывается по действующим настройкам, от блока запуска пула. При любых настройках антиснайп никогда не берёт меньше налога. Сеттер отклоняет ставку выше 100 % и схему, строки которой превышают налог. Лимит вайтлиста проверяется при создании рынка: уже заданный список остаётся как есть.
Апгрейды
С 2026-10-02 владелец StockFun может апгрейдить хук с немедленным вступлением в силу.
Налог, его разбивка, антиснайп и вайтлисты, описанные на этой странице, относятся к
текущей имплементации. Апгрейд сохраняет адрес хука и должен сохранить тот же
PoolManager; фабрика, которую хук читает и которая решает, кто может его апгрейдить,
зафиксирована в имплементации.