1. Related Modules:#
1) batchSwap
In the Balancer Vault, batchSwap provides arbitrary combination swaps similar to Uniswap V4—settlement occurs only after the transaction is completed.
Tokens can be minted in any quantity during the process, and users only need to pay for the final settlement result.
2) Composable Pools
LST tokens with similar underlying assets (such as peg) can be exchanged in Composable Pools, with the exchange ratio depending on the ratio of "LST to underlying asset quantity" in the original linear pool. The larger the {underlying asset/LST}, the higher the value of that LST in the composable pool.
3) Linear Pools
Balancer's linear pools round up the amount in and round down the amount out during transactions.
When the pool's Virtual supply is zero, the pool will initialize, at which point LST tokens are exchanged 1:1 with the underlying asset.
(Virtual supply = totalSupply - linear pool balance
where Virtual supply is the actual issuance of LST tokens, totalSupply is a constant, and linear pool balance represents the pre-minted amount)
2. Available Attack Vectors#
1) The "minting" mechanism of BatchSwap: LST tokens can be minted during the transaction to fill the Virtual supply, providing conditions for initializing the linear pool.
2) The rounding mechanism of linear pools: Using LST to exchange for underlying assets, the rounded down amount out can cause an imbalance in the exchange ratio of the linear pool, especially when the original asset ratios in the linear pool are disparate.
Imbalance manifestation: {underlying asset/LST} is too large
3) The exchange ratio mechanism of composable pools: According to the characteristics of composable pools, raising the price of a certain LST can allow for the exchange of other LSTs at a discounted price.
3. Main Process:#
-
The first swap (USDC linear pool): The "minted" USDC BPT (the LST mentioned above) exchanges for most of the USDC in the linear pool.
-
The second swap (USDC linear pool): A transaction is constructed where the amount out is set to 0. The linear pool's {underlying asset/LST} becomes extremely large due to the rounding mechanism.
-
The third swap (composable pool): The DAI/USDT BPT in the composable pool is exchanged for USDC BPT at a low price.
-
The fourth swap (USDC linear pool): USDC BPT is injected into the linear pool, making VirtualSupply=0, initializing the linear pool.
-
The fifth swap (USDC linear pool): USDC is exchanged for USDC BPT at a 1:1 ratio to repay the "minted" loan.
The fifth step is essential: The precision of USDC is lower than that of USDC BPT, and the rounding-induced balance tilt in the linear pool is one-sided; only the fifth step can provide sufficient USDC BPT while retaining DAI/USDT BPT.
4. Association#
In the zkLend attack, the attacker first made the value of lending_accumulator extremely large, then used the rounding mechanism to exchange a small amount of wstETH for a larger amount of wstETH.
The rounding in zkLend rounds down (core payload), and Balancer's linear pool has the same issue, but the Balancer attacker did not take this path.
The specific implementation is:
- "Borrow" BPT at a rate of 1 > (flash loan) and trade it for main and wrapped, reducing the token balance to near zero.
- Create a transaction that utilizes the rounding error of GivenOut swaps to make the total balance equal to the virtual supply, thus resetting the exchange rate to 1 (because exchange rate = balance/supply).
- Repay the flash loan BPT at the new lower rate to make a profit.
5. References#
https://slowmist.medium.com/review-and-recommendations-of-balancer-incident-d2b31b5bd863