DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: low
Invalid

`getPrice` can still accept stale prices when `sequencerUptimeFeed` is not configured

Summary

The current implementation of getPrice does not check if the sequencerUptimeFeed is not configured and could lead to wrong or stale prices in such situations.

Vulnerability Details

The sequencerUptimeFeed is a core invariant in relation to the Arbitrum chain, which is said to be the deployment chain and should be handle with outmost care. The getPrice function does check if the isSequencerUp is true, meaning the sequencer is up, otherwise it should revert with an error OracleSequencerUptimeFeedIsDown.

However, in situations whereby the admin have not yet configured the sequencerUptimeFeed, the above checks will not be made and it would lead to chainlink price feed returning a stale price thereby affecting the overall health system while also breaking the invariant.

It is eminent to implement a proper logic that handles such cases in situations whereby the sequencerUptimeFeed has not yet been configured.

Impact

Chainlink price feed might return stale prices or wrong data.

POC

function getPrice(
IAggregatorV3 priceFeed,
uint32 priceFeedHeartbeatSeconds,
IAggregatorV3 sequencerUptimeFeed
)
internal
view
returns (UD60x18 price)
{
uint8 priceDecimals = priceFeed.decimals();
// should revert if priceDecimals > 18
if (priceDecimals > Constants.SYSTEM_DECIMALS) {
revert Errors.InvalidOracleReturn();
}
if (address(sequencerUptimeFeed) != address(0)) {
try sequencerUptimeFeed.latestRoundData() returns (
uint80, int256 answer, uint256 startedAt, uint256, uint80
) {
bool isSequencerUp = answer == 0;
if (!isSequencerUp) {
revert Errors.OracleSequencerUptimeFeedIsDown(address(sequencerUptimeFeed));
}
uint256 timeSinceUp = block.timestamp - startedAt;
if (timeSinceUp <= Constants.SEQUENCER_GRACE_PERIOD_TIME) {
revert Errors.GracePeriodNotOver();
}
} catch {
revert Errors.InvalidSequencerUptimeFeedReturn();
}
} //@audit add an else statement to revert if sequener not configured
try priceFeed.latestRoundData() returns (uint80, int256 answer, uint256, uint256 updatedAt, uint80) {
if (block.timestamp - updatedAt > priceFeedHeartbeatSeconds) {
revert Errors.OraclePriceFeedHeartbeat(address(priceFeed));
}
IOffchainAggregator aggregator = IOffchainAggregator(priceFeed.aggregator());
int192 minAnswer = aggregator.minAnswer();
int192 maxAnswer = aggregator.maxAnswer();
if (answer <= minAnswer || answer >= maxAnswer) {
revert Errors.OraclePriceFeedOutOfRange(address(priceFeed));
}
price = ud60x18(answer.toUint256() * 10 ** (Constants.SYSTEM_DECIMALS - priceDecimals));
} catch {
revert Errors.InvalidOracleReturn();
}
}

Tools Used

Manual review

Recommendations

+ else {
+ revert Errors.OracleSequencerUptimeFeedIsNotConfigured();
+ }
Updates

Lead Judging Commences

inallhonesty Lead Judge
11 months ago
inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

`sequencerUptimeFeed` has not yet been configured

Support

FAQs

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