March 13

DeFi. Атаки MEV-ботов. Обмен $220k USDc на $5k USDt

MEV-боты

Благодарность

Спасибо М. Сизых (@maxsiz) из DAO Envelop за важные дополнения!

Коротко

MEV-боты - это отдельная тема и любовь (или сильная НЕ любовь: зависит от того, кто вы и на какой стороне). Но в любом случае - эта тема интересна для любого нетсталкера.

Давайте рассмотрим новый пример? Давайте.

Суть атаки

Вот сама транзакция: https://etherscan.io/tx/0xee9fcd2b9996e96b642cb4cda47fc140f98fdaf07ee02657743d4bfcc4670106 и её скрин, чтобы не "бегать" по экранам:

Транзакция "взлома"

Видим, что $220 762,89 USDc обменены в Uniswap v. 3 пуле на $5,271,11 USDt, что, конечно же, не очень хорошо, а в целом - потери в $214k.

Но как такое произошло и случилось?! Посмотрим сюда:

Данные

Здесь стоит "обратить внимание,  что это вторая транзакция в блоке, и первая транзакция для адреса отправителя. А в первой транзакции блока MEV-бот создал перекос в пуле Uniswap" (цитирую CTO):

https://etherscan.io/tx/0xde5aa0c1521d97a48496f10bb8aff364e490c8fc3a4f5d9d587538f15d80cd36 и выглядит она вот так:

Транзакция-ловушка

И именно в этой транзакции  был хитрый кросс-займ (AAVE) с последующим свопом (Curve+Uniswap). В результате этого в пул Uniswap плюхнулось 18 млн $.  Это привело к разбалансировке пула:

Дисбланас пула

И теперь - важно! Ещё одна транзакция: буквально - следующая транзакция в блоке: она тоже от MEV-бота, где займ вернули:

https://etherscan.io/tx/0x3e72f3ad09d87149ce372e5f35eeb8012fed05f52bef45fb85fdacc0057a943c и выглядит это так:

Возврат займа

То есть перед нами что? Верно: классическая сендвич-атака!

(Есть подозрение, что подобное нельзя сделать, не имея сговор с блок- продьюсером. Почему? Потому что блоке  всего  8 транзакций,  что не типично для текущего объёма).

Что ещё нужно знать?

Давайте зайдём события по транзакции начальной: https://etherscan.io/tx/0xee9fcd2b9996e96b642cb4cda47fc140f98fdaf07ee02657743d4bfcc4670106#eventlog:

Логи траназкции

Что мы здесь видим? Коротко:

  • Сумму входа/выхода;
  • Ликвидность;
  • А ещё - тик.

Что это? Давайте обратимся к первоисточнику: в контексте предоставления ликвидности на Uniswap, тикминимальная единица измерения, используемая для определения конкретных ценовых диапазонов, в которых можно разместить ликвидность.

Каждый тик представляет собой наименьший участок ценового пространства, где может быть предоставлена ликвидность.

Каждый уровень комиссии (fee tier) имеет своё собственное расстояние между тиками (tick spacing), что помогает пулу отслеживать ликвидность. Расстояние между тиками определяет, насколько близко друг к другу расположены ценовые уровни, на которых можно размещать ликвидность.

Например, более низкие уровни комиссионных обеспечивают более близкое расположение потенциально активных тиков, что позволяет поставщикам ликвидности более точно настраивать диапазоны цен для своей ликвидности.

(Примечание: базисные пункты (basis points), известные как bps или "bips", — другой термин, используемый для обозначения процентного изменения цены пула. Один тик и один bip взаимозаменяемы и равны 0,01% или 0,0001 в десятичной форме. Десятичное значение bip составляет 1/10000. Таким образом, если умножить процентную ставку комиссии на 10 000, получится значение комиссии пула, используемое в контракте).

Пулы Uniswap v3 имеют диапазон тиков от минимального значения -887272 до максимального 887272.

Тики, используемые для позиций в верхних и нижних диапазонах, должны быть кратны расстоянию между тиками (tick spacing). Тики также могут быть преобразованы в цену; каждый пул имеет две цены, выраженные в значениях token0 и token1.

Таким образом, тики играют ключевую роль в определении и управлении ценовыми диапазонами, в которых поставщики ликвидности могут эффективно размещать свои средства, обеспечивая более точное и эффективное предоставление ликвидности на платформе Uniswap v3.

На практике получаем вот что: есть формула цены: Price = 1.0001*tick (один, ноль ноль ноль один в степени tick). Подставим tick=−38716tick=−38716, или Price=1.0001 в степени −38716, что приблизительно (≈) равно 0.02083.

Проще говоря: Price=1.0001−38716≈0.02083. А это означает, что в пуле цена 1 USDC = 0.02083 USDT, что совершенно не соответствует реальному курсу (≈ 1:1).

Как от этого защититься?

Сначала - 3 совета практических, которые использую КАЖДЫЙ ДЕНЬ:

  1. Никогда не меняю больше $10k (раньше делал, но давно отказался) за 1 раз. Да, я потеряю на комиссиях сколько-то, но оно того, как видите, стоит. Тем более, давайте честно: комиссии нынче вполне достойные и терпимые потому.
  2. Проскальзывание: довольно много про него знаю и знаю, также про практические имплементацию у 1inch и других, а потому: а) если знаю, что и как работает в ручном режиме - делаю это; б) если нет - использую автоматизированные.
  3. Всегда проверяю, если что-то крупное меня интересует, что происходило с пулом, vault и прочими инструментами до меня: для этого ведь и существуют эксплореры.

Теоретически можно добавить ещё 2:

  • Лимитные ордера - использую на дельта-нейтральных стратегиях, но редко, т.к. изначально ордер-бук должен быть или ончейн верно выстроен, или оффчейн, но с понятной оракульной защитой.
  • Пул инструментов, указанных выше в п. 2-3 надо постоянно расширять и тестировать, НО ДО проведения крупных сделок.

В остальном пока всё и

До!