The Standard

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

Setting `amountOutMinimum` to 0 even when the user has enough collateral can result in the loss of user funds due to a sandwich attack.

Summary

SmartVaultV3:swap function can have slippage protection of 0 if the user collateral excluding the swap fund is enough to cover the debt, this can result in the loss of the user collateral because of a sandwich attack.

Vulnerability Details

In smartVaultV3, users can exchange their collateral for another supported asset to avoid liquidation. This option is useful when they expect the value of their original collateral to decrease soon.

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
//@audit no slippage protection
collateralValueMinusSwapValue >= requiredCollateralValue
? 0
: calculator.eurToToken(
getToken(_outTokenSymbol),
requiredCollateralValue - collateralValueMinusSwapValue
);
}

The swapping is done using uniswapV3, and the amountOutMinimum is set to 0 if the total user collateral minus the swap amount is sufficient to cover the user debt and prevent liquidation.

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, //@audit don't set this to 0
sqrtPriceLimitX96: 0
});
inToken == ISmartVaultManagerV3(manager).weth()
? executeNativeSwapAndFee(params, swapFee)
: executeERC20SwapAndFee(params, swapFee);
}

While this is acceptable for the protocol but setting 100% as a slippage makes it an easy target for MEV bots, they can easily manipulate the transaction and return 0 as the received token, resulting in the loss of the user's collateral.

Link to how this type of attack works:

https://medium.com/coinmonks/defi-sandwich-attack-explain-776f6f43b2fd

Steps

  • User swap 100 LINK to ETH where slippage is set to 0

  • Due to the sandwich attack, the user will receive 0 ETH

  • his 100 LINK is lost

Impact

Users will lose their tokens and can be easily liquidated if the remaining collateral value falls even a small amount.

Tools Used

Manual review

Recommendations

Allow the user to set the amoutOutMinimum, instead of protocol doing that, because if a user is swapping he may be aware of the possible output.

Updates

Lead Judging Commences

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

Slippage-issue

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

Slippage-issue

Support

FAQs

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