Incorrect L2 sequencer uptime feed integration
Description
When the L2 sequencer feed (_sequencerOracle
) is set, the getAssetPrice
function in ConcreteOracle
checks data freshness from the sequencer feed before consuming data from the price feed:
function getAssetPrice(address asset) public view override returns (uint256) {
// [...]
(, int256 price,, uint256 updatedAt,) = source.latestRoundData();
bool isFreshPrice = updatedAt >= (block.timestamp - getGracePeriodOfAsset(asset));
if (price > 0 && isFreshPrice && _isSequencerOracleFresh()) {
return _normalizePrice(source, uint256(price));
} else {
return _getAssetPriceFromFallbackOracle(asset);
}
// [...]
}
function _isSequencerOracleFresh() internal view returns (bool) {
// for L1 layers, we always return true
if (address(_sequencerOracle) == address(0)) return true;
// for L2 layers, we check if the price is fresh
(,,, uint256 updatedAt,) = _sequencerOracle.latestRoundData();
return updatedAt >= (block.timestamp - DEFAULT_GRACE_PERIOD);
}
However, L2 sequencer uptime feeds update only when the sequencer status changes. If the sequencer operates normally and the last update occurred long ago, _isSequencerOracleFresh
returns false. This causes getAssetPrice
to use the fallback oracle price instead of the primary source price, which is not the intended design.
According to the Chainlink "L2 Sequencer Uptime Feeds" documentation↗, correct integration with L2 sequencer uptime feeds requires 1) checking the sequencer status and reverting if it is down, and 2) implementing a grace period after the sequencer restarts.
Impact
The incorrect freshness check from the sequencer feed causes getAssetPrice
to use the fallback oracle price when it should use the primary source price. If the fallback oracle is unset, getAssetPrice
returns 0
, which causes reverts in calling functions.
Additionally, the missing sequencer status check allows getAssetPrice
to use stale prices. When the L2 sequencer goes down, price oracles stop updating data. Stale prices can appear fresh during sequencer downtime.
Recommendations
We recommend removing the incorrect _isSequencerOracleFresh
check and implementing the L2 sequencer uptime check specified by Chainlink.
Remediation
This issue has been acknowledged by Blueprint Finance, and a fix was implemented in commit 731f01d7↗.