A pool with an empty asset's balance allows for anyone to generate unlimited free share tokens. As a result, such a pool can be emptied by an attacker.
As a result, deposing assets in a pool with an empty balance generates free pool tokens.
An attacker with enough funds can empty any pool's asset. Pools with low liquidity or assets with low a decimals are more likely to be vulnerable
Exploit Scenario
Bob has a pool with $10,000 of TUSD (decimals 6) and $10,000 of DAI (decimals 18). Eve has $10,000,000. Eve buys all the TUSD from the pool, generates free pool tokens, and empties both assets from the pool. Eve stole $20,000.
A truffle test is provided below showing this scenario.
Recommendation
Short term, revert in joinswapPoolAmountOut if calcSingleInGivenPoolOut is zero.
Long term, consider to:
Check for the 0 value when transferring values if appropriate.
Use Echidna and Manticore to test the rounding effects
Fixed. Requires tokenAmountIn != 0 for joinswapPoolAmountOut. Also, the new min / max ratios on joinswap and exitswap should limit this type of behavior.
Severity: High Difficulty: High
Description
A pool with an empty asset's balance allows for anyone to generate unlimited free share tokens. As a result, such a pool can be emptied by an attacker.
joinswapPoolAmountOut
is of the function to deposit a single asset: https://github.com/balancer-labs/balancer-core/blob/942a51e202cc5bf9158bad77162bc72aa0a8afaf/contracts/BPool.sol#L582-L604If
inRecord.balance
is 0,calcSingleInGivenPoolOut
will returns 0: https://github.com/balancer-labs/balancer-core/blob/942a51e202cc5bf9158bad77162bc72aa0a8afaf/contracts/BMath.sol#L147-L183As a result, deposing assets in a pool with an empty balance generates free pool tokens.
An attacker with enough funds can empty any pool's asset. Pools with low liquidity or assets with low a decimals are more likely to be vulnerable
Exploit Scenario
Bob has a pool with $10,000 of TUSD (decimals 6) and $10,000 of DAI (decimals 18). Eve has $10,000,000. Eve buys all the TUSD from the pool, generates free pool tokens, and empties both assets from the pool. Eve stole $20,000.
A truffle test is provided below showing this scenario.
Recommendation
Short term, revert in
joinswapPoolAmountOut
ifcalcSingleInGivenPoolOut
is zero.Long term, consider to:
Testcase