On November 3, 2025, the Balancer protocol was attacked by hackers on multiple public chains such as Arbitrum and Ethereum, resulting in a loss of $120 million in assets. The core of the attack stemmed from a dual vulnerability of precision loss and invariant manipulation.
The key issue in this attack lies in the protocol's logic for handling small transactions. When a user makes a small exchange, the protocol calls the _upscaleArray function, which uses mulDown to round the value down. If the balance in the transaction and the input amount both fall within a specific rounding boundary (e.g., the 8-9 wei range), a significant relative precision error occurs.
The accuracy error propagated to the calculation of the invariant value D in the protocol caused the value of D to be abnormally reduced. The change in the value of D directly lowered the price of BPT (Balancer Pool Token) in the Balancer protocol. Hackers exploited this depressed price of BPT to complete arbitrage through pre-designed transaction paths, ultimately causing huge asset losses.
Vulnerability exploit link:
Asset transfer link:
The attack entry point is the Balancer: Vault contract, and the corresponding entry function is the batchSwap function, which internally calls onSwap to perform token swaps.
From the function parameters and restrictions, we can obtain several pieces of information:
BPT Price Calculation Method
In Balancer's stable pool model, the price of BPT is an important reference point, which determines how many BPTs a user receives and how many assets are received per BPT.
In the pool exchange calculation:
The portion that serves as the benchmark for BPT prices is a constant value D ; that is, manipulating BPT prices requires manipulating D. Let's analyze the calculation process of D:
In the code above, the calculation of D depends on the scaled balances array . This means that an operation is needed to change the precision of these balances, leading to an error in the calculation of D.
As shown above, when using _upscaleArray , if the balance is very small (e.g., 8-9 wei), the down-rounding of mulDown will result in a significant loss of precision.
The attacker above used Batch Swap to perform multiple swaps within a single transaction:
These swaps are all within the same batch swap transaction and the same balance state , but _upscaleArray is called to modify the balances array for each swap.
The main process is started by Vault, so how does this lead to the accumulation of precision loss? The answer lies in the passing mechanism of the balances array .
Analyzing the code above, although Vault creates a new currentBalances array every time onSwap is called, in Batch Swap :
The reasons for Balancer's attack can be summarized as follows:
1. Scaling function uses rounding down : _upscaleArray uses mulDown for scaling, which will produce a significant loss of relative precision when the balance is very small (such as 8-9 wei).
2. Invariant value calculation is sensitive to precision : The calculation of the invariant value D depends on the scaled balances array, and the precision loss will be directly passed to the calculation of D, making D smaller.
3. Lack of verification of changes in invariant values : During the exchange process, it was not verified whether the changes in the invariant value D were within a reasonable range, which allowed attackers to repeatedly exploit the loss of precision to lower the price of BPT.
4. Accumulated precision loss in batch swap : In the same batch swap, the precision loss from multiple swaps will accumulate and eventually amplify into huge financial losses.
These two issues—precision loss and lack of validation—combined with the attacker's careful design of boundary conditions, resulted in this loss.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
