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
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.
High - if usd value of vault collateral is less than required collateral, it can become subject to an unexpected liquidation
Manual review
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);
}
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.