The Standard

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

The status of the Arbitrum sequencer in Chainlink feeds is not checked.

Summary

Given that the contract will be deployed on Arbitrum, it's important to ensure that the prices provided are not falsely perceived as fresh particularly in scenarios where the sequencer might be non-operational. Hence, a critical step involves confirming the active status of the sequencer before trusting the data returned by the oracle.

Vulnerability Details

In the event of an Arbitrum Sequencer outage, the oracle data may become outdated, potentially leading to staleness. There is no check to ensure if the Arbitrum sequencer is indeed active. You can review Chainlink docs on L2 Sequencer Uptime Feeds for more details on this. https://docs.chain.link/data-feeds/l2-sequencer-feeds

Impact

In the scenario where the Arbitrum sequencer experiences an outage, stale prices will be used.

Tools Used

Manual Review

Recommendations

There is a code example on Chainlink docs for this scenario: https://docs.chain.link/data-feeds/l2-sequencer-feeds#example-code.

contract DataConsumerWithSequencerCheck {
AggregatorV2V3Interface internal dataFeed;
AggregatorV2V3Interface internal sequencerUptimeFeed;
uint256 private constant GRACE_PERIOD_TIME = 3600;
error SequencerDown();
error GracePeriodNotOver();
constructor() {
dataFeed = AggregatorV2V3Interface(
0xC16679B963CeB52089aD2d95312A5b85E318e9d2
);
sequencerUptimeFeed = AggregatorV2V3Interface(
0x4C4814aa04433e0FB31310379a4D6946D5e1D353
);
}
function getChainlinkDataFeedLatestAnswer() public view returns (int) {
// prettier-ignore
(
/*uint80 roundID*/,
int256 answer,
uint256 startedAt,
/*uint256 updatedAt*/,
/*uint80 answeredInRound*/
) = sequencerUptimeFeed.latestRoundData();
// Answer == 0: Sequencer is up
// Answer == 1: Sequencer is down
bool isSequencerUp = answer == 0;
if (!isSequencerUp) {
revert SequencerDown();
}
// Make sure the grace period has passed after the
// sequencer is back up.
uint256 timeSinceUp = block.timestamp - startedAt;
if (timeSinceUp <= GRACE_PERIOD_TIME) {
revert GracePeriodNotOver();
}
// prettier-ignore
(
/*uint80 roundID*/,
int data,
/*uint startedAt*/,
/*uint timeStamp*/,
/*uint80 answeredInRound*/
) = dataFeed.latestRoundData();
return data;
}
}
Updates

Lead Judging Commences

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Arbitrum-sequncer

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

Arbitrum-sequncer

Support

FAQs

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