DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: medium
Valid

Inadequate checks to confirm the correct status of the sequecnce/sequecncerUptimeFeed in ChainlinkUtil.getPrice()

Summary

sequencerUptimeFeed needs to check for startedAt!=0 , to prevent “invalid round”

Vulnerability Details

in ChainlinkUtil.getPrice()
we will checkOracleSequencerUptimeFeedIsDown

function getPrice(
IAggregatorV3 priceFeed,
uint32 priceFeedHeartbeatSeconds,
IAggregatorV3 sequencerUptimeFeed
)
...
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 {

The chainlink docs say that sequencerUptimeFeed can return a 0 value for startedAt if it is called during an "invalid round".

Please note that an "invalid round" is described to mean there was a problem updating the sequencer's status, possibly due to network issues or problems with data from oracles, and is shown by a startedAt time of 0 and answer is 0. Further explanation can be seen as given by an official chainlink engineer as seen here in the chainlink public discord

https://discord.com/channels/592041321326182401/605768708266131456/1213847312141525002

as startedAt will be 0, the arithmetic operation block.timestamp - startedAt will result in a value greater than GRACE_PERIOD_TIME (which is hardcoded to be 3600) i.e block.timestamp = 1719739032, so 1719739032 - 0 = 1719739032 which is bigger than 3600. The code won't revert.

Imagine a case where a round starts, at the beginning startedAt is recorded to be 0, and answer, the initial status is set to be 0. Note that docs say that if answer = 0, sequencer is up, if equals to 1, sequencer is down. But in this case here, answer and startedAt can be 0 initially, till after all data is gotten from oracles and update is confirmed then the values are reset to the correct values that show the correct status of the sequencer.

Note: The above description is from https://github.com/code-423n4/2024-06-size-findings/issues/209

Impact

inadequate checks to confirm the correct status of the sequecncer/sequecncerUptimeFeed in ChainlinkUtil.getPrice() contract will cause getPrice() to not revert even when the sequcncer uptime feed is not updated or is called in an invalid round.

Tools Used

Recommendations

add a check that reverts if startedAt is returned as 0.

function getPrice(
IAggregatorV3 priceFeed,
uint32 priceFeedHeartbeatSeconds,
IAggregatorV3 sequencerUptimeFeed
)
...
if (address(sequencerUptimeFeed) != address(0)) {
try sequencerUptimeFeed.latestRoundData() returns (
uint80, int256 answer, uint256 startedAt, uint256, uint80
) {
- bool isSequencerUp = answer == 0;
+ bool isSequencerUp = (answer == 0 || startedAt==0);
if (!isSequencerUp) {
revert Errors.OracleSequencerUptimeFeedIsDown(address(sequencerUptimeFeed));
}
uint256 timeSinceUp = block.timestamp - startedAt;
if (timeSinceUp <= Constants.SEQUENCER_GRACE_PERIOD_TIME) {
revert Errors.GracePeriodNotOver();
}
} catch {
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Inadequate implementation of sequencer check

Support

FAQs

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