stETH, lsETH & OETH (CrossRate)
Generic custom price feed for an asset Y that has no direct Y/USD feed but is quoted in a base asset X that does.
Generic custom price feed for an asset Y that has no direct Y/USD feed but is quoted in a base asset X that does. The price is the cross-rate of the NAV's own X/USD base price and a Chainlink Y/X feed. The shared CrossRateCustomPriceFeed base is instantiated as one named per-token contract for each asset that needs it. On Ethereum mainnet the primary instances are lsETH (lsETH_CustomPriceFeed, Liquid Collective — Y/X is Chainlink's LsETH/ETH Exchange Rate) and OETH (OETH_CustomPriceFeed) — each Y/USD = ETH/USD × Y/ETH, where the cross-rate is the asset's sole pricing feed.
stETH is not priced by a cross-rate. Its primary is a fundamental unit-rate feed (1.0 × ETH/USD), matching wstETH and eETH; the market stETH/ETH cross-rate is registered as a monitor (stETHCrossRate), deployed from the generic base rather than a named per-token subclass. This page describes how that monitor computes its price — it does not set stETH's NAV value.
Source: CrossRateCustomPriceFeed.sol
The same base also backs divergence monitors for the fundamental LST/LRT primaries — ezETH, ETHx, osETH, and rETH (ezETH/ETHx/osETH/rETH_CrossRateCustomPriceFeed), where the Y/ETH leg is an independent market feed. Those assets are priced by a fundamental protocol-rate primary (ezETH, ETHx, osETH, rETH); the cross-rate is registered as a monitor feed, so a market depeg makes it diverge from the fundamental primary and NAV flags the asset irregular — it never prices NAV. The L2 deployments use the same pattern (e.g. weETHCrossRate, rsETHCrossRate monitors on Arbitrum/Base).
Approach
NAV base X/USD (getPriceDataNoDivergence(WETH)) × Chainlink Y/X
The base/USD term is sourced from the NAV's own selector — see Base/USD from the NAV's own selector.
Price calculation
X/USD
NAV base — getPriceDataNoDivergence(WETH) (8 dec)
the NAV's primary ETH/USD price
Y/X
Chainlink Y/X feed (latestRoundData)
Underlying Y quoted in X
The Y/X leg is a Chainlink feed; the X/USD (ETH/USD) leg is the NAV's primary base price. The divisor is 10 ** yToX.decimals(), which cancels the Y/X feed's decimals so the result keeps the X/USD leg's scale. Output is 8 decimals (inherited from the X/USD leg via _decimals).
For the mainnet instances, X is ETH (ETH/USD via the NAV base) and Y is stETH, lsETH, or OETH respectively (a stETH/ETH, LsETH/ETH, or OETH/ETH feed).
Constructor
underlyingAsset_
The asset Y whose USD price is returned (stETH, lsETH, or OETH)
yToXFeed_
Chainlink Y/X aggregator (e.g. stETH/ETH or OETH/ETH)
yToXHeartbeat_
Staleness window (seconds) for the Y/X feed
nav_
NAVCalculator (proxy) — supplies the base asset's USD price via getPriceDataNoDivergence
baseAsset_
The registered base asset whose USD price is read (WETH)
Staleness
The Y/X heartbeat is checked directly. getLatestPrice() returns stale = true if the Y/X feed satisfies block.timestamp − updatedAt ≥ heartbeat, if either leg's answer is ≤ 0, if the Y/X updatedAt is in the future (clamped to block.timestamp), or if the NAV reports the base asset (WETH) primary feed stale. The base leg's updatedAt comes from the NAV's selected feed. The reported updatedAt is the older of the two legs.
Chains
On Ethereum, as primary feeds: lsETH and OETH, each configured with the matching Y/X feed. As monitor feeds (same base contract, market Y/ETH leg), watching their fundamental primaries: stETHCrossRate, ezETHCrossRate, ezETHCrossRateMarket, ETHxCrossRate, osETHCrossRate, and rETHCrossRate — ezETH carries two because its original monitor's rate leg stopped being a market feed.
On the L2s, all monitors: weETHCrossRate, ezETHCrossRate and rsETHCrossRate on Arbitrum, and weETHCrossRate on Base. Gnosis has no cross-rate instance.
Every one of these takes an external yToXFeed, so each is covered by the pre-deploy rate-feed guard — pair identity where the provider's description() names the pair, and a declared $UNVERIFIABLE exemption plus a plausibility band where it does not.
Last updated