The Standard

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

swap computation should take spot price

Summary

SmartVaultV3 swaps Collateral through the uniswap V3 and instead of spot price it does computation based on the average price of 4 hours.

Vulnerability Details

function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount) external onlyOwner {
uint256 swapFee = _amount * ISmartVaultManagerV3(manager).swapFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
address inToken = getSwapAddressFor(_inToken);
uint256 minimumAmountOut = calculateMinimumAmountOut(_inToken, _outToken, _amount);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: inToken,
tokenOut: getSwapAddressFor(_outToken),
fee: 3000,
recipient: address(this),
deadline: block.timestamp,
amountIn: _amount - swapFee,
amountOutMinimum: minimumAmountOut,
sqrtPriceLimitX96: 0
});
inToken == ISmartVaultManagerV3(manager).weth() ?
executeNativeSwapAndFee(params, swapFee) :
executeERC20SwapAndFee(params, swapFee);
}

https://github.com/Cyfrin/2023-12-the-standard/blob/main/contracts/SmartVaultV3.sol#L214

Owner of smart vault calls swap() to swap input token to output token. To set the slippage it calls private function calculateMinimumAmountOut()

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

https://github.com/Cyfrin/2023-12-the-standard/blob/main/contracts/SmartVaultV3.sol#L206

At Line 208 it computes the requiredCollateralValue which is necessary collateral smart vault should have for minted euros. but at Line 209 it computes collateralValueMinusSwapValue from euroCollateral() which is coming from average token price of 4 hours.

function euroCollateral() private view returns (uint256 euros) {
ITokenManager.Token[] memory acceptedTokens = getTokenManager().getAcceptedTokens();
for (uint256 i = 0; i < acceptedTokens.length; i++) {
ITokenManager.Token memory token = acceptedTokens[i];
euros += calculator.tokenToEurAvg(token, getAssetBalance(token.symbol, token.addr));
}
}

https://github.com/Cyfrin/2023-12-the-standard/blob/main/contracts/SmartVaultV3.sol#L71

As here it computes the euros from average price not as spot price

Impact

Not using spot price for swap could leads to too higher/lower slippage i.e. unfavorable trade, which can also trigger liquidation of vault

Tools Used

Manual

Recommendations

Use spot price during swap instead of 4 hours average price of tokens

Updates

Lead Judging Commences

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

chainlink-minanswer

tripathi Submitter
over 1 year ago
hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

chainlink-minanswer

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

avg-spot-price

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.