- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
319 lines
7.3 KiB
Markdown
319 lines
7.3 KiB
Markdown
# Price Feed Setup Guide
|
|
|
|
**Date**: 2025-01-27
|
|
**Status**: ✅ **COMPLETE**
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
This guide explains how to set up price feeds for the Reserve System, including both mock feeds for testing and real Chainlink aggregators for production.
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
### Components
|
|
|
|
1. **OraclePriceFeed** - Integrates Reserve System with Chainlink-compatible aggregators
|
|
2. **MockPriceFeed** - Mock price feed for testing and development
|
|
3. **ReserveSystem** - Core reserve system that receives price updates
|
|
|
|
### Flow
|
|
|
|
```
|
|
Chainlink Aggregator / MockPriceFeed
|
|
│
|
|
▼
|
|
OraclePriceFeed
|
|
│
|
|
▼
|
|
ReserveSystem
|
|
```
|
|
|
|
---
|
|
|
|
## Setup Options
|
|
|
|
### Option 1: Mock Price Feeds (Testing/Development)
|
|
|
|
Use mock price feeds for testing and development environments.
|
|
|
|
**Advantages**:
|
|
- No external dependencies
|
|
- Full control over prices
|
|
- Easy to test edge cases
|
|
- No API costs
|
|
|
|
**Usage**:
|
|
```bash
|
|
export USE_MOCK_FEEDS=true
|
|
export XAU_ASSET=<xau_token_address>
|
|
export USDC_ASSET=<usdc_token_address>
|
|
export ETH_ASSET=<eth_token_address>
|
|
|
|
forge script script/reserve/SetupPriceFeeds.s.sol:SetupPriceFeeds \
|
|
--rpc-url chain138 \
|
|
--broadcast
|
|
```
|
|
|
|
### Option 2: Real Chainlink Aggregators (Production)
|
|
|
|
Use real Chainlink aggregators for production environments.
|
|
|
|
**Advantages**:
|
|
- Real-time market prices
|
|
- High reliability
|
|
- Industry standard
|
|
- Multiple data sources
|
|
|
|
**Usage**:
|
|
```bash
|
|
export USE_MOCK_FEEDS=false
|
|
export XAU_ASSET=<xau_token_address>
|
|
export XAU_AGGREGATOR=<chainlink_xau_usd_aggregator>
|
|
export USDC_ASSET=<usdc_token_address>
|
|
export USDC_AGGREGATOR=<chainlink_usdc_usd_aggregator>
|
|
export ETH_ASSET=<eth_token_address>
|
|
export ETH_AGGREGATOR=<chainlink_eth_usd_aggregator>
|
|
|
|
forge script script/reserve/SetupPriceFeeds.s.sol:SetupPriceFeeds \
|
|
--rpc-url chain138 \
|
|
--broadcast
|
|
```
|
|
|
|
---
|
|
|
|
## Step-by-Step Setup
|
|
|
|
### Step 1: Deploy OraclePriceFeed (if not already deployed)
|
|
|
|
The `SetupPriceFeeds.s.sol` script will automatically deploy `OraclePriceFeed` if not provided via environment variable.
|
|
|
|
### Step 2: Configure Aggregators
|
|
|
|
#### For Mock Feeds:
|
|
|
|
```bash
|
|
# Set environment variables
|
|
export RESERVE_SYSTEM=<reserve_system_address>
|
|
export RESERVE_ADMIN=<admin_address>
|
|
export USE_MOCK_FEEDS=true
|
|
|
|
# Asset addresses (use test token addresses)
|
|
export XAU_ASSET=0x1111111111111111111111111111111111111111
|
|
export USDC_ASSET=0x2222222222222222222222222222222222222222
|
|
export ETH_ASSET=0x3333333333333333333333333333333333333333
|
|
|
|
# Run setup script
|
|
forge script script/reserve/SetupPriceFeeds.s.sol:SetupPriceFeeds \
|
|
--rpc-url chain138 \
|
|
--broadcast
|
|
```
|
|
|
|
#### For Real Aggregators:
|
|
|
|
```bash
|
|
# Set environment variables
|
|
export RESERVE_SYSTEM=<reserve_system_address>
|
|
export RESERVE_ADMIN=<admin_address>
|
|
export USE_MOCK_FEEDS=false
|
|
|
|
# Asset addresses
|
|
export XAU_ASSET=<xau_token_address>
|
|
export USDC_ASSET=<usdc_token_address>
|
|
export ETH_ASSET=<eth_token_address>
|
|
|
|
# Chainlink aggregator addresses (example for Ethereum mainnet)
|
|
export XAU_AGGREGATOR=0x214eD9Da11D2fbe465a6fc601a91E62EbEc1a0D6 # XAU/USD
|
|
export USDC_AGGREGATOR=0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6 # USDC/USD
|
|
export ETH_AGGREGATOR=0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419 # ETH/USD
|
|
|
|
# Run setup script
|
|
forge script script/reserve/SetupPriceFeeds.s.sol:SetupPriceFeeds \
|
|
--rpc-url chain138 \
|
|
--broadcast
|
|
```
|
|
|
|
### Step 3: Update Price Feeds
|
|
|
|
Price feeds can be updated manually or via automated keeper:
|
|
|
|
```solidity
|
|
// Manual update
|
|
oraclePriceFeed.updatePriceFeed(assetAddress);
|
|
|
|
// Update multiple assets
|
|
address[] memory assets = [xauAsset, usdcAsset, ethAsset];
|
|
oraclePriceFeed.updateMultiplePriceFeeds(assets);
|
|
```
|
|
|
|
### Step 4: Verify Price Feeds
|
|
|
|
```solidity
|
|
// Check if update is needed
|
|
bool needsUpdate = oraclePriceFeed.needsUpdate(assetAddress);
|
|
|
|
// Get current price
|
|
(uint256 price, uint256 timestamp) = reserveSystem.getPrice(assetAddress);
|
|
```
|
|
|
|
---
|
|
|
|
## Price Feed Configuration
|
|
|
|
### Supported Assets
|
|
|
|
Common assets to configure:
|
|
|
|
1. **Gold (XAU)**
|
|
- Token: XAU token address
|
|
- Aggregator: Chainlink XAU/USD
|
|
- Decimals: 8 (Chainlink) → 18 (Reserve System)
|
|
- Multiplier: 1e10
|
|
|
|
2. **USDC**
|
|
- Token: USDC token address
|
|
- Aggregator: Chainlink USDC/USD
|
|
- Decimals: 8 (Chainlink) → 18 (Reserve System)
|
|
- Multiplier: 1e10
|
|
|
|
3. **ETH**
|
|
- Token: ETH/WETH token address
|
|
- Aggregator: Chainlink ETH/USD
|
|
- Decimals: 8 (Chainlink) → 18 (Reserve System)
|
|
- Multiplier: 1e10
|
|
|
|
### Price Multipliers
|
|
|
|
Price multipliers convert from aggregator decimals (typically 8) to Reserve System decimals (18):
|
|
|
|
- **8 decimals → 18 decimals**: Multiplier = 1e10
|
|
- **18 decimals → 18 decimals**: Multiplier = 1e0 (1)
|
|
|
|
### Update Interval
|
|
|
|
Default update interval: 30 seconds
|
|
|
|
Can be configured:
|
|
```solidity
|
|
oraclePriceFeed.setUpdateInterval(60); // 60 seconds
|
|
```
|
|
|
|
---
|
|
|
|
## Mock Price Feed Usage
|
|
|
|
### Deploy Mock Price Feed
|
|
|
|
```solidity
|
|
// Deploy with initial price
|
|
MockPriceFeed mockFeed = new MockPriceFeed(2000 * 1e8, 8); // $2000, 8 decimals
|
|
```
|
|
|
|
### Update Mock Price
|
|
|
|
```solidity
|
|
// Update price
|
|
mockFeed.updatePrice(2100 * 1e8); // $2100
|
|
|
|
// Update with custom timestamp
|
|
mockFeed.updatePriceWithTimestamp(2100 * 1e8, block.timestamp - 10);
|
|
```
|
|
|
|
### Get Price Data
|
|
|
|
```solidity
|
|
// Get latest answer
|
|
int256 price = mockFeed.latestAnswer();
|
|
|
|
// Get latest round data
|
|
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
|
|
mockFeed.latestRoundData();
|
|
```
|
|
|
|
---
|
|
|
|
## Automated Price Updates
|
|
|
|
### Keeper Integration
|
|
|
|
Set up a keeper to automatically update price feeds:
|
|
|
|
```javascript
|
|
// Example keeper script
|
|
const OraclePriceFeed = await ethers.getContractAt("OraclePriceFeed", oraclePriceFeedAddress);
|
|
const assets = [xauAsset, usdcAsset, ethAsset];
|
|
|
|
// Check if updates are needed
|
|
for (const asset of assets) {
|
|
const needsUpdate = await OraclePriceFeed.needsUpdate(asset);
|
|
if (needsUpdate) {
|
|
await OraclePriceFeed.updatePriceFeed(asset);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Cron Job Example
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# Update price feeds every 30 seconds
|
|
|
|
while true; do
|
|
forge script script/reserve/UpdatePriceFeeds.s.sol:UpdatePriceFeeds \
|
|
--rpc-url chain138 \
|
|
--broadcast
|
|
sleep 30
|
|
done
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Price Feed Not Available
|
|
|
|
**Error**: `ReserveSystem: price feed not available`
|
|
|
|
**Solution**:
|
|
1. Verify aggregator is set: `oraclePriceFeed.aggregators(asset)`
|
|
2. Update price feed: `oraclePriceFeed.updatePriceFeed(asset)`
|
|
3. Check aggregator is returning valid data
|
|
|
|
### Stale Price
|
|
|
|
**Error**: `ReserveSystem: stale source price`
|
|
|
|
**Solution**:
|
|
1. Update price feed more frequently
|
|
2. Increase update interval if needed
|
|
3. Check aggregator is updating regularly
|
|
|
|
### Invalid Price
|
|
|
|
**Error**: `OraclePriceFeed: invalid price`
|
|
|
|
**Solution**:
|
|
1. Verify aggregator is returning positive values
|
|
2. Check aggregator is not paused
|
|
3. Verify aggregator address is correct
|
|
|
|
---
|
|
|
|
## Security Considerations
|
|
|
|
1. **Access Control**: Only authorized addresses can update price feeds
|
|
2. **Price Validation**: Prices are validated before updating Reserve System
|
|
3. **Staleness Check**: Prices older than threshold are rejected
|
|
4. **Multi-Sig**: Consider using multi-sig for critical price feed updates
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- [Reserve System Documentation](./INTEGRATION_COMPLETE.md)
|
|
- [Oracle System Documentation](../oracle/README.md)
|
|
- [Chainlink Price Feeds](https://docs.chain.link/data-feeds/price-feeds)
|
|
|