QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: low
Invalid

Data validation issues in ChainlinkOracle price feed implementation

Summary

The current implementation lacks essential checks for data staleness, round completion verification, and proper timestamp validation, which could lead to the consumption of invalid or stale price data.

Vulnerability Details

The current implementation in ChainlinkOracle.sol handles price feed data as follows:

function _getData() internal view override returns (int216, uint40) {
(, /*uint80 roundID*/ int data, , /*uint startedAt*/ uint timestamp, ) = /*uint80 answeredInRound*/
priceFeed.latestRoundData();
require(data > 0, "INVLDDATA");
data = data * int(10 ** normalizationFactor);
return (int216(data), uint40(timestamp)); // Overflow of data is extremely improbable and uint40 is large enough for timestamps for a very long time
}

https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/ChainlinkOracle.sol#L27-L33

The implementation only validates that the returned price is greater than zero. This single check is insufficient for ensuring price feed reliability and accuracy.

The core issue stems from ignoring critical fields returned by latestRoundData(). The AggregatorV3Interface.sol contract specifically includes these fields for validation purposes:

function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);

Impact

The contract may use outdated price data since it doesn't verify the updatedAt timestamp against the current block timestamp. This could lead to trade executions at incorrect prices.

It could also use data from an incomplete round since it doesn't verify the round's completion status through timestamp checks.

Without validating answeredInRound against roundId, the contract might use price data from an incorrect round, potentially from a previous state of the market.

Recommendations

The following implementation includes all necessary validations:

function _getData() internal view override returns (int216, uint40) {
(
uint80 roundId,
int256 data,
,
uint256 updatedAt,
uint80 answeredInRound
) = priceFeed.latestRoundData();
require(updatedAt != 0, "Incomplete round");
require(answeredInRound >= roundId, "Round not complete");
require(block.timestamp - updatedAt < 60 minutes, "Stale price feed");// if 1 hour is the staleness check
require(data > 0, "Invalid price");
data = data * int(10 ** normalizationFactor);
return (int216(data), uint40(updatedAt));
}
Updates

Lead Judging Commences

n0kto Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

invalid_chainlink_staled_data_updateAt_roundId_known_issue

LightChaser: ## [Medium-4] Insufficient oracle validation

Support

FAQs

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

Give us feedback!