#3 Инцидент с Balancer V2: несоответствие округления нарушает инвариант и распространяется по цепочкам
3 ноября 2025 года пулы Composable Stable Pools протокола Balancer V2, а также ряд форк-проектов в нескольких сетях подверглись скоординированной атаке, результатом которой стали совокупные потери на сумму более $125 миллионов, из которых, по имеющимся данным, около $45 миллионов удалось вернуть. Первопричиной стала манипуляция ценой, вызванная потерей точности при расчете инварианта, что стало следствием несоответствия округления между операциями масштабирования вверх и вниз, исказившими логику ценообразования BPT (токена пула Balancer).
Этот инцидент выделяется как один из десяти крупнейших инцидентов безопасности 2025 года не только из-за масштаба потерь, но и из-за сложности самой уязвимости. Более того, эксплойт быстро распространился по нескольким сетям, затронув как Balancer, так и его форки, что подчеркивает, как общие кодовые базы и компонуемая DeFi-инфраструктура могут значительно усиливать системные риски.
Мы опубликовали подробный отчет «Глубокий анализ: эксплойт Balancer V2» [1], который содержит детальный технический разбор. Ниже представлено краткое описание инцидента.
Предыстория
Composable Stable Pool в Balancer V2
Затронутым компонентом в этой атаке стал Composable Stable Pool [2] протокола Balancer V2. Эти пулы предназначены для активов, которые, как ожидается, поддерживают паритет 1:1 (или торгуются по известному курсу обмена), и позволяют совершать крупные свопы с минимальным влиянием на цену, тем самым значительно повышая эффективность капитала для аналогичных или коррелирующих активов. Каждый пул имеет свой токен Balancer Pool Token (BPT), представляющий долю поставщика ликвидности в пуле, наряду с соответствующими базовыми активами.
-
Этот пул использует Stable Math (основанную на модели Curve StableSwap), где инвариант D представляет собой виртуальную общую стоимость пула.
-
Цена BPT может быть аппроксимирована следующим образом:
Исходя из приведенной выше формулы, если D можно сделать меньше «на бумаге» (даже без фактической потери средств), цена BPT будет казаться ниже.
batchSwap() и onSwap()
Balancer V2 предоставляет функцию batchSwap(), которая позволяет выполнять многоходовые свопы внутри Vault [3]. Существует два типа свопов, определяемых параметром, передаваемым в эту функцию:
GIVEN_IN(«С заданным входом»): вызывающая сторона указывает точное количество входного токена, а пул вычисляет соответствующее выходное количество.GIVEN_OUT(«С заданным выходом»): вызывающая сторона указывает желаемое выходное количество, а пул вычисляет необходимое входное количество.
Обычно batchSwap() состоит из нескольких свопов «токен-в-токен», выполняемых через функцию onSwap(). Этот процесс неизбежно включает вычисления сумм, привязанные к инварианту D [1].
Масштабирование и округление
Для нормализации вычислений между различными балансами токенов Balancer выполняет две следующие операции:
- Масштабирование вверх (Upscaling): масштабирование балансов и сумм до единой внутренней точности перед выполнением вычислений.
- Масштабирование вниз (Downscaling): преобразование результатов обратно к их исходной точности с применением направленного округления (например, входные суммы обычно округляются вверх, чтобы избежать недоплаты в сторону пула, в то время как выходные суммы часто округляются вниз).
Теоретически масштабирование вверх и вниз — это парные операции: умножение и деление соответственно. Однако в реализации этих двух операций существует несоответствие. В частности, операция масштабирования вниз имеет два варианта или направления: divUp и divDown. Напротив, операция масштабирования вверх имеет только одно направление, а именно mulDown.
Анализ уязвимости
Фундаментальная проблема возникает из операции округления вниз, выполняемой во время масштабирования вверх в функции BaseGeneralPool._swapGivenOut(). В частности, _swapGivenOut() некорректно округляет вниз swapRequest.amount через функцию _upscale(). Полученное округленное значение впоследствии используется как amountOut при расчете amountIn через _onSwapGivenOut(). Это поведение противоречит стандартной практике, согласно которой округление должно применяться таким образом, чтобы это было выгодно протоколу.
Таким образом, для заданного пула (wstETH/rETH/cbETH) вычисленное значение amountIn недооценивает фактически требуемый вход. Это позволяет пользователю обменять меньшее количество одного базового актива (например, wstETH) на другой (например, cbETH), тем самым уменьшая инвариант D в результате снижения эффективной ликвидности. Следовательно, цена соответствующего BPT (wstETH/rETH/cbETH) становится заниженной, так как цена BPT = D / общий объем предложения.
Анализ атаки
Злоумышленник провел двухэтапную атаку, вероятно, чтобы минимизировать риск обнаружения:
- На первом этапе основной эксплойт был выполнен в рамках одной транзакции, не принесшей немедленной прибыли.
- На втором этапе злоумышленник реализовал прибыль, выведя активы в отдельной транзакции.
Первый этап можно дополнительно разделить на две фазы: расчет параметров и пакетный своп. Ниже мы проиллюстрируем эти фазы на примере транзакции атаки (TX) в сети Arbitrum.
Фаза расчета параметров
На этой фазе злоумышленник объединил вычисления вне сети с симуляциями внутри сети, чтобы точно настроить параметры каждого «прыжка» в следующей (пакетной) фазе, основываясь на текущем состоянии Composable Stable Pool (включая масштабные коэффициенты, коэффициент усиления, курс BPT, торговые комиссии и другие параметры). Злоумышленник также развернул вспомогательный контракт для помощи в этих расчетах, что, возможно, было сделано для снижения вероятности фронтраннинга. Более подробную информацию см. в [1].
Фаза пакетного свопа
Операция batchSwap() может быть разбита на три шага:
Шаг 1: Злоумышленник обменивает BPT (wstETH/rETH/cbETH) на базовые активы, чтобы точно настроить баланс одного токена (cbETH) до границы округления (количество = 9). Это создает условия для потери точности на следующем шаге.
Шаг 2: Затем злоумышленник совершает своп между другим базовым активом (wstETH) и cbETH, используя специально подобранное количество (= 8). Из-за округления вниз при масштабировании сумм токенов вычисленное Δx становится чуть меньше (8.918 превращается в 8), что приводит к недооцененному Δy и, следовательно, к меньшему инварианту (D из модели Curve StableSwap). Поскольку цена BPT = D / общий объем предложения, цена BPT становится искусственно заниженной.
Шаг 3: Злоумышленник совершает обратный своп базовых активов в BPT, восстанавливая баланс и получая прибыль за счет заниженной цены BPT.
Резюме
Этот инцидент включал серию скоординированных транзакций эксплойта, нацеленных на пулы Balancer V2 Composable Stable и множество форк-проектов в разных сетях, что привело к существенным потерям. После первого эксплойта начали появляться подражатели, что показывает, как быстро паттерн атаки может распространиться после публикации.
Ключевые выводы:
- Округление и обработка точности: Каждая операция масштабирования и точности с суммами токенов должна округляться в сторону, выгодную протоколу. Даже одного несоответствия между
_upscale()(только округление вниз) и операциями масштабирования вниз (направленное округление) оказалось достаточно для создания уязвимости ценового искажения. - Гонка вооружений в безопасности: Злоумышленник разделил манипуляцию и вывод прибыли на разные транзакции, чтобы избежать обнаружения. Системы обнаружения должны коррелировать связанные транзакции, а не просто помечать отдельные из них.
- Операционная безопасность: Как только паттерн эксплойта стал публичным, подражатели воспроизвели его в других сетях в течение нескольких минут. Протоколам, использующим общую кодовую базу, требуется скоординированный мониторинг и возможности быстрой межсетевой приостановки работы.
Ссылки
-
https://blocksec.com/blog/in-depth-analysis-the-balancer-v2-exploit
-
https://docs-v2.balancer.fi/concepts/pools/composable-stable.html
-
https://docs-v2.balancer.fi/reference/swaps/batch-swaps.html
О компании BlockSec
BlockSec — поставщик комплексных услуг в области безопасности блокчейна и крипто-комплаенса. Мы создаем продукты и услуги, которые помогают клиентам проводить аудит кода (включая смарт-контракты, блокчейн и кошельки), перехватывать атаки в режиме реального времени, анализировать инциденты, отслеживать незаконные средства и соблюдать требования AML/CFT на протяжении всего жизненного цикла протоколов и платформ.
BlockSec опубликовала множество работ по безопасности блокчейн-систем на престижных конференциях, сообщила о нескольких атаках «нулевого дня» в DeFi-приложениях, заблокировала множество хакерских атак, спасая более 20 миллионов долларов, и обеспечила сохранность криптовалютных активов на миллиарды долларов.
-
Официальный сайт: https://blocksec.com/
-
Официальный аккаунт в Twitter: https://twitter.com/BlockSecTeam



