First Flight #21: KittyFi

First Flight #21
Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: medium
Valid

Lack of essential stale check in `getUserVaultMeowllateralInEuros()` and `getTotalMeowllateralInAave()`

Description:

On the KittyVault.sol in both the getUserVaultMeowllateralInEuros() and getTotalMeowllateralInAave() we are using the latestRoundData(), but there is no check if the return value indicates stale data.

function getUserVaultMeowllateralInEuros(address _user) external view returns (uint256) {
@> (, int256 collateralToUsdPrice, , , ) = i_priceFeed.latestRoundData();
@> (, int256 euroPriceFeedAns, , ,) = i_euroPriceFeed.latestRoundData();
uint256 collateralAns = getUserMeowllateral(_user).mulDiv(uint256(collateralToUsdPrice) * EXTRA_DECIMALS, PRECISION);
return collateralAns.mulDiv(uint256(euroPriceFeedAns) * EXTRA_DECIMALS, PRECISION);
}
function getTotalMeowllateralInAave() public view returns (uint256) {
(uint256 totalCollateralBase, , , , , ) = i_aavePool.getUserAccountData(address(this));
@> (, int256 collateralToUsdPrice, , , ) = i_priceFeed.latestRoundData();
return totalCollateralBase.mulDiv(PRECISION, uint256(collateralToUsdPrice) * EXTRA_DECIMALS);
}

Impact:

This could lead to stale prices which means that prices would be executed that don't reflect the current pricing resulting in a potential loss of funds for the user and/or the protocol

Tools Used:

Manual Review.

Recommended Mitigation:

The updatedAt parameter should be returned from latestRoundData() and compare it to a staleness threshold.

function getUserVaultMeowllateralInEuros(address _user) external view returns (uint256) {
- (, int256 collateralToUsdPrice, , , ) = i_priceFeed.latestRoundData();
+ (, int256 collateralToUsdPrice, , uint256 updatedAt,) = i_priceFeed.latestRoundData();
- (, int256 euroPriceFeedAns, , ,) = i_euroPriceFeed.latestRoundData();
+ (, int256 euroPriceFeedAns, , uint256 updatedAt,) = i_euroPriceFeed.latestRoundData();
+ if (updatedAt < block.timestamp - 60 * 60 ) {
+ revert("stale price feed");
+ }
uint256 collateralAns = getUserMeowllateral(_user).mulDiv(uint256(collateralToUsdPrice) * EXTRA_DECIMALS, PRECISION);
return collateralAns.mulDiv(uint256(euroPriceFeedAns) * EXTRA_DECIMALS, PRECISION);
}
function getTotalMeowllateralInAave() public view returns (uint256) {
(uint256 totalCollateralBase, , , , , ) = i_aavePool.getUserAccountData(address(this));
- (, int256 collateralToUsdPrice, , , ) = i_priceFeed.latestRoundData();
+ (, int256 collateralToUsdPrice, , uint256 updatedAt,) = i_priceFeed.latestRoundData();
+ if (updatedAt < block.timestamp - 60 * 60 ) {
+ revert("stale price feed");
+ }
return totalCollateralBase.mulDiv(PRECISION, uint256(collateralToUsdPrice) * EXTRA_DECIMALS);
}
Updates

Lead Judging Commences

shikhar229169 Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Stale Price from Chainlink Datafeed

Support

FAQs

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