The Standard

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

incorrect calculation of minimumAmountOut due to inconsistency between chainlink price feeds and uniswap v3 pools in swap function

Summary

in SmartVaultV3::swap, minimumAmountOut is calculated using chainlink price feeds which might return totally different values than uniswap pools. the problem is that chainlink price feeds are updated only if price leaves a certain range while uniswap pools are subject to huge and instant price changes. e.g. there could be a case where chainlink price feeds are returning 2400 usd per ETH, while due to previous ETH/USD swaps that are included before a SmartVaultV3::swap call, 1 ETH is worth 1900$ in a uniswap pool

Vulnerability Details

SmartVaultV3::swap uses calculateMinimumAmountOut function to calculate the minimum amount of out tokens that vault must receive in order to not become undercollateralized. in case that usd value of input amount is more than minimum amount of needed collateral to back minted euro, the vault must receive a minimum amount of output tokens in order to not become under-collateralized.
However, this minimum amount of tokens are calculated using chainlink price feeds which might be returning totally different values than uniswap pools.

for example, chainlink price feeds might return 10 Ethereum as minimumAmountOut worth 20,000 usd, while 10 Ethereum might worth 15,000 usd according to uniswap at time of performing the swap (lets say due to a sandwich attack). the swap still executes successfully and contract receives 10 ETH worth 5k usd less than what we expected which can make vault undercollateralized and subject to liquidation.

Impact

High - if usd value of vault collateral is less than required collateral, it can become subject to an unexpected liquidation

Tools Used

  • Manual review

Recommendations

one solution that came to my mind is to use uniswap router in order to check how much of out tokens contract must receive:

example:

uint requiredUSDtoReceive = uniswap_router.getAmountsOut(required_usd_to_receive, [usd, out token]

also make sure to check that we received the expected amount of tokens after swap:

function swap( bytes32 _inToken, bytes32 _outToken, uint256 _amount ) external onlyOwner { uint collateralValueBefore = euroCollateral(); // swap code if(minimumAmountOut > 0) require(euroCollateral() >= collateralValueBefore); }
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.