Closed sherlock-admin closed 1 year ago
@T-Woodward / @weitianjie2000
Think this is not a legitimate bug, but still investigating to be sure
@T-Woodward comment from submitter
The report highlights that price calculation is computed using virtualSupply and other variables. The virtualSupply is derived from the Deployments.BALANCER_VAULT.getPoolTokens(BALANCER_POOL_ID) function. The API spec for this function from Balancer can be found https://dev.balancer.fi/references/contracts/apis/the-vault#getpooltokens
As you can see the Balancer's getPoolTokens function will get the spot balance of the tokens within the Balance pool. Whenever a price calculation involves the spot balance of a pool, it is no longer resistant to price manipulation because the spot balance or pool can be manipulated within a single block/transaction.
Yeah but I suspect that is vacuously true. Yes, the virtual supply can be changed in one transaction - by trading on the pool. But guess what - doing so also changes the balances of the other tokens in the pool. So on a net basis there's no impact. This guy hasn't shown any proof that there is a net impact. I'm 99% sure there isn't but we're still doing more testing to prove that @Evert0x
xiaoming90
high
Boosted Balancer Leverage Vault Vulnerable To Price Manipulation
Summary
The Boosted Balancer leverage vaults are vulnerable to price manipulation as one of the variables used to compute the price can be manipulated within a single block/transaction.
Vulnerability Detail
The design of the strategy vault must be resistant to price manipulation and flash-loan attacks.
It was observed that the token balance returned by the
Boosted3TokenPoolUtils._getTimeWeightedPrimaryBalance
function is not time-weighted even though the comments claim that it will return the time-weighted primary token balance for a givenbptAmount
and will use Chainlink (See Line 185-186). Thus, theBoosted3TokenPoolUtils._getTimeWeightedPrimaryBalance
function is not flash-loan resistance.The
primaryAmount
returned byBoosted3TokenPoolUtils._getTimeWeightedPrimaryBalance
function is computed based on a number of variables. One of the variables used during the calculation is thevirtualSupply
.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/Boosted3TokenPoolUtils.sol#L191
The
virtualSupply
is computed within theBoosted3TokenPoolUtils._getVirtualSupply
function. Note that theoracleContext.bptBalance
is used during the calculation.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/Boosted3TokenPoolUtils.sol#L136
The
oracleContext.bptBalance
is derived from thebalances
parameter passed into theBoosted3TokenPoolMixin._boostedOracleContext
function.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/mixins/Boosted3TokenPoolMixin.sol#L103
The
balances
parameter passed into theBoosted3TokenPoolMixin._boostedOracleContext
function is retrived from theDeployments.BALANCER_VAULT.getPoolTokens(BALANCER_POOL_ID)
function at Line 195. This is a major issue because the spot balance/reserve of the Boosted BPT token (e.g. bb-a-USD) is being used in the calculation of thevirtualSupply
. As such, thevirtualSupply
can be manipulated within a single transaction/block by buying or selling the Boosted BPT token (e.g. bb-a-USD) from the pool.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/Boosted3TokenAuraVault.sol#L190
Note that the
virtualSupply
is passed to theStableMath._calcTokenOutGivenExactBptIn
function at Line 213. Therefore, the returnedprimaryAmount
amount can be manipulated within a single transaction/block. With that, a malicious user manipulates the balance returned from the_getTimeWeightedPrimaryBalance
function to be larger or smaller than expected depending on the attack scenarios.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/Boosted3TokenPoolUtils.sol#L191
Impact
The
_getTimeWeightedPrimaryBalance
function is used by many functions within the Boosted Balancer Leverage Vault. The most critical function affected by this issue would be theVaultConfiguration.calculateCollateralRatio
function that relies on the_getTimeWeightedPrimaryBalance
function when converting the strategy tokens to underlying value (SeeBoosted3TokenPoolUtils._convertStrategyToUnderlying
). Therefore, the collateral ratio of a vault account can be manipulated in favor of the attacker.For instance, an attacker can manipulate the collateral ratio to be much larger than the threshold to overborrow from Notional, or an attacker can manipulate the collateral ratio of a vault account to fall below the threshold in an attempt to pre-maturely deleverage/liquidate an account.
Code Snippet
https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/Boosted3TokenPoolUtils.sol#L191 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/pool/Boosted3TokenPoolUtils.sol#L136 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/mixins/Boosted3TokenPoolMixin.sol#L103 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/Boosted3TokenAuraVault.sol#L190
Tool used
Manual Review
Recommendation
It is recommended to avoid using spot reserve or spot price within the
_getTimeWeightedPrimaryBalance
function when computing the balance. Consider leveraging Chainlink as per the source code's comment to derive the balance at Line 186