The Standard

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

Stale Data Risk in distributeAssets Function

Summary

The distributeAssets function within the LiquidationPool contract exhibits a critical vulnerability due to its reliance on potentially stale or outdated price data fetched from Chainlink oracles. This risk arises from the absence of checks to confirm the freshness and accuracy of the oracle data, a crucial factor in the contract's financial computations.

Vulnerability Details

The specific vulnerability is found in the way the function retrieves price data from Chainlink oracles using the latestRoundData method. This method, while providing the most recent price data, does not inherently guarantee the data's recency or validity. In the absence of additional checks, there is a risk that the data used might be stale, having been carried over from a previous round without any recent updates.

The problematic code is identified as follows:

// @note In this line, the contract fetches the latest asset price in USD but neglects to verify if this data is current, potentially leading to decisions made on outdated information.
(,int256 assetPriceUsd,,,) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();

Impact

The reliance on stale or incorrect price data in distributeAssets can lead to several adverse outcomes:

Miscalculated Asset Distributions: Incorrect asset prices can result in the erroneous distribution of assets, harming the protocol's fairness and accuracy.

Tools Used

Manual Review

Reference to Similar Issues in Other Protocols

Recommended Mitigation

To address this vulnerability, the following enhancements are recommended:

Validate Data Freshness:
Implement a mechanism to check the updatedAt timestamp from the latestRoundData return values. This ensures the price data is recent.

Example check:

(,int256 assetPriceUsd,, uint256 updatedAt,) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();
require(block.timestamp - updatedAt < MAX_STALE_PERIOD, "Price data is stale");

Validate Data Relevance:
Confirm that the answeredInRound value aligns with the current round ID, indicating that the data is from the latest round and not carried over from a previous one.

Example validation:

(uint80 roundID,, , , uint80 answeredInRound) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();
require(answeredInRound == roundID, "Data from a stale round");

Check Price Validity:
Ensure the retrieved price is greater than zero, indicating a valid and positive price.

require(assetPriceUsd > 0, "Invalid price data");

Handling Stale Data:
Define a protocol behavior for scenarios where the price data is determined to be stale. This could involve fallback mechanisms, alerts, or temporary suspension of certain functions to safeguard against erroneous calculations.

You can find bellow a safer implementation:

( uint80 roundId, int256 assetPriceUsd, , uint256 updateTime, uint80 answeredInRound ) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();
require(assetPriceUsd > 0, "Chainlink price <= 0");
require(updateTime != 0, "Incomplete round");
require(answeredInRound >= roundId, "Stale price");

By implementing these checks and safeguards, the distributeAssets function can significantly reduce the risk of using stale or incorrect price data, enhancing the reliability and integrity of its financial operations.

Updates

Lead Judging Commences

hrishibhat Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

Chainlink-price

hrishibhat Lead Judge almost 2 years ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

Chainlink-price

Support

FAQs

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

Give us feedback!