NAV Oracle
NAVOracle is public infrastructure: an onchain view contract that values any Basquets basket in USD, with explicit freshness semantics. It’s what our own periphery uses, and it’s designed for you to build on: lending markets listing basket collateral, wallets showing balances, structured products, dashboards.
Interface
struct NAVResult {
uint256 navPerToken; // USD, 8 decimals (Chainlink convention)
uint256 oldestUpdate; // updatedAt of the most stale component feed
bool fresh; // true iff every freshness check passed
}
/// Always returns; check .fresh before using the value for anything value-bearing.
function nav(address basket) external view returns (NAVResult memory);
/// Reverts unless fresh. Use this in anything that moves value.
function navStrict(address basket) external view returns (uint256);
/// Value one component amount; same freshness semantics.
function componentValue(address token, uint256 amount)
external view returns (uint256 value, bool fresh);
Freshness semantics
fresh == true requires, for every component of the basket:
- Sequencer up: the L2 sequencer uptime feed reports up, and a grace period has elapsed since restart (skipped until the feed address is published; see Addresses).
- Sane answer:
answer > 0,updatedAt > 0. - Not stale:
block.timestamp − updatedAt ≤ heartbeatfor that feed (per the component registry, sourced from Chainlink’s feed page). - No corporate action in progress: the stock token’s
oraclePaused()is false.
Integration rules
- Use
navStrict()for anything value-bearing. Liquidations, borrow limits, settlement: never the unchecked value. nav()withfresh == falseis a display value. Show it as “last known NAV”; US stock feeds update 24/5, so it goes stale every weekend by design. Stale-on-weekends is normal operation, not an outage.- Never apply
uiMultiplieryourself. Chainlink’s Robinhood feeds already include the corporate-action multiplier. Multiplying twice is the classic integration bug on this chain; the oracle uses feed prices as returned, and so should any code of yours that touches the feeds directly. - Expect reverts, handle them as “wait.” During corporate actions and weekends,
navStrictreverts. The correct integrator behavior is almost always to queue and retry, not to fall back to a stale price. - Decimals: NAV is 8 decimals (Chainlink convention). Basket tokens are 18. USDG is 6. Read
decimals(); never assume.
Collateral integration checklist
Considering basket tokens as collateral? The properties that matter:
- Baskets are fully backed by onchain component balances, verifiable at any time via
components()andbalanceOf. - No rebasing, ever. Balances only change on transfer, and supply only on mint/redeem/fee-accrual.
- Fail-closed valuation (this oracle) means you never liquidate against a price that doesn’t exist.
- The residual risks are the component tokens’ issuer powers; read Security before parameterizing LTVs.