RAAC crvUSD to USD Oracle¶
Overview¶
The CrvUSDToUSDOracle is a robust, multi-tiered price oracle that provides the crvUSD/USD exchange rate for the RAAC protocol. It implements a sophisticated fallback mechanism to ensure price availability even during oracle failures, with built-in circuit breakers to protect against depeg events.
The oracle uses a three-tier fallback system:
- Primary: Direct Chainlink crvUSD/USD feed
- Secondary: ETH/USD + ETH/crvUSD (Curve TriCRV pool)
- Tertiary: Hard-coded fallback price
Non-Reverting Design
The oracle is designed to never revert on price queries. Instead, it gracefully falls back through multiple price sources to ensure continuous operation of the protocol.
Architecture¶
flowchart TD
A[Price Query] --> B{crvUSD/USD Feed Available?}
B -- Yes --> C{Price Fresh?<br/>< 1 day + 1 hour}
C -- Yes --> D[Return crvUSD/USD Price<br/>Level 0]
C -- No --> E{ETH/USD + Curve Available?}
B -- No --> E
E -- Yes --> F{ETH Price Fresh?<br/>< 1 hour + 10 min}
F -- Yes --> G[Calculate: ETH/USD ÷ ETH/crvUSD<br/>Level 1]
F -- No --> H[Return Fallback Price<br/>Level 2]
E -- No --> H
D --> I[Apply Circuit Breaker]
G --> I
H --> I
I --> J[Return Final Price]
style D fill:#d9f0d3
style G fill:#fff2cc
style H fill:#f4cccc
Fallback Levels¶
Level | Source | Description | Staleness Check |
---|---|---|---|
0 | Chainlink crvUSD/USD | Direct price feed from Chainlink | 1 day + 1 hour |
1 | ETH/USD + ETH/crvUSD | Chainlink ETH/USD × Curve TriCRV ETH/crvUSD | 1 hour + 10 minutes |
2 | Hard-coded fallback | Protocol-set fallback price (default: $1.00) | N/A |
Purpose¶
- Price Conversion: Convert crvUSD prices to USD for house price calculations
- Reliability: Ensure price availability through multiple fallback mechanisms
- Depeg Protection: Circuit breaker prevents extreme price deviations
- Protocol Integration: Seamless integration with
RAACHousePrices
for price conversion
Key Features¶
Multi-Tier Fallback System¶
The oracle implements a sophisticated three-tier fallback mechanism:
- Primary Source: Chainlink crvUSD/USD feed on Arbitrum
- Secondary Source: Chainlink ETH/USD feed combined with Curve TriCRV pool ETH/crvUSD price
- Tertiary Source: Hard-coded fallback price (configurable by owner)
Circuit Breaker Protection¶
flowchart LR
A[Raw Price] --> B{Circuit Breaker Enabled?}
B -- No --> C[Return Raw Price]
B -- Yes --> D{Price < Min Threshold?}
D -- Yes --> E[Return Min Threshold<br/>0.9 USD]
D -- No --> F{Price > Max Threshold?}
F -- Yes --> G[Return Max Threshold<br/>1.1 USD]
F -- No --> C
style E fill:#f4cccc
style G fill:#f4cccc
style C fill:#d9f0d3
- Default thresholds: 0.9 USD (min) to 1.1 USD (max)
- Configurable: Owner can adjust thresholds or disable circuit breaker
- Depeg protection: Prevents extreme price deviations during market stress
Price Sources¶
Primary: Chainlink crvUSD/USD¶
- Network: Arbitrum Mainnet
- Feed: CRVUSD/USD-RefPrice-DF-Arbitrum-001
- Staleness: 1 day + 1 hour
- Decimals: Normalized to 18 decimals
Secondary: ETH/USD + Curve TriCRV¶
- ETH/USD Feed: Chainlink ETH/USD on Ethereum
- Curve Pool: TriCRV Factory Tricrypto-4
- Calculation:
crvUSD/USD = ETH/USD ÷ ETH/crvUSD
- Staleness: 1 hour + 10 minutes for ETH/USD
- K Value: 0 (ETH index in TriCRV pool)
Key Functions¶
Price Queries¶
Function | Description | Returns |
---|---|---|
getLatestPrice() |
Full price data with fallback level | (price, timestamp, fallbackLevel) |
getPrice() |
Simple price query | uint256 price |
decimals() |
Price decimals (always 18) | uint8 |
Configuration (Owner Only)¶
Function | Description | Parameters |
---|---|---|
setCrvUSDDataFeed(address) |
Set Chainlink crvUSD/USD feed | _crvUSDDataFeed |
setEthDataFeed(address) |
Set Chainlink ETH/USD feed | _ethDataFeed |
setCurveOracle(address) |
Set Curve TriCRV oracle | _curveOracle |
setMaxStableStaleTime(uint256) |
Set crvUSD feed staleness limit | _maxStableStaleTime |
setMaxUnstableStaleTime(uint256) |
Set ETH feed staleness limit | _maxUnstableStaleTime |
setFallbackPriceInUSD(uint256) |
Set hard-coded fallback price | _fallbackPriceInUSD |
setCircuitBreakerConfig(bool, uint256, uint256) |
Configure circuit breaker | enabled, minThreshold, maxThreshold |
setK(uint256) |
Set Curve pool token index | _K |
Fallback Logic Details¶
Level 0: Direct Chainlink Feed¶
// Check if crvUSD/USD feed is available and fresh
if (address(crvUSDDataFeed) != address(0)) {
(, int256 answer, , uint256 updatedAt, ) = crvUSDDataFeed.latestRoundData();
if (answer > 0 && block.timestamp - updatedAt <= maxStableStaleTime) {
return normalizeTo18Decimals(uint256(answer), crvUSDDataFeed.decimals());
}
}
Level 1: ETH/USD + Curve Calculation¶
// Calculate crvUSD/USD = ETH/USD ÷ ETH/crvUSD
uint256 ethPriceInUSD = normalizeTo18Decimals(ethAnswer, ethDataFeed.decimals());
uint256 ETHPriceInCrvUSD = curveOracle.price_oracle(K);
uint256 crvUSDPriceInUSD = (ethPriceInUSD * 10**18) / ETHPriceInCrvUSD;
Level 2: Hard-coded Fallback¶
Circuit Breaker Configuration¶
Default Settings¶
- Enabled:
true
- Min Threshold:
0.9e18
(0.90 USD) - Max Threshold:
1.1e18
(1.10 USD)
Circuit Breaker Logic¶
function _clampCircuitBreaker(uint256 price) internal view returns (uint256) {
if (!circuitBreakerEnabled) return price;
if (price < minPriceThreshold) return minPriceThreshold;
if (price > maxPriceThreshold) return maxPriceThreshold;
return price;
}
Integration with RAACHousePrices¶
The oracle is integrated with RAACHousePrices
for price conversion:
// In RAACHousePrices.getLatestPrice()
uint256 usdPrice = tokenToHousePrice[_tokenId];
uint256 crvUSDPrice = (usdPrice * 10**crvUSDToUSDOracle.decimals()) / crvUSDToUSDOracle.getPrice();
This ensures house prices stored in USD are properly converted to crvUSD for protocol calculations.
Operational Considerations¶
Monitoring¶
- Monitor fallback level usage to detect oracle issues
- Track circuit breaker activations during market stress
- Ensure all price feeds remain healthy and updated
Emergency Procedures¶
- Oracle Failure: System automatically falls back to secondary/tertiary sources
- Depeg Event: Circuit breaker clamps prices within safe thresholds
- Feed Staleness: Automatic fallback to fresher sources
Owner Responsibilities
The owner must ensure all oracle addresses are correctly configured and monitor the system for proper operation. Incorrect configuration could lead to stale or incorrect prices.