🗯️Chainlink: Using latestAnswer instead of latestRoundData

In UniswapV3Oracle.sol, the latestAnswer method is invoked to retrieve the most recent WETH price. While this method provides the last recorded value, it does not offer any mechanism to verify the timeliness of this data, which is crucial for maintaining the accuracy and reliability of price information used in transactions.

An alternative approach would be to utilize the latestRoundData method, as it allows for additional validations to ensure that the price data is current and reliable. Below is a code snippet demonstrating how to implement these additional checks:

solidityCopy code(
    roundId,
    rawPrice,
    ,
    updateTime,
    answeredInRound
) = AggregatorV3Interface(XXXXX).latestRoundData();
require(rawPrice > 0, "Chainlink price <= 0");
require(updateTime != 0, "Incomplete round");
require(answeredInRound >= roundId, "Stale price");

With these checks, you can ensure not only that the price is greater than zero but also that it comes from a completed round and is not outdated. This additional layer of validation provides a more secure and reliable price for use in transactions and other critical operations.

For further details on verifying whether the answer from a round is being carried over from a previous one, refer to Chainlink's official documentation.

Vulnerability Details

The EIP1271Wallet contract utilizes the deprecated latestAnswer method from the Chainlink API:

“This API is deprecated. Please see the API Reference for the latest Price Feed API.” - Chainlink Docs

This deprecated function presents risks as it returns '0' without throwing an error if no answer is available. Moreover, it reports latestAnswer with varying decimals: 18 decimals for crypto quotes and 8 for FX quotes, leading to inconsistency (detailed in the Chainlink FAQ). It’s advisable to dynamically fetch the decimals from the oracle to avoid hard-coding and potential discrepancies in the contract.

To resolve this vulnerability, replace the latestAnswer method with the latestRoundData function for price retrieval. Additionally, incorporate checks and appropriate revert messages for stale prices or incomplete rounds to enhance contract robustness:

solidityCopy code(uint80 roundID, int256 price, , uint256 timeStamp, uint80 answeredInRound) = priceOracle.latestRoundData();
require(answeredInRound >= roundID, "Stale price detected");
require(timeStamp != 0, "Incomplete round detected");

These amendments ensure accurate, consistent, and timely price data retrieval, mitigating risks associated with deprecated functions and data inconsistencies.

Last updated