OracleLib

contracts/src/lib/OracleLib.sol · Solidity 0.8.26

An internal library that performs a single Chainlink price read behind two safety layers: a staleness check and an Arbitrum-Orbit sequencer-uptime guard. Its defining design choice is that it returns stale = true instead of reverting on any anomaly — so NAV pricing degrades gracefully while in-kind mint/redeem (which never call it) stay fully functional.

It declares its own minimal IAggregatorV3 interface (decimals(), latestRoundData()) and has no state and no imports.

Function

function readPrice(address feed, uint48 maxStaleness_, address seqFeed, uint48 grace)
    internal
    view
    returns (uint256 price1e18, bool stale)
Parameter Meaning
feed Chainlink price feed to read
maxStaleness_ Maximum allowed age of the price, in seconds
seqFeed Sequencer-uptime feed; address(0) disables the sequencer check (fork/dev)
grace Grace period in seconds after a sequencer restart

Returns price1e18 (price normalized to 1e18 scale) and stale (true if the reading must not be trusted). This function never reverts — every failure mode returns (0, true).

Logic

Sequencer guard (only if seqFeed != address(0)), reads the sequencer feed's latestRoundData and returns (0, true) if:

  • seqAnswer != 0 — sequencer is down; or
  • seqStartedAt > block.timestamp — future timestamp; or
  • block.timestamp - seqStartedAt <= grace — still inside the grace window after restart.

Price read — reads feed.latestRoundData() and returns (0, true) if:

  • answer <= 0 || updatedAt == 0; or
  • updatedAt > block.timestamp — future timestamp; or
  • block.timestamp - updatedAt > maxStaleness_ — too old; or
  • feed.decimals() > 18 — defensive guard against underflow in the normalization below.

Normalization — on success returns:

return (uint256(answer) * 10 ** (18 - dec), false);

Why "stale, not revert"

A basket's nav() sums each constituent's value; if any leg is stale, it sets the overall stale flag and that leg contributes price = 0. This means NAV can be understated while stale, which is why NAV is never used to gate mint/redeem — only for display, zap pricing, and fee accounting. The oracle can degrade without ever freezing the vault's core deposit/withdraw guarantees.