Lack of checking data returned from Chainlink oracle feed
LiquidationPool#distributeAssets() function fetches the latestRoundData() from a Chainlink oracle feed. However, neither round completeness nor the quoted timestamp are checked to ensure that the reported price is not stale.
(,int256 assetPriceUsd,,,) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();
uint256 _portion = asset.amount * _positionStake / stakeTotal;
uint256 costInEuros = _portion * 10 ** (18 - asset.token.dec) * uint256(assetPriceUsd) / uint256(priceEurUsd)
* _hundredPC / _collateralRate;
If stale price is lower than real one, holders might get more assets token based on TST and EUROs token they have.
If stale price is upper than real one, holders might get less assets token based on TST and EUROs token they have, which is the worst case.
Manual review
Validate data feed for round completeness. If assets failed to validate, skip it, and go to other token;
(uint80 roundID,int256 assetPriceUsd,,uint256 updatedAt,uint80 answeredInRound) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();
+ if(answeredInRound >= roundID) continue; // <-- check for round completeness
+ if((block.timestamp - updatedAt)>= MaxDelay) continue; // <-- check timestamp
Better solution is using other off-chain oracle providers, or using Uniswap's TWAP when chainlink failed to get newest price.
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.