Price Oracle Contracts (Harbor Aggregators)
The Harbor Price Aggregator system provides validated price feeds for wrapped collateral tokens and their underlying assets, combining Chainlink price feeds with rate providers to deliver accurate pricing data across multiple chains.
Repository: harbor-price-aggregators
Overview
Harbor uses a system of price aggregators (HarborAggregator_v3 and HarborAggregator_v4) that combine:
- Chainlink Price Feeds: For underlying asset prices (ETH/USD, BTC/USD, EUR/USD, stock prices, etc.)
- Rate Providers: For wrapped token exchange rates (fxSAVE, wstETH, sUSDe)
- Price Validation: Staleness checks, heartbeat validation (42-second tolerance), and price bounds
- Multi-Chain Support: Deployed on Ethereum Mainnet, Arbitrum, Base, and MegaETH
Contract Architecture
Base Contracts
HarborAggregator_v3:
- Immutable Configuration: Feed addresses, heartbeats, and rate sources are constructor parameters
- Upgradeable: Uses UUPS (Universal Upgradeable Proxy Standard) pattern via BaoFactory
- Ownership: Fixed owner address (immutable)
- Identity: Provides
baseName(),quoteName(), andoracleName()for identification
HarborAggregator_v4:
- Direct Deployments: Immutable contracts (no proxy pattern)
- Same Core Logic: Uses same price calculation libraries as v3
- Optimized: For simpler oracle pairs (direct feeds)
Oracle Types by Chain
Harbor price oracles are deployed across multiple chains with different configurations:
Mainnet (36 oracles):
- fxUSD Pairs: Single-feed oracles (fxUSD/ETH, fxUSD/BTC, fxUSD/EUR, fxUSD/GOLD, fxUSD/SILVER, fxUSD/MCAP)
- stETH Pairs: Double-feed oracles (stETH/BTC, stETH/EUR, stETH/GOLD, stETH/SILVER, stETH/MCAP)
- Leveraged Token Oracles: USD-denominated prices for leveraged tokens (hsfxUSD-, hsstETH-)
- sUSDe Pairs: v4 oracles for sUSDe collateral (sUSDe/BTC, sUSDe/ETH, sUSDe/EUR, etc.)
- Direct Feeds: wstETH/USD, wBTC/USD, tBTC/USD, PAXG/USD
Arbitrum (20 oracles):
- USDE Stock Indices: USDE/AAPL, USDE/AMZN, USDE/GOOGL, USDE/META, USDE/MSFT, USDE/NVDA, USDE/SPY, USDE/TSLA, USDE/MAG7, USDE/MAG7.i26
- stETH Stock Indices: stETH/AAPL, stETH/AMZN, stETH/GOOGL, stETH/META, stETH/MSFT, stETH/NVDA, stETH/SPY, stETH/TSLA, stETH/MAG7, stETH/MAG7.i26
Base (1 oracle):
- stETH/BOM5: Bag of Memes index (DOGE, SHIB, PEPE, TRUMP, WIF with supply normalization)
MegaETH (6 oracles):
- Direct Feeds: BTC/USD, wstETH/USD, USDMY pairs
For detailed oracle listings, addresses, and configurations per chain, see the chain-specific pages.
Key Functions
Price Query
latestAnswer() returns (uint256 minUnderlyingPrice, uint256 maxUnderlyingPrice, uint256 minWrappedRate, uint256 maxWrappedRate)
Returns validated price and rate information.
Returns:
minUnderlyingPrice: Minimum underlying asset price (18 decimals)maxUnderlyingPrice: Maximum underlying asset price (18 decimals)minWrappedRate: Minimum wrapped token rate (18 decimals)maxWrappedRate: Maximum wrapped token rate (18 decimals)
Note: Currently, min and max values are the same (no price bounds), but the interface supports future price bounds.
Identity Functions
baseName() returns (string)- Base asset name (e.g., "fxUSD", "stETH")quoteName() returns (string)- Quote asset name (e.g., "ETH", "BTC", "EUR")oracleName() returns (string)- Full oracle name (e.g., "fxUSD/ETH")rateProvider() returns (address)- Address of rate provider (fxSAVE or wstETH)version() returns (uint256)- Oracle version (3)
Oracle Types
Single Feed Oracles (fxUSD Pairs)
For fxUSD-based markets:
Components:
- FXSAVE: Rate provider contract (fxSAVE vault)
- PRICE_FEED: Single Chainlink feed (e.g., ETH/USD, BTC/USD)
- PRICE_FEED_HEARTBEAT: Maximum staleness threshold
- PRICE_DIVISOR: Divisor for price normalization (typically 1 or 1e12)
- INVERT_PRICE: Whether to invert the price feed
Price Calculation:
- Gets rate from fxSAVE using
ChainlinkRateLib.getRate():rate = FXSAVE.getRate() - Gets price from Chainlink feed using
ChainlinkFeedLib(with validation and optional inversion) - Returns:
(price, price, rate, rate)
Libraries Used:
ChainlinkRateLib: For rate retrieval and validationChainlinkFeedLib: For feed data retrieval and staleness checks
Example: Aggregator_fxUSD_ETH
- Uses fxSAVE for fxUSD rate (via
ChainlinkRateLib) - Uses ETH/USD Chainlink feed (inverted to get USD/ETH)
- Returns fxUSD/ETH price
Double Feed Oracles (stETH Pairs)
For stETH-based markets:
Components:
- WSTETH: Rate provider contract (wrapped stETH)
- FIRST_FEED: First Chainlink feed (e.g., ETH/USD)
- SECOND_FEED: Second Chainlink feed (e.g., BTC/USD)
- FIRST_FEED_HEARTBEAT: Staleness threshold for first feed
- SECOND_FEED_HEARTBEAT: Staleness threshold for second feed
- PRICE_DIVISOR: Divisor for price normalization
- INVERT_PRICE: Whether to invert the final price
Price Calculation:
- Gets rate from wstETH using
ChainlinkRateLib.getRate():rate = WSTETH.getRate() - Gets prices from both feeds using
ChainlinkFeedLiband divides:price = (firstFeedPrice / secondFeedPrice) / divisor - Returns:
(price, price, rate, rate)
Libraries Used:
ChainlinkRateLib: For rate retrieval and validationChainlinkFeedLib: For feed data retrieval and staleness checksDoubleFeedPriceLib: For combining two feeds (division-based)
Example: Aggregator_stETH_BTC
- Uses wstETH for stETH rate (via
ChainlinkRateLib) - Uses ETH/USD and BTC/USD Chainlink feeds
- Calculates:
(ETH/USD) / (BTC/USD) = ETH/BTC - Returns stETH/BTC price
Multi-Feed Oracles (Stock Indices)
For markets requiring multiple price feeds (e.g., stock indices):
Components:
- Rate Provider: fxSAVE or wstETH (depending on base asset)
- FEEDS: Array of Chainlink feeds (e.g., AAPL/USD, MSFT/USD, etc.)
- FEED_DECIMALS: Array of decimals for each feed
- FEED_HEARTBEATS: Array of heartbeat thresholds for each feed
- NORMALIZATION_FACTORS: (Optional) Array of normalization factors for weighted averages
- DIVISOR: (Optional) Custom divisor for price calculation
Price Calculation Strategies:
-
Sum Strategy (
MultiFeedSumPriceLib):- Sums all feed prices:
price = sum(feed_prices) - Used for index calculations where prices are summed
- Sums all feed prices:
-
Average Strategy (
MultiFeedDivPriceLib):- Sums and divides by feed count:
price = sum(feed_prices) / feed_count - Used for simple average calculations
- Sums and divides by feed count:
-
Normalized Average Strategy (
MultiFeedNormalizedPriceLib):- Weighted average with normalization factors:
price = sum(normalized_prices) / feed_count - Used for market-cap weighted or supply-adjusted averages
- Weighted average with normalization factors:
Libraries Used:
ChainlinkRateLib: For rate retrievalMultiFeedSumPriceLib: For summing multiple feedsMultiFeedDivPriceLib: For sum-and-divide calculationsMultiFeedNormalizedPriceLib: For normalized weighted averages
Example: Aggregator_stETH_MCAP (Market Cap Index)
- Uses wstETH for stETH rate
- Uses multiple stock price feeds (AAPL, MSFT, TSLA, etc.)
- Calculates normalized average using market cap weights
- Returns stETH/MCAP price
Rate Providers
fxSAVE Rate Provider
For fxUSD pairs, the rate comes from the fxSAVE vault:
- Interface:
IFxSAVE(ERC4626 vault) - Rate:
FXSAVE.getRate()- Exchange rate of fxSAVE shares to underlying assets - Purpose: Accounts for yield accrual in fxSAVE vault
wstETH Rate Provider
For stETH pairs, the rate comes from wrapped stETH:
- Interface:
IWstETH - Rate:
WSTETH.getRate()- Exchange rate of wstETH to stETH - Purpose: Accounts for staking rewards accrual
Price Calculation Libraries
The Harbor aggregator system uses several internal libraries for price calculations and validation:
ChainlinkRateLib
Library for retrieving and validating rates from Chainlink feeds.
Key Features:
- Rate Normalization: Normalizes rates to 18 decimals regardless of feed decimals
- Staleness Validation: Validates feed freshness using heartbeat thresholds (default: 24 hours)
- Bounds Validation: Validates rates are within acceptable bounds (default: 1e18 to 2e18)
- Error Handling: Reverts with specific errors for invalid rates or stale feeds
Functions:
getRate(AggregatorV3Interface feed): Get rate with default validationgetRate(feed, feedDecimals, minRate, maxRate, maxAge): Get rate with custom validation
Default Constants:
DEFAULT_MIN_RATE: 1e18DEFAULT_MAX_RATE: 2e18DEFAULT_MAX_AGE: 86,400 seconds (24 hours)
Errors:
InvalidRate(uint256 rate): Rate is invalid (negative, zero, or out of bounds)StaleRateSource(address source, uint256 updatedAt): Feed data is stale
MultiFeedSumPriceLib
Library for summing prices from multiple Chainlink feeds.
Key Features:
- Multi-Feed Aggregation: Sums prices from up to 50 feeds
- Individual Validation: Each feed is validated independently for staleness
- Normalization: All feed prices normalized to 18 decimals before summing
- Array Validation: Ensures feed arrays match in length
Function:
getPrice(feeds, feedDecimals, feedHeartbeats): Returns sum of all feed prices
Errors:
EmptyFeeds(): No feeds providedInvalidFeedCount(uint256 count): Feed count exceeds limit (50) or array length mismatch
Use Case: Used for aggregating multiple price sources (e.g., summing multiple stock prices for an index)
MultiFeedDivPriceLib
Library for summing prices from multiple feeds and dividing by a custom divisor.
Key Features:
- Custom Divisor: Allows dividing sum by a custom value (e.g., feed count for average, or index divisor)
- Same Validation: Uses same validation as
MultiFeedSumPriceLib - Flexible Calculation:
price = sum / divisor
Function:
getPrice(feeds, feedDecimals, feedHeartbeats, divisor): Returnssum / divisor
Use Case: Used for calculating average prices or indexed values where a divisor is needed
MultiFeedNormalizedPriceLib
Library for calculating normalized average prices from multiple feeds.
Key Features:
- Normalization Factors: Each feed can have a custom normalization factor (18 decimals)
- Weighted Average: Calculates average of normalized prices:
(sum of normalized prices) / feed count - Supply Scaling: Normalization factors account for supply differences between feeds
- Precision: Uses OpenZeppelin's
Math.mulDivfor precision-preserving multiplication
Function:
getPrice(feeds, feedDecimals, feedHeartbeats, normalizationFactors): Returns normalized average
Formula:
normalized_price[i] = (feed_price[i] * normalization_factor[i]) / 1e18
average_price = sum(normalized_price) / feed_count
Use Case: Used for calculating market-cap weighted averages or supply-adjusted prices
Library Integration
These libraries work together with ChainlinkFeedLib (which handles feed data retrieval and staleness checks) to provide robust price aggregation:
- ChainlinkFeedLib: Retrieves and validates individual feed data
- Price Libraries: Aggregate multiple feeds using different strategies
- Rate Libraries: Handle rate provider data (fxSAVE, wstETH)
Price Validation
All prices are validated for:
- Staleness: Prices must be within heartbeat threshold (validated by
ChainlinkFeedLib) - Zero Values: Invalid feeds return zero (reverts in Minter)
- Decimals: All prices normalized to 18 decimals
- Feed Health: Chainlink feed status checked
- Rate Bounds: Rates validated against min/max bounds (via
ChainlinkRateLib)
Chain-Specific Deployments
Harbor price oracles are deployed across multiple chains. Each chain has its own set of deployed oracles with specific configurations. Click on each chain to view detailed oracle listings, addresses, and configurations:
Mainnet (Ethereum) - 36 Oracles
Chain ID: 1
Contract Versions: Mix of v3 (proxy) and v4 (direct) contracts
Oracle Categories:
- fxUSD Pairs (6): fxUSD/ETH, fxUSD/BTC, fxUSD/EUR, fxUSD/GOLD, fxUSD/SILVER, fxUSD/MCAP
- stETH Pairs (5): stETH/BTC, stETH/EUR, stETH/GOLD, stETH/SILVER, stETH/MCAP
- Leveraged Token Oracles (12): USD-denominated prices for hsfxUSD-* and hsstETH-* tokens
- sUSDe Pairs (6): sUSDe/BTC, sUSDe/ETH, sUSDe/EUR, sUSDe/MCAP, sUSDe/GOLD, sUSDe/SILVER
- Direct Feeds (7): wstETH/USD, wBTC/USD, tBTC/USD, PAXG/USD, and others
Example Market Oracle Addresses:
- ETH/fxUSD Market:
0x71437C90F1E0785dd691FD02f7bE0B90cd14c097 - BTC/fxUSD Market:
0x8F76a260c5D21586aFfF18f880FFC808D0524A73 - BTC/stETH Market:
0xE370289aF2145A5B2F0F7a4a900eBfD478A156dB
Arbitrum - 20 Oracles
Chain ID: 42161
Contract Version: v3 (proxy pattern)
Oracle Categories:
- USDE Stock Indices (10): USDE/AAPL, USDE/AMZN, USDE/GOOGL, USDE/META, USDE/MSFT, USDE/NVDA, USDE/SPY, USDE/TSLA, USDE/MAG7, USDE/MAG7.i26
- stETH Stock Indices (10): stETH/AAPL, stETH/AMZN, stETH/GOOGL, stETH/META, stETH/MSFT, stETH/NVDA, stETH/SPY, stETH/TSLA, stETH/MAG7, stETH/MAG7.i26
Rate Providers: sUSDe/USDE (Chainlink) for USDE pairs, wstETH/stETH (Chainlink) for stETH pairs
Base - 1 Oracle
Chain ID: 8453
Contract Version: v3 (proxy pattern)
Oracle:
- stETH/BOM5: Bag of Memes index with supply normalization (DOGE, SHIB, PEPE, TRUMP, WIF)
Rate Provider: wstETH/stETH (Chainlink)
MegaETH - 6 Oracles
Chain ID: 4326
Contract Version: v4 (direct deployments, no proxy)
Oracle Categories:
- Direct Feeds: BTC/USD, wstETH/USD, USDMY pairs
For complete oracle listings, addresses, status, and detailed configurations per chain, see the chain-specific pages linked above.
Price Usage in Protocol
Minter Contract
The Minter uses price oracles for:
-
Minting Calculations:
- Determines collateral value in quote terms
- Calculates how many pegged/leveraged tokens to mint
-
Redemption Calculations:
- Determines redemption value
- Calculates collateral to return
-
Collateral Ratio:
- Monitors system health
- Triggers rebalancing when below threshold
-
Fee Calculations:
- Some fees based on asset values
- Discounts based on collateral ratio
Price Feed Requirements
- Prices must be fresh (within heartbeat)
- Prices must be non-zero
- Rate providers must return valid rates
- All values normalized to 18 decimals
Security Considerations
- Staleness Protection: Heartbeat thresholds prevent stale prices
- Zero Price Protection: Invalid feeds return zero (reverts operations)
- Upgradeability: UUPS pattern allows upgrades (owner-only)
- Fixed Owner: Owner address immutable in base contract
- Chainlink Reliability: Uses battle-tested Chainlink feeds
- Rate Provider Validation: Rate providers validated on construction
Oracle Pair Examples
Mainnet Examples
fxUSD/ETH (Single Feed):
- Rate Provider: fxSAVE exchange rate
- Price Feed: ETH/USD Chainlink feed (inverted)
- Calculation:
price = fxSAVE_rate × (1 / ETH_USD_price) - Result: Price of fxUSD in ETH terms
- Address: See Mainnet oracles
stETH/BTC (Double Feed):
- Rate Provider: wstETH exchange rate
- Price Feeds: ETH/USD and BTC/USD Chainlink feeds
- Calculation:
price = wstETH_rate × (ETH_USD_price / BTC_USD_price) - Result: Price of stETH in BTC terms
- Address: See Mainnet oracles
fxUSD/GOLD (Single Feed):
- Rate Provider: fxSAVE exchange rate
- Price Feed: XAU/USD Chainlink feed (inverted)
- Calculation:
price = fxSAVE_rate × (1 / XAU_USD_price) - Result: Price of fxUSD in gold (XAU) terms
- Address: See Mainnet oracles
Arbitrum Examples
USDE/MAG7 (Multi-Feed Index):
- Rate Provider: sUSDe/USDE rate (Chainlink)
- Price Feeds: USDE/USD, AAPL/USD, MSFT/USD, TSLA/USD, GOOGL/USD, META/USD, AMZN/USD, NVDA/USD
- Calculation:
price = sUSDe_rate × (sum(stock_prices) / 7) - Result: Price of USDE in MAG7 index terms
- Address: See Arbitrum oracles
stETH/AAPL (Double Feed):
- Rate Provider: wstETH/stETH rate (Chainlink)
- Price Feeds: stETH/USD, AAPL/USD
- Calculation:
price = wstETH_rate × (AAPL_USD_price / stETH_USD_price) - Result: Price of stETH in AAPL terms
- Address: See Arbitrum oracles