Автор: @Ehsan1579
Компиляция | Odaily Planet Daily (@OdailyChina); Переводчик | Ethan (@ethanzhang_web 3)

Если судить только по заголовку, можно ошибочно принять, что это была атака с использованием уязвимости.
Суть события: кто-то обменял USDT на сумму 50,4 миллиона долларов и в итоге получил AAVE на сумму всего 35,9 тысяч долларов.
Когда я впервые услышал об этом, я был потрясен. Поэтому я тщательно изучил все событие: отследил транзакцию, путь решателя (solver), вызовы контрактов, исторические резервы, данные о расчетах, процесс адаптера, код интерфейса Aave, SDK CoW Flash Loan и код маршрутизации, определяющий, является ли котировка «разумной».
Это не было взломом. Базовый протокол Aave не дал сбой. Расчеты CoW не дали сбой. Uniswap не дал сбой. SushiSwap не дал сбой. Транзакция была действительна, подписи действительны, все контракты выполнялись строго в соответствии с кодом. Тем не менее, почти вся экономическая ценность была уничтожена только потому, что ей было позволено пойти по абсурдному маршруту.
Проблема была не в блокчейне, проблема была в маршрутизации.
На мой взгляд, легкомысленно списывать это на простую «ошибку пользователя» — необъективный и нестрогий подход. Безусловно, пользователь подписал ордер, но вся программная система позволила операции по ротации залога на сумму почти 50 миллионов долларов пройти через этапы котировки, подписания, планирования маршрута и вплоть до финального исполнения, причем весь процесс вел в пул с низкой ликвидностью, содержавший всего около 331 AAVE. Это должно было быть совершенно невозможно, по крайней мере, система должна была жестко заблокировать и отказать в расчете.
Отслеживание ключевой информации о транзакции
Хэш этой аномальной транзакции: 0x9fa9feab3c1989a33424728c23e6de07a40a26a98ff7ff5139f3492ce430801f, подтверждена в блоке Ethereum № 24643151 12 марта 2026 года, индекс транзакции 1, потреблено 3780570 единиц Gas, исполнение транзакции успешно. Кошелек, которому принадлежал ордер, начинается с 0x98b9, фактический адрес решателя (отправитель транзакции) начинается с 0x3980, в данных соревнований CoW помечен как tsolver.
Важно понимать, что это был не простой обмен USDT на AAVE на уровне кошелька. Проданным токеном был aEthUSDT, т.е. депозитный сертификат USDT, приносящий проценты, на платформе Aave. Купленным токеном был aEthAAVE, т.е. депозитный сертификат AAVE, приносящий проценты, на платформе Aave. Таким образом, это фактически была ротация залога в Aave через систему расчетов протокола CoW и его процесс адаптера flash loan.
До транзакции кошелек содержал примерно 50,432,693.075254 aEthUSDT и 0 aEthAAVE. После транзакции у него осталось всего 4.980399 aEthUSDT, и он получил 327.241335505966487788 aEthAAVE. Фактически, кошелек продал почти всю свою позицию.
Метаданные еще яснее показывают, что маршрут был «токсичным» еще до исполнения. Ордер поступил из процесса aave-v3-interface-collateral-swap. API CoW отображает его как подписанный ордер на продажу, а метаданные приложения помечают его как своп залога по рыночной цене с использованием интеллектуального проскальзывания в 121 базисный пункт. Подписанная сумма продажи составляла 50,432,688.41618 aEthUSDT. Подписанная минимальная сумма покупки составляла 324.949260918413591035 aEthAAVE. Фактически при расчете было выплачено 327.241335505966487788 aEthAAVE.
Это чрезвычайно важная деталь. Этот ордер изначально не ожидал получить тысячи AAVE, которые затем каким-то образом были уничтожены по пути. Он был построен именно вокруг такого результата — около трехсот с лишним AAVE.
Полная цепочка коллапса маршрута
Как только вы проследите за транзакцией, процесс становится жестоко прямолинейным.
Основной поток средств на верхнем уровне опирается на расчетный контракт CoW Protocol GPv2Settlement (начинается с 0x9008). Сначала контракт HooksTrampoline (начинается с 0x60bf) выполняет операцию авторизации aEthUSDT, позволяя ретранслятору хранилища CoW извлекать активы пользователя без отдельной транзакции авторизации; затем контракт GPv2VaultRelayer (начинается с 0xc92e) извлекает 50432688.41618 aEthUSDT из кошелька пользователя в процесс расчета. На этом этапе все операции соответствуют нормальной логике.
Расчетный контракт затем предоставляет права на операции с aEthUSDT неоткрытому вспомогательному контракту (начинается с 0xd524) и инициирует вызов через селектор функции 0x494b3137; этот вспомогательный контракт затем передает права на выполнение неоткрытому контракту-исполнителю (начинается с 0x699c). На этом месте полностью раскрывается полная карта аномального маршрута транзакции.
Первый действительный вызов направлен на контракт пула ликвидности Aave (начинается с 0x87870), через функцию withdraw (селектор 0x69328dec) сжигает aEthUSDT, выкупая базовый нативный USDT; затем маршрут переходит в глубокий пул Uniswap V3 USDT/WETH (начинается с 0x4e68), где все 50432688.41618 USDT обмениваются на 17957.810805702142342238 WETH.
Эта стадия транзакции полностью нормальна: обменный курс составляет примерно 2808.4 USDT за 1 WETH, что соответствует рыночным условиям на тот момент, проблем с ликвидностью нет, вычислительных отклонений нет, первая ступень транзакционной цепочки не содержит никаких аномалий.
Проблема возникает на второй ступени, как только вы видите резервы ликвидности, остальная история становится неизбежной.
Исполнитель, получив 17957.810805702142342238 WETH, переводит все средства в пул SushiSwap V2 AAVE/WETH по адресу 0xd75ea151a61d06868e31f8988d28dfe5e9df57b4.
Я проверил исторические данные о резервах ликвидности этого пула непосредственно перед моментом аномальной транзакции (высота блока 24643150), в пуле находилось всего:
331.631982538108027323 AAVE, 17.653276196397688066 WETH
Это не ошибка ввода данных, а неопровержимый факт.
Этот торговый маршрут влил почти 17958 WETH в микропул, резерв WETH которого составлял всего 17.65, а общий запас AAVE — всего 331.63. Объем введенных WETH примерно в 1017 раз превышал резерв WETH в пуле.
Это не обычная проблема «высокого проскальзывания» или «несколько тонкой ликвидности», а крайне абсурдный путь исполнения рыночного ордера, эквивалентный принуждению пула AMM с постоянным продуктом крайне малого объема обработать огромную сделку, в тысячи раз превышающую его собственный размер.
Торговый пул AMM выполнил операцию в соответствии с установленным алгоритмом, практически исчерпав весь запас AAVE в пуле.
Пара SushiSwap инициировала основное событие обмена Swap: исполнитель перевел 17957.810805702142342238 WETH и получил взамен всего 331.305315608938235428 AAVE. После транзакции в пуле осталось примерно:
0.326666929169791895 AAVE, 17975.464081898540030304 WETH
Проще говоря, около 99.9% запасов AAVE в пуле были выкачаны за один шаг.
Согласно резервам до транзакции, подразумеваемая цена AAVE в пуле составляла примерно 149.50 долларов. Фактическая цена исполнения для пользователя составила около 154,114.66 USDT за 1 AAVE. Это более чем в 1000 раз отличается от спотовой цены до транзакции.
Затем эти AAVE были внесены обратно в пул ликвидности Aave с использованием селектора 0x617ba037, т.е. supply(address,uint256,address,uint16). В результате вновь созданные aEthAAVE были возвращены расчетному контракту. Расчетный контракт в конечном итоге перевел 327.241335505966487788 aEthAAVE пользователю. Примерно 4.06398010297174764 aEthAAVE остались в расчетном контракте в качестве излишка по сравнению с оплатой пользователя.
Таким образом, расчет не исказил внезапно хороший результат исполнения в плохой. Он просто зафиксировал результат, который уже был произведен маршрутом.
Это ключевой момент, который стоит четко озвучить: Катастрофический результат уже был «заложен» в маршруте до его исполнения.
Во встроенных данных вызова вспомогательного контракта в маршруте целевая сумма на стороне покупки составляла примерно 331.272185078031026739, подписанный пользователем минимальный объем покупки составлял 324.949260918413591035, фактический расчетный объем составил 327.241335505966487788. Все ключевые значения были заблокированы на уровне нескольких сотен AAVE еще до расчета.
Этот маршрут изначально был плохим.
Где была уязвимость?
Ответ: каждый уровень проверки в системе проверял не те параметры.
Все уровни проверяли только, является ли транзакция исполнимой, действительны ли подписи, ненулевые ли суммы, но почти ни на одном ключевом уровне не проверялось, является ли торговый маршрут экономически обоснованным. Это коренная причина сбоя механизма.
Дефект кода пути котировок адаптера интерфейса Aave
Первая очевидная аномалия кода появилась в процессе котировок адаптера CoW интерфейса Aave: функция, изначально предназначенная для включения специализированных данных приложения при запросе котировки, была принудительно отключена.

Источник: rates.helpers.ts:93 и adapters.helpers.ts:194
Это означает, что интерфейс Aave при запросе котировки у CoW не прикреплял метаданные flash loan и хуков, которые附加руются при фактическом размещении ордера. Другими словами, то, на что давалась котировка, не совсем то, что должно было быть исполнено. Комментарий в коде даже говорит, что цель этой вспомогательной функции — сделать котировки адаптера более точными, но затем эта функция была жестко отключена.
Логика определения разумности котировок CoW слишком слаба (ключевая уязвимость)
Вторая и самая серьезная проблема заключается в логике соревнования котировок протокола CoW: в его общедоступном коде любая котировка с положительной комиссией Gas и ненулевой выходной суммой считается «разумной котировкой».

Источник: quote.rs:31
Для маршрутизирующей системы, обрабатывающей ордера на десятки миллионов долларов, это ошеломляюще слабое определение «разумности».
Система не была подключена к оракулу для проверки здравости цены, не было механизма блокировки при «отклонении котировки от спотовой цены более чем в 500 раз», не было оценки риска «маршрут полностью исчерпает пул ликвидности», не было предупреждения о «серьезном несоответствии ликвидности на последнем шаге и размера ордера»; требовалось только, чтобы решатель возвращал исполнимый, ненулевой маршрут, и он принимался системой. Это ключевая уязвимость данного инцидента.
Дефект логики моделирования ликвидности в стиле Uniswap V2
Третья проблема заключается в способе моделирования пулов ликвидности в стиле Uniswap V2: код использовал только стандартный алгоритм постоянного продукта, отвергая только математически невозможные случаи, такие как нулевые резервы, числовое переполнение снизу (underflow) или переполнение сверху (overflow), без проверки экономической целесообразности.

Источник: pool_fetching.rs:118 и pool_fetching.rs:153
Этот код не определял, достаточно ли объема пула ликвидности для обработки соответствующей транзакции по маршруту, он проверял только, является ли операция обмена математически valid. Поэтому даже микропул с резервом всего в 331 AAVE считался valid местом для обработки запроса на покупку на 17957 WETH, только потому что алгоритм постоянного продукта мог вычислить ненулевой результат, полностью игнорируя тот факт, что этот результат приведет к катастрофической потере активов.
Вторичный сбой SDK Flash Loan и механизма проверки ордеров
Затем SDK Flash Loan напрямую внедрил эту недействительную котировку в полезную нагрузку исполнения ордера и хуков, не предприняв никаких вторичных мер по блокировке рисков.

Затем:

Источник: index.js:484 и index.js:591
Вот почему я всегда говорю, что этот маршрут был «плохим с рождения». Уровень адаптера не «обнаружил» новую плохую сумму во время исполнения. Он сериализовал уже указанную плохую сумму в данные хуков и определенные адреса экземпляров. Как только плохая котировка существовала, остальные механизмы добросовестно передавали ее дальше.
Даже логика проверки ордеров CoW не защищала пользователя здесь, потому что она проверяет только, превышает ли ордер рыночную цену на момент котировки, а не проверяет, является ли сама котировка абсурдной по сравнению с фактической ликвидностью.

Источник: order_validation.rs:694
Это проверка на соответствие. Если сама котировка уже была бессмыслицей, ордер все равно мог пройти.
Предупреждающий механизм UI-фронтенда был фиктивным
Интерфейс Aave действительно имеет предупреждение о высоком ценовом воздействии, но это не жесткий аварийный выключатель. Когда потеря стоимости превышает 20%, он превращается в флажок подтверждения.

Как только пользователь устанавливает флажок, препятствие устранено:

Источник: helpers.ts:24 и HighPriceImpactWarning.tsx:35
Таким образом, даже если эта транзакция почти полностью опустошит стоимость активов, система оценила ее только как операцию, требующую подтверждения пользователем, а не как высокорисковую транзакцию, которую система должна жестко отвергать. Предупреждающий механизм полностью утратил функцию блокировки рисков.
Основываясь на всех вышеперечисленных сбоях механизмов, я категорически не согласен с敷衍结论ом «пользователь просто глуп». Пользователь действительно подписал, но у всей программной системы было бесчисленное количество возможностей предотвратить эту катастрофу, однако на каждом уровне проводилась только базовая проверка, и после определения «ненулевой, исполнимый, подписанный» она напрямую пропускалась, что в конечном итоге привело к печальным последствиям.
Маршрут не был изменен
Этот момент крайне важен, он напрямую исключает множество ошибочных предположений: соответствующий официальный процесс интерфейса Aave, aave-v3-interface-collateral-swap, в файле useSwapOrderAmounts.ts строка 139, объединяет котировку, сетевые сборы, партнерские сборы, сборы flash loan для расчета скорректированной суммы покупки с учетом проскальзывания; строка 331 преобразует ее в значение buyAmountBigInt; затем в файле CollateralSwapActionsViaCoWAdapters.tsx строка 191 выполняется точная подпись этой суммы.
Последующий контракт адаптера в файле AaveV3BaseAdapter.sol строка 141 проверяет полное соответствие полей подписанного ордера и сохраненных значений; расчетный контракт CoW в файле GPv2Settlement.sol строка 337 принудительно применяет правила лимитов, оговоренных подписью. Следовательно, результат исполнения в блокчейне не выходил за пределы, разрешенные подписанным ордером, и пользователь фактически получил активов даже больше, чем минимальный лимит, оговоренный подписью.
Этого достаточно, чтобы доказать: катастрофа произошла до этапа расчета, а не в процессе расчета, фатальный дефект маршрута уже предопределил исход.
Куда делась стоимость?
Следующая транзакция в том же блоке (хэш начинается с 0x45388b0f) выполнила арбитраж обратного хода (backrun arbitrage) против разрушенного пула SushiSwap AAVE/WETH. После того как аномальная транзакция заполнила пул огромным количеством WETH и выкачала绝大部分 AAVE, арбитражер немедленно продал AAVE обратно в пул, собирая сверхприбыль, вызванную дисбалансом ликвидности.
Этот арбитраж обратного хода извлек примерно 17929.770158685933 WETH, затем заплатил сборщику блока (block builder) примерно 13087.73 ETH, а адресу исполнения арбитража — примерно 4824.31 ETH.
Вся потерянная экономическая стоимость пользователя почти мгновенно превратилась в прибыль от MEV-арбитража в том же блока и доход сборщика блока.
Дополнительная проверка временной последовательности на уровне блока подтверждает: до транзакции никто злонамеренно не манипулировал пулом SushiSwap, чтобы заманить пользователя в ловушку, эта пара AAVE/WETH была затронута впервые именно этой аномальной транзакцией (индекс транзакции 1); immediately следующая транзакция (индекс транзакции 2) выполнила первый обратный ход против ценового искажения, вызванного этой транзакцией; транзакция с индексом 3 также затронула эту пару в процессе рыночной коррекции. Временная шкала четко подтверждает: эта аномальная транзакция создала крайне искаженную цену, последующие транзакции напрямую собрали эту искаженную прибыль.
Так чья же вина?
Если вы спросите, дал ли сбой базовый протокол Aave V3, ответ — нет. Пул Aave выполнил инструкции exactly, нормально завершив процесс выкупа USDT и внесения AAVE.
Если вы спросите, дал ли сбой расчетный контракт CoW GPv2Settlement, ответ — нет. Расчет принудительно исполнил действительный подписанный ордер и выплатил сумму, превышающую подписанный минимум.
Если вы спросите, дали ли сбой контракты торговых пар Uniswap V3 или SushiSwap, ответ同样 — нет. Оба пула выполнили定价 транзакции в соответствии с их алгоритмическими правилами.
Решительный системный провал произошел на более высоких уровнях маршрутизации и контроля рисков:
Основная ответственность лежит на модулях маршрутизации, котировок и решателей протокола CoW: Вся система имела слишком слабые критерии определения «разумного маршрута», позволяя ордеру на десятки миллионов долларов в конечном итоге направляться в микропул с низкой ликвидностью, принимая его, пока маршрут был исполним и ненулевой, полностью игнорируя крайнюю экономическую нецелесообразность.
Второстепенная ответственность лежит на интерфейсе Aave: При запросе котировки адаптера не прикреплялись данные приложения, связанные с хуками,直接将 ошибочный результат передавался в процесс подписания, и он полагался только на предупреждения, без механизмов жесткого отказа. Для таких экстремально крупных транзакций подобные меры контроля рисков совершенно недостаточны для предотвращения рисков.
Это был крах качества торговой маршрутизации и защитных ограждений, который превратил законную и соответствующую правилам операцию по ротации залога в разрушительное событие потери активов.






