The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: medium
Valid

Divergence in the pricing method for collateral within the `calculateMinimumAmountOut()` may result in vaults transitioning into an uncollateralized state after executing swaps.

Summary

In the SmartVaultV3.calculateMinimumAmountOut() function, the variable collateralValueMinusSwapValue is computed using calculator.tokenToEur() instead of calculator.tokenToEurAvg(). This leads to inaccurate values for collateralValueMinusSwapValue when there are recent changes in the price of the swapped token. In extreme cases, this miscalculation can result in the SmartVaultV3.swap() function instantly placing the vault in an uncollaterized position after the swap.

Vulnerability Details

Before any swap is done, the swap parameters need to be calculated on-chain, especially the minAmountOut parameter. This parameter is calculated in SmartVaultV3.calculateMinimumAmountOut(), as shown in the code snippet from calculateMinimumAmountOut() below.

function calculateMinimumAmountOut(bytes32 _inTokenSymbol, bytes32 _outTokenSymbol, uint256 _amount) private view returns (uint256) {
ISmartVaultManagerV3 _manager = ISmartVaultManagerV3(manager);
uint256 requiredCollateralValue = minted * _manager.collateralRate() / _manager.HUNDRED_PC();
uint256 collateralValueMinusSwapValue = euroCollateral() - calculator.tokenToEur(getToken(_inTokenSymbol), _amount);
return collateralValueMinusSwapValue >= requiredCollateralValue ?
0 : calculator.eurToToken(getToken(_outTokenSymbol), requiredCollateralValue - collateralValueMinusSwapValue);
}

As we can see, when collateralValueMinusSwapValue is calculated it gets the current vault collateral from euroCollateral().Internally, this function uses calculator.tokenToEurAvg() to fetch the value of collaterals. The method tokenToEurAvg() computes the average value of the specified token over the last four hours. However, immediately following this, euroCollateral() subtracts the result by calculator.tokenToEur, which instead utilizes the most recent value of the token, not the averaged one.

This mismatch from using tokenToEur instead of tokenToEurAvg() makes collateralValueMinusSwapValue susceptible to rapid price fluctuations. Consequently, under volatile market conditions, collateralValueMinusSwapValue might be overestimated or underestimated, depending on whether the token prices are rising or falling.

If tokenToEurAvg() > tokenToEur(), such as when the token price is falling, collateralValueMinusSwapValue will be overestimated. Conversely, if tokenToEurAvg() < tokenToEur(), such as when the price is increasing, collateralValueMinusSwapValue will be underestimated. This discrepancy can lead to issues; for instance, an overestimated collateralValueMinusSwapValue can result in a smaller minAmountOut calculated in SmartVaultV3.calculateMinimumAmountOut(). In extreme cases, this can cause the swap output to be less collateral than required, putting the vault in an uncollaterized state.

This is particularly problematic during situations when vault owners are more likely to perform swaps, such as swapping one collateral for another during periods of market volatility to shield themselves from declining asset values. In such cases, the difference between tokenToEurAvg() and tokenToEur() becomes more significant due to the rapid price fluctuations.

Consider the following example: If the price of WBTC has significantly decreased over the last few hours, a vault owner swaps their WBTC collateral to another asset to safeguard against undercollateralization in case the WBTC keeps falling. However, due to the recent fall in the WBTC price, tokenToEurAvg() > tokenToEur(), leading to an overestimated collateralValueMinusSwapValue. As a result, the minAmountOut calculated from the swap is reduced, making the vault less collateralized, contrary to the owner's intention of protecting the vault through the swap.

Impact

During volatile market conditions, collateralValueMinusSwapValue will be calculated incorrectly. In extreme cases, this can cause swaps to place the vault in an uncollaterized state.

Tools Used

Manual Review.

Recommended Mitigation

Consider using calculator.tokenToEurAvg instead of calculator.tokenToEur in SmartVaultV3.calculateMinimumAmountOut().

Updates

Lead Judging Commences

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Slippage-issue

tricko Submitter
over 1 year ago
t0x1c Auditor
over 1 year ago
hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

avg-spot-price

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.