First Flight #21: KittyFi

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

KittyVault::getUserVaultMeowllateralInEuros doesnt check for heartbeat or price validation

[M-01] KittyVault::getUserVaultMeowllateralInEuros doesnt check for heartbeat or price validation

Summary

Chainlink recommends that when utilizing its price feeds, developers should always verify the staleness of the data and validate the price values. The KittyVault contract fails to implement these checks, particularly when retrieving different prices from Chainlink price feeds, which can lead to inaccuracies.

Vulnerability Details

The functions getTotalMeowllateralInAave and getUserVaultMeowllateralInEuros make multiple calls to Chainlink oracles for price data but lack the necessary validations for price staleness and correctness.

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
);
}
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
);
}

Impact

Without proper validation, the contract may use incorrect prices, leading to potential issues such as users being incorrectly liquidated when they are not at risk.

Tools Used

Manual Review

Recommendations

  • Implement a heartbeat check for each price feed to ensure the data is fresh and reliable.

  • Validate that each retrieved price is greater than 0 to catch and handle invalid data points.

  • Consider adding error handling mechanisms to gracefully manage instances where price data cannot be validated.

function getUserVaultMeowllateralInEuros(address _user) external view returns (uint256) {
- (, int256 collateralToUsdPrice, , , ) = i_priceFeed.latestRoundData();
- (, int256 euroPriceFeedAns, , , ) = i_euroPriceFeed.latestRoundData();
+ (uint80 roundID, int256 collateralToUsdPrice, , uint256 updatedAt, uint80 answeredInRound) = i_priceFeed.latestRoundData();
+ require(collateralToUsdPrice > 0, "Invalid collateral price");
+ require(block.timestamp - updatedAt > HEART_BEAT , "Stale collateral price");
+ (uint80 euroRoundID, int256 euroPriceFeedAns, , uint256 euroUpdatedAt, uint80 euroAnsweredInRound) = i_euroPriceFeed.latestRoundData();
+ require(euroPriceFeedAns > 0, "Invalid euro price");
+ require(block.timestamp - euroUpdatedAt > EURO_HEART_BEAT, "Stale euro price");
uint256 collateralAns = getUserMeowllateral(_user).mulDiv(uint256(collateralToUsdPrice) * EXTRA_DECIMALS, PRECISION);
return collateralAns.mulDiv(uint256(euroPriceFeedAns) * EXTRA_DECIMALS, PRECISION);
}
Updates

Lead Judging Commences

shikhar229169 Lead Judge 11 months 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.