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

Arbitrum uptime sequencer should check `startedAt != 0`.

Summary

Arbitrum uptime sequencer should check startedAt != 0.

Vulnerability Details

According to Chainlink docs, https://docs.chain.link/data-feeds/l2-sequencer-feeds#example-code, the uptime sequencer on Arbitrum should check for startedAt != 0 to avoid uninitialization issues.

The startedAt variable returns 0 only on Arbitrum when the Sequencer Uptime contract is not yet initialized. For L2 chains other than Arbitrum, startedAt is set to block.timestamp on construction and startedAt is never 0. After the feed begins rounds, the startedAt timestamp will always indicate when the sequencer feed last changed status.

https://github.com/CodeHawks-Contests/2025-02-gamma/blob/main/contracts/KeeperProxy.sol#L48

function _validatePrice(address perpVault, MarketPrices memory prices) internal view {
// L2 Sequencer check
(
/*uint80 roundID*/,
int256 answer,
@> uint256 startedAt,
/*uint256 updatedAt*/,
/*uint80 answeredInRound*/
) = AggregatorV2V3Interface(sequencerUptimeFeed).latestRoundData();
bool isSequencerUp = answer == 0;
require(isSequencerUp, "sequencer is down");
// Make sure the grace period has passed after the sequencer is back up.
uint256 timeSinceUp = block.timestamp - startedAt;
require(timeSinceUp > GRACE_PERIOD_TIME, "Grace period is not over");
address market = IPerpetualVault(perpVault).market();
IVaultReader reader = IPerpetualVault(perpVault).vaultReader();
MarketProps memory marketData = reader.getMarket(market);
_check(marketData.indexToken, prices.indexTokenPrice.min);
_check(marketData.indexToken, prices.indexTokenPrice.max);
_check(marketData.longToken, prices.indexTokenPrice.min);
_check(marketData.longToken, prices.indexTokenPrice.max);
_check(marketData.shortToken, prices.shortTokenPrice.min);
_check(marketData.shortToken, prices.shortTokenPrice.max);
}

Impact

Uptime sequencer may be unready, and a wrong oracle answer would be used.

Tools Used

N/A

Recommendations

Check startedAt != 0 for uptime sequencer.

Updates

Lead Judging Commences

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

invalid_sequencerUptimeFeed_startedAt_0_no_roundId

startedAt is only 0 when contract is not initialized on Arbitrum, but it is already initialized on Arbitrum. startedAt is sufficient for the protocol, it does not need roundID. Current documentation of Chainlink does not have this sentence: “This timestamp returns `0` if a round is invalid.“

Support

FAQs

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