以下は、GIVEN_OUT 交換タイプにおける amount_in の計算を示しており、これは不変量 D に関連しています。
inGivenOut token x for y - 解く多項式方程式
// ax = 計算するための金額
// bx = トークン残高
x = bx + ax (finalBalanceIn)
D = 不変式
A = 増幅係数
// n = トークンの数
S = 最終残高の合計ですが、x
// P = 最終残高の積ですが x
D D^(n+1)
x ^ 2 + ( S - ---------- - D) * x - ------------- = 0
(A * n^n) A * n^2n * P
価格操作の黒魔術: Balancer V2 の不変計算の脆弱性の解剖学
編纂:平易なブロックチェーン
!
2025年11月3日、Balancer V2のコンポーザブルステーブルプール(Composable Stable Pools)および複数のチェーン上のいくつかのフォークプロジェクトが協調攻撃を受け、総損失は1.25億ドルを超えました。BlockSecは最初に警報を発し、その後初期分析を発表しました。
これは高度に複雑な攻撃です。私たちの調査によると、根本的な原因は不変量(invariant)計算における精度の損失によって引き起こされた価格操作であり、それによってBPT(Balancerプールトークン)の価格計算が歪められました。この不変量操作により、攻撃者は特定の安定プールからの一回のバッチスワップを通じて利益を得ることが可能になりました。一部の研究者が洞察に満ちた分析を提供していますが、特定の解釈には誤解を招くものがあり、根本的な原因や攻撃プロセスはまだ完全には明らかにされていません。本ブログはこの事件について包括的かつ正確な技術分析を行うことを目的としています。
重要なポイント (TL;DR)
根本原因: 丸めの不整合と精度の損失
攻撃の実行
運用上の影響と増幅
以下の部分では、まずBalancer V2に関する重要な背景情報を提供し、その後、発見された問題や関連する攻撃について詳しく分析します。
0x1 背景
1. Balancer V2 のコンビネーション型ステーブルプール
今回の攻撃で影響を受けたコンポーネントは、Balancer V2 プロトコルのコンビネーション型ステーブルプールです。これらのプールは、1:1 のペッグ(または既知の為替レートで取引される)資産を維持することを目的として設計されており、最小限の価格影響で大規模な交換を可能にし、同類または関連資産間の資本効率を大幅に向上させます。各プールには、自身の Balancer プールトークン (BPT) があり、流動性提供者のプール内の持分と、それに対応する基礎資産を表しています。
このプールは、Stable Math(Curveに基づくStableSwapモデル)を採用しており、不変量Dはプールの仮想総価値を表しています。
BPT価格は次のように近似できます:
2. batchSwap()とonSwap()
Balancer V2 は、batchSwap() 関数を提供しており、この関数は Vault 内でのマルチホップスワップをサポートしています。この関数に渡されるパラメータに基づいて、2 種類のスワップタイプがあります。
通常、batchSwap() は、複数の onSwap() 関数を通じて実行されるトークン間の交換で構成されています。以下は、SwapRequest が GIVEN_OUT 交換タイプとして割り当てられたときの実行パスを概説しています(ComposableStablePool は BaseGeneralPool を継承していることに注意してください):
! 【画像】()
以下は、GIVEN_OUT 交換タイプにおける amount_in の計算を示しており、これは不変量 D に関連しています。
inGivenOut token x for y - 解く多項式方程式 // ax = 計算するための金額 // bx = トークン残高 x = bx + ax (finalBalanceIn)
D = 不変式 A = 増幅係数 // n = トークンの数 S = 最終残高の合計ですが、x
// P = 最終残高の積ですが x
x ^ 2 + ( S - ---------- - D) * x - ------------- = 0
(A * n^n) A * n^2n * P
3. スケーリングと丸め
異なるToken残高間の計算を標準化するために、Balancerは以下の2つの操作を実行します:
! 【画像】()
! 【画像】()
明らかに、拡大と縮小は理論的には対になった操作であり、それぞれ乗算と除算です。しかし、これらの操作の実装には不一致があります。具体的には、縮小操作には divUp と divDown の2つの変種または方向があります。対照的に、拡大操作には mulDown という1つの方向しかありません。
この不一致の原因はまだ明らかではありません。_upscale() 関数のコメントによると、開発者は片方向の丸めの影響がごくわずかであると考えています。
0x2 脆弱性分析
根本問題は、BaseGeneralPool._swapGivenOut() 関数内でのアップスケーリング操作を実行する際に実施される切り捨て操作に起因します。特に、_swapGivenOut() は _upscale() 関数を通じて swapRequest.amount を誤って切り下げます。この切り捨てられた値は、その後 amountOut として使用され、_onSwapGivenOut() を通じて amountIn を計算するために使用されます。このような動作は「丸めはプロトコルに有利な方法で適用されるべきである」という標準的な慣行に矛盾しています。
! 【画像】()
したがって、与えられたプール(wstETH/rETH/cbETH)に対して、計算された amountIn は実際に必要な入力を過小評価しています。これにより、ユーザーは少ない数量の一つの基礎資産(例えば wstETH)を別の資産(例えば cbETH)と交換でき、効果的な流動性の減少により不変量 D が減少します。したがって、対応する BPT(wstETH/rETH/cbETH)の価格は人為的に押し下げられ(deflated)、なぜなら $\text{BPT price} = \frac{D}{\text{totalSupply}}$ だからです。
0x3 攻撃分析
攻撃者は実行しました
二段階攻撃は、検出リスクを最小限に抑えるためのものである可能性があります:
第一段階はさらに二つの段階に分けることができます:パラメータ計算とバッチ交換。以下に、Arbitrum上の攻撃取引(TX)の例を使用して(これらの段階を説明します。
パラメータ計算段階
この段階では、攻撃者はオフチェーン計算とオンチェーンシミュレーションを組み合わせ、ハイブリッド安定プールの現在の状態(スケーリングファクター、拡大係数、BPTレート、交換手数料、その他のパラメータを含む)に基づいて、次の段階(バッチ交換)での各ジャンプのパラメータを正確に調整します。興味深いことに、攻撃者はこれらの計算を支援するために補助契約を展開しました。これは「フロントランニング」のリスクを減らすためかもしれません。
まず、攻撃者はターゲットプールの基本情報を収集します。これには各Tokenのスケーリングファクター、拡大パラメーター、BPTレート、および交換手数料の割合が含まれます。それから、彼らは精度損失を引き起こすために操作されたターゲットTokenの数である重要な値trickAmtを計算します。
ターゲットトークンのスケーリングファクター(scaling factor)を sF として、次のように計算します:
uint256[] バランス; プールトークンの残高(BPTを除く) uint256[] scalingFactors; // 各プールのトークンのスケーリングファクター uint tokenIn; // このジャンプがシミュレートする入力トークンのインデックス uint tokenOut; // このジャンプでシミュレーションされる出力トークンのインデックス uint256 amountOut; 出力トークンの予想数 uint256 amp; // プールの拡大パラメータ uint256料金; プールインターチェンジフィーの割合
返されたデータは:
uint256[] バランス; スワッピング後のプールトークンの残高(BPTを除く)
具体的には、初期残高と反復ループの回数はチェーン外で計算され、攻撃者の契約にパラメータとして渡されます(報告はそれぞれ 100,000,000,000 と 25)。各反復は三回の交換を実行します:
ご注意ください。StableMathの計算においてニュートン-ラフソン法が使用されているため、このステップは時折失敗する可能性があります。この状況を緩和するために、攻撃者は2回の再試行を実装し、各回のバックアップ値として元の値の9/10を使用しています。
攻撃者の補助コントラクトは Balancer V2 の StableMath ライブラリから派生しており、これは「BAL」スタイルのカスタムエラーメッセージが含まれていることから証明できます。
$d$ バッチ交換フェーズ
そして、batchSwap###( 操作は三つのステップに分解できます:
! 【画像】)( 3. ステップ 3:攻撃者は、基盤となる資産を逆に BPT に換え、バランスを回復し、同時に押し下げられた BPT の価格から利益を得ます。
0x4:攻撃対損失
私たちは下表にこれらの攻撃とそれに対応する損失をまとめており、総損失は1.25億ドルを超えています。
! 【画像】)(
0x5 まとめ
この事件は、Balancer V2 プロトコルおよびそのフォークプロジェクトに対する一連の攻撃取引に関連しており、重大な財務損失を引き起こしました。最初の攻撃の後、複数のチェーン上で大量の追随および模倣取引が観察されました。この事件は、DeFi プロトコルの設計とセキュリティに関するいくつかの重要な教訓を浮き彫りにしています。
運営とビジネスの継続性を維持しながら、業界の参加者は BlockSec Phalcon を最後の防御線として利用して、彼らの資産を保護することができます。BlockSec の専門家チームは、あなたのプロジェクトのために包括的なセキュリティ評価を行う準備が整っています。
本文リンク:
源: