一、関連モジュール:#
1)batchSwap
Balancer Vault において、batchSwap は Uniswap V4 のような任意の組み合わせ交換を提供します —— 取引が完了した時点でのみ決済が行われます。
トークンはプロセス中に任意の数量が増発される可能性があり、ユーザーは最終的な決済結果に対してのみ支払う必要があります。
2)Composable Pools(コンポーザブルプール)
基盤資産(例えば peg)が類似する LST トークンは Composable Pool で交換可能で、交換比率は元の線形プールにおける「LST と基盤資産の数量の比率」に依存します。{基盤資産 / LST} が大きいほど、その LST はコンポーザブルプール内での価値が高くなります。
3)線形プール
Balancer の線形プールは取引時に amount in を切り上げ、amount out を切り下げます。
プールの Virtual supply がゼロになると、プールは初期化され、この時 LST トークンは基盤資産と 1:1 で交換されます。
(Virtual supply=totalSupply - 線形プール balance
ここで Virtual supply は LST トークンの実際の発行量、totalSupply は定数、線形プール balance は予増発量を示します)
二、利用可能な攻撃ベクトル#
1) BatchSwap の「増発」メカニズム:LST トークンは取引中に Virtual supply を満たす数量が鋳造され、線形プールの初期化条件を提供します。
2) 線形プールの切り上げメカニズム:LST を基盤資産に交換する際、切り下げられた amount out は線形プールの交換比率を不均衡にし、線形プール内の元の資産比率が著しく異なる場合に特に顕著になります。
不均衡の表れ:{基盤資産 / LST} が大きい
3) コンポーザブルプールの交換比率メカニズム:コンポーザブルプールの特性に基づき、特定の LST の価格を引き上げることで、他の LST を割引価格で交換することができます。
三、主要なプロセス:#
-
最初のスワップ(usdc 線形プール):増発された USDC BPT(上記の LST)を使って線形プール内の大部分の usdc を交換しました。
-
二回目のスワップ(usdc 線形プール):amount out を 0 に設定した取引を構築します。線形プールの {基盤資産 / LST} は切り上げメカニズムにより極大になります。
-
三回目のスワップ(コンポーザブルプール):コンポーザブルプール内の DAI/USDT BPT が低価格で USDC BPT に交換されます。
-
四回目のスワップ(usdc 線形プール):線形プールに USDC BPT を注入し、VirturalSupply=0 にして線形プールを初期化します。
-
五回目のスワップ(usdc 線形プール):1:1 の比率で USDC を使って USDC BPT を交換し、「増発」されたローンを返済します。
五回目は必須です:USDC の精度は USDC BPT よりも低く、丸めによる線形プールのバランスの傾斜は一方向であり、五回目のみが十分な USDC BPT を提供し、同時に DAI/USDT BPT を保持できます。
四、連想#
zkLend 攻撃では、攻撃者は事前に lending_accumulator の値を極大にし、丸めメカニズムを利用して少量の wstETH を多量の wstETH に交換しました。
zkLend の丸めはすべて切り下げられます(コアペイロード)、Balancer の線形プールにも同様の問題がありますが、Balancer の攻撃者はこの経路を選びませんでした。
具体的な実装は:
- 1 > の金利で BPT を「借入れ」(フラッシュ)し、メインとラップされたトークンに取引してトークン残高をほぼゼロに減少させます。
- 取引を作成し、GivenOut スワップの丸め誤差を利用して総残高を仮想供給量と等しくし、為替レートを 1 にリセットします(為替レート = 残高 / 供給量)。
- 新しい低金利でフラッシュスワップ BPT を返済して利益を得ます。
五、参考#
https://slowmist.medium.com/review-and-recommendations-of-balancer-incident-d2b31b5bd863