Oracle Precompile Usage
Address: 0x0000000000000000000000000000000000001008
The Sei Oracle precompile enables EVM applications to query real-time price feed data directly from Sei’s native Oracle module. This provides access to exchange rates, Time-Weighted Average Prices (TWAPs), and other economic data essential for DeFi applications.
How Does the Oracle Precompile Work?
The Oracle precompile at address 0x0000000000000000000000000000000000001008
exposes functions like getExchangeRates()
and getOracleTwaps()
.
- Direct Integration: EVM contracts and dApps can query price data like any other smart contract method.
- Native Execution: Oracle queries are executed at the Cosmos SDK level for maximum efficiency.
- Real-Time Data: Access live price feeds maintained by Sei’s validator network.
Use Cases
- DeFi Protocols: Build lending platforms, DEXs, and derivatives with reliable price feeds.
- Stablecoins: Implement price-stable tokens with accurate exchange rate data.
- Liquidation Systems: Create robust liquidation mechanisms using real-time prices.
- Trading Bots: Develop automated trading strategies with TWAP data.
- Risk Management: Build portfolio management tools with accurate asset valuations.
Functions
The Oracle precompile exposes the following functions:
Query Functions
struct OracleExchangeRate {
string exchangeRate;
string lastUpdate;
int64 lastUpdateTimestamp;
}
struct DenomOracleExchangeRatePair {
string denom;
OracleExchangeRate oracleExchangeRateVal;
}
/// Retrieves the exchange rates for all denominations.
/// @return An array of denomination and exchange rate pairs.
function getExchangeRates() external view returns (DenomOracleExchangeRatePair[] memory);
struct OracleTwap {
string denom;
string twap;
int64 lookbackSeconds;
}
/// Retrieves Oracle Time-Weighted Average Prices (TWAPs) for the specified lookback period.
/// @param lookback_seconds The lookback period in seconds (min: 60, max: 86400).
/// @return An array of denomination and TWAP pairs.
function getOracleTwaps(
uint64 lookback_seconds
) external view returns (OracleTwap[] memory);
Supported Denominations
Common denominations available in the oracle include:
usei
- Micro SEI (1 SEI = 1,000,000 usei)uusdc
- Micro USDCuatom
- Micro ATOMuosmo
- Micro OSMOueth
- Micro Ethereumubtc
- Micro Bitcoinuusdt
- Micro USDT
getExchangeRates()
to see all currently available price feeds.Using the Contract
Setup
Prerequisites
Before getting started, ensure you have:
- Node.js (v18 or higher recommended)
- npm or yarn package manager
- MetaMask or compatible EVM wallet
- SEI tokens for gas fees (typically 0.001-0.01 SEI per oracle query)
Install Dependencies
Install the required packages for interacting with Sei precompiles:
# Install ethers.js for smart contract interactions
npm install ethers
# Install Sei EVM bindings for precompile addresses and ABIs
npm install @sei-js/precompiles@2.1.2
# Install dotenv for managing private keys (optional but recommended)
npm install dotenv
Import Precompile Components
// Import Oracle precompile address and ABI
// View the entire ABI here: https://github.com/sei-protocol/sei-chain/tree/main/precompiles/oracle
import { ORACLE_PRECOMPILE_ABI, ORACLE_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';
import { ethers } from 'ethers';
0x0000000000000000000000000000000000001008
Get SEI Tokens
Purchase SEI tokens from supported exchanges. You will need a small amount of SEI in your wallet to pay for gas fees when making calls to the Oracle precompile.
Contract Initialization
Set up your provider, signer, and contract instance:
// Using MetaMask as the signer and provider (browser environment)
const provider = new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []);
const signer = await provider.getSigner();
// Or for Node.js environment
const provider = new ethers.JsonRpcProvider('https://evm-rpc.sei-apis.com');
const signer = new ethers.Wallet('YOUR_PRIVATE_KEY', provider);
// Create a contract instance for the Oracle precompile
const oracle = new ethers.Contract(ORACLE_PRECOMPILE_ADDRESS, ORACLE_PRECOMPILE_ABI, signer);
Helper Functions
Use these helper functions for price data handling:
// Helper functions for Oracle data conversion
class OracleDataHelper {
// Convert exchange rate string to number
static rateToNumber(rateString: string): number {
try {
const rate = parseFloat(rateString);
if (isNaN(rate) || !isFinite(rate)) {
throw new Error(`Invalid rate: ${rateString}`);
}
return rate;
} catch (error) {
console.error('Error parsing rate:', rateString, error);
return 0;
}
}
// Format timestamp to readable date
static formatTimestamp(timestamp: bigint | number): string {
try {
return new Date(Number(timestamp) * 1000).toISOString();
} catch (error) {
console.error('Error formatting timestamp:', timestamp, error);
return 'Invalid timestamp';
}
}
// Calculate price from exchange rate (assuming USD base)
static calculatePrice(exchangeRate: string, amount: number = 1): number {
return this.rateToNumber(exchangeRate) * amount;
}
// Find specific denom in exchange rates
static findDenom(rates: any[], denom: string): any {
return rates.find((rate) => rate.denom === denom);
}
// Check if price data is stale (older than 5 minutes)
static isPriceStale(timestamp: bigint | number): boolean {
const now = Math.floor(Date.now() / 1000);
const priceTime = Number(timestamp);
return now - priceTime > 300; // 5 minutes
}
}
Step-by-Step Guide: Using the Oracle Precompile
Get Exchange Rates
// Get all exchange rates
const exchangeRates = await oracle.getExchangeRates();
// Display rates
exchangeRates.forEach((rate) => {
const price = OracleDataHelper.rateToNumber(rate.oracleExchangeRateVal.exchangeRate);
const timestamp = rate.oracleExchangeRateVal.lastUpdateTimestamp;
const isStale = OracleDataHelper.isPriceStale(timestamp);
console.log(`${rate.denom}: $${price.toFixed(6)}${isStale ? ' (STALE)' : ''}`);
console.log(`Last Update: ${OracleDataHelper.formatTimestamp(timestamp)}`);
});
Get TWAP Data
// Get 1-hour TWAP (3600 seconds)
const lookbackSeconds = 3600;
const twaps = await oracle.getOracleTwaps(lookbackSeconds);
// Display TWAPs
twaps.forEach((twap) => {
console.log(`${twap.denom} TWAP: ${twap.twap}`);
console.log(`Lookback: ${twap.lookbackSeconds} seconds`);
});
Query Specific Token Price
// Get exchange rates and find specific token
const rates = await oracle.getExchangeRates();
const seiRate = rates.find((r) => r.denom === 'usei');
if (seiRate) {
const price = parseFloat(seiRate.oracleExchangeRateVal.exchangeRate);
console.log(`SEI Price: $${price}`);
}
Monitor Price Changes
// Monitor price changes every 30 seconds (recommended minimum for mainnet)
async function monitorPrices() {
const previousPrices = new Map();
const monitor = async () => {
try {
const rates = await oracle.getExchangeRates();
rates.forEach((rate) => {
const currentPrice = OracleDataHelper.rateToNumber(rate.oracleExchangeRateVal.exchangeRate);
const previousPrice = previousPrices.get(rate.denom);
if (previousPrice) {
const change = ((currentPrice - previousPrice) / previousPrice) * 100;
console.log(`${rate.denom}: $${currentPrice.toFixed(6)} (${change >= 0 ? '+' : ''}${change.toFixed(2)}%)`);
}
previousPrices.set(rate.denom, currentPrice);
});
} catch (error) {
console.error('Monitor error:', error);
}
};
// Initial fetch
await monitor();
// Monitor every 30 seconds
setInterval(monitor, 30000);
}
Complete Integration Example
Create a file named oracle-demo.js
:
const { ethers } = require('ethers');
const { ORACLE_PRECOMPILE_ABI, ORACLE_PRECOMPILE_ADDRESS } = require('@sei-js/precompiles');
require('dotenv').config();
// Helper functions
function safeParseFloat(str) {
try {
const num = parseFloat(str);
return isNaN(num) ? 0 : num;
} catch {
return 0;
}
}
function formatTimestamp(timestamp) {
try {
return new Date(Number(timestamp) * 1000).toISOString();
} catch {
return 'Invalid timestamp';
}
}
function isPriceStale(timestamp, maxAgeSeconds = 300) {
const now = Math.floor(Date.now() / 1000);
return now - Number(timestamp) > maxAgeSeconds;
}
async function main() {
try {
// Connect to Sei Mainnet
console.log('🔗 Connecting to Sei Mainnet...');
const provider = new ethers.JsonRpcProvider('https://evm-rpc.sei-apis.com');
// Verify connection to mainnet
const network = await provider.getNetwork();
if (Number(network.chainId) !== 1329) {
throw new Error(`Expected Sei Mainnet (1329), but connected to chain ${network.chainId}`);
}
console.log(`✅ Connected to Sei Mainnet (Chain ID: 1329)`);
// Setup wallet
const privateKey = process.env.PRIVATE_KEY;
if (!privateKey) {
throw new Error('Please set PRIVATE_KEY in .env file');
}
const wallet = new ethers.Wallet(privateKey, provider);
console.log('👛 Wallet address:', wallet.address);
// Check balance
const balance = await provider.getBalance(wallet.address);
const balanceInSei = ethers.formatEther(balance);
console.log('💰 Wallet balance:', balanceInSei, 'SEI');
if (parseFloat(balanceInSei) < 0.01) {
console.warn('⚠️ Low balance detected. You may need more SEI for gas fees.');
console.log('💡 Purchase SEI from supported exchanges like Binance, Coinbase, or KuCoin');
}
// Initialize Oracle precompile contract
const oracle = new ethers.Contract(ORACLE_PRECOMPILE_ADDRESS, ORACLE_PRECOMPILE_ABI, wallet);
console.log('\n' + '='.repeat(50));
console.log('🔮 Oracle Precompile Demo - Sei Mainnet');
console.log('='.repeat(50));
// 1. Get all exchange rates
console.log('\n1️⃣ Fetching current exchange rates...');
const exchangeRates = await oracle.getExchangeRates();
if (!exchangeRates || exchangeRates.length === 0) {
console.log('📭 No exchange rates available on mainnet');
return;
}
console.log(`📊 Found ${exchangeRates.length} price feeds on Sei Mainnet:`);
// Display all available rates
exchangeRates.forEach((rate, index) => {
const price = safeParseFloat(rate.oracleExchangeRateVal.exchangeRate);
const timestamp = rate.oracleExchangeRateVal.lastUpdateTimestamp;
const lastUpdate = formatTimestamp(timestamp);
const isStale = isPriceStale(timestamp);
console.log(`\n ${index + 1}. ${rate.denom}:`);
console.log(` 💲 Price: $${price.toFixed(6)}${isStale ? ' ⚠️ (STALE)' : ''}`);
console.log(` ⏰ Last Update: ${lastUpdate}`);
});
// 2. Get TWAP data
console.log('\n2️⃣ Fetching 1-hour TWAP data...');
const lookbackSeconds = 3600; // 1 hour
try {
const twaps = await oracle.getOracleTwaps(lookbackSeconds);
if (twaps && twaps.length > 0) {
console.log(`📈 Found ${twaps.length} TWAP values:`);
twaps.forEach((twap, index) => {
const twapPrice = safeParseFloat(twap.twap);
console.log(`\n ${index + 1}. ${twap.denom}:`);
console.log(` 📊 1hr TWAP: $${twapPrice.toFixed(6)}`);
console.log(` ⏱️ Lookback: ${twap.lookbackSeconds} seconds`);
});
} else {
console.log('📭 No TWAP data available for the requested period');
}
} catch (twapError) {
console.error('❌ Failed to fetch TWAP data:', twapError.message);
}
// 3. Focus on SEI price analysis
console.log('\n3️⃣ SEI Price Analysis...');
const seiRate = exchangeRates.find((r) => r.denom === 'usei');
if (seiRate) {
const seiPrice = safeParseFloat(seiRate.oracleExchangeRateVal.exchangeRate);
const timestamp = seiRate.oracleExchangeRateVal.lastUpdateTimestamp;
console.log(`\n 💎 SEI (usei) Details:`);
console.log(` 💲 Current Price: $${seiPrice.toFixed(6)}`);
console.log(` ⏰ Last Update: ${formatTimestamp(timestamp)}`);
console.log(` 🔄 Price Age: ${Math.floor(Date.now() / 1000) - Number(timestamp)} seconds`);
// Market cap calculation (approximate)
const circulatingSupply = 3_90000000; // Approximate SEI supply
const marketCap = seiPrice * circulatingSupply;
console.log(` 📊 Est. Market Cap: $${(marketCap / 1000000).toFixed(2)}M`);
} else {
console.log(' ❌ SEI price not found in oracle data');
}
// 4. DeFi use case - Advanced collateral calculation
console.log('\n4️⃣ Advanced DeFi Example - Multi-asset portfolio...');
const portfolio = [
{ asset: 'usei', amount: 1000 },
{ asset: 'uusdc', amount: 500 },
{ asset: 'uatom', amount: 50 }
];
let totalPortfolioValue = 0;
const portfolioBreakdown = [];
console.log(`\n 💼 Portfolio Analysis:`);
portfolio.forEach(({ asset, amount }) => {
const assetRate = exchangeRates.find((r) => r.denom === asset);
if (assetRate) {
const price = safeParseFloat(assetRate.oracleExchangeRateVal.exchangeRate);
const value = price * amount;
totalPortfolioValue += value;
portfolioBreakdown.push({
asset,
amount,
price,
value,
percentage: 0 // Will calculate after total
});
console.log(` 🪙 ${asset}: ${amount} tokens × $${price.toFixed(6)} = $${value.toFixed(2)}`);
}
});
// Calculate percentages
portfolioBreakdown.forEach((item) => {
item.percentage = (item.value / totalPortfolioValue) * 100;
});
console.log(`\n 📊 Portfolio Summary:`);
console.log(` 💰 Total Value: $${totalPortfolioValue.toFixed(2)}`);
portfolioBreakdown.forEach(({ asset, value, percentage }) => {
console.log(` 📈 ${asset}: $${value.toFixed(2)} (${percentage.toFixed(1)}%)`);
});
// Lending calculations
const maxLTV = 0.75; // 75% max loan-to-value
const maxBorrow = totalPortfolioValue * maxLTV;
console.log(` 🏦 Max Borrowing Power (75% LTV): $${maxBorrow.toFixed(2)}`);
// 5. Gas cost analysis
console.log('\n5️⃣ Gas cost analysis on mainnet...');
try {
const feeData = await provider.getFeeData();
const exchangeRateGas = await oracle.getExchangeRates.estimateGas();
const twapGas = await oracle.getOracleTwaps.estimateGas(3600);
const exchangeRateCost = exchangeRateGas * (feeData.gasPrice || 0n);
const twapCost = twapGas * (feeData.gasPrice || 0n);
console.log(`\n ⛽ Mainnet Gas Estimates:`);
console.log(` 📊 getExchangeRates(): ${exchangeRateGas.toString()} gas`);
console.log(` 📈 getOracleTwaps(): ${twapGas.toString()} gas`);
console.log(` 💰 Exchange Rate Cost: ~${ethers.formatEther(exchangeRateCost)} SEI`);
console.log(` 💰 TWAP Cost: ~${ethers.formatEther(twapCost)} SEI`);
// Current SEI price for USD conversion
if (seiRate) {
const seiPrice = safeParseFloat(seiRate.oracleExchangeRateVal.exchangeRate);
const exchangeRateUSD = parseFloat(ethers.formatEther(exchangeRateCost)) * seiPrice;
const twapUSD = parseFloat(ethers.formatEther(twapCost)) * seiPrice;
console.log(` 💵 Exchange Rate Cost: ~$${exchangeRateUSD.toFixed(4)} USD`);
console.log(` 💵 TWAP Cost: ~$${twapUSD.toFixed(4)} USD`);
}
} catch (gasError) {
console.log(' ⚠️ Could not estimate gas costs:', gasError.message);
}
} catch (error) {
console.error('\n❌ Demo failed:', error.message);
// Enhanced error diagnostics for mainnet
if (error.message.includes('1329')) {
console.log("💡 Network issue: Make sure you're connecting to Sei Mainnet");
console.log(' - RPC URL: https://evm-rpc.sei-apis.com');
console.log(' - Chain ID: 1329');
} else if (error.code === 'INSUFFICIENT_FUNDS') {
console.log('💡 Buy SEI tokens from:');
console.log(' - Binance: https://www.binance.com/en/trade/SEI_USDT');
console.log(' - Coinbase: https://www.coinbase.com/price/sei');
console.log(' - KuCoin: https://www.kucoin.com/trade/SEI-USDT');
} else if (error.code === 'NETWORK_ERROR') {
console.log('💡 Network troubleshooting:');
console.log(' - Check internet connection');
console.log(' - Verify RPC endpoint is accessible');
console.log(' - Try alternative RPC if available');
}
process.exit(1);
}
}
// Graceful shutdown
process.on('SIGINT', () => {
console.log('\n🛑 Demo interrupted');
process.exit(0);
});
// Run the demo
if (require.main === module) {
main().catch(console.error);
}
module.exports = { main };
Running the Example
- Create a new directory and initialize npm:
mkdir sei-oracle-mainnet
cd sei-oracle-mainnet
npm init -y
- Install dependencies:
npm install ethers @sei-js/precompiles@2.1.2 dotenv
- Create a
.env
file:
PRIVATE_KEY=your_private_key_here_without_0x_prefix
-
Create the demo file: Copy the complete integration example above into
oracle-demo.js
-
Run the script:
node oracle-demo.js
Expected Output on Mainnet
🔗 Connecting to Sei Mainnet...
✅ Connected to Sei Mainnet (Chain ID: 1329)
👛 Wallet address: 0x742d35Cc6634C0532925a3b844Bc6789e065f3B
💰 Wallet balance: 5.2 SEI
==================================================
🔮 Oracle Precompile Demo - Sei Mainnet
==================================================
1️⃣ Fetching current exchange rates...
📊 Found 12 price feeds on Sei Mainnet:
1. usei:
💲 Price: $0.421500
⏰ Last Update: 2024-01-15T15:45:32.000Z
2. uusdc:
💲 Price: $1.000100
⏰ Last Update: 2024-01-15T15:45:32.000Z
3. uatom:
💲 Price: $9.875000
⏰ Last Update: 2024-01-15T15:45:32.000Z
2️⃣ Fetching 1-hour TWAP data...
📈 Found 12 TWAP values:
1. usei:
📊 1hr TWAP: $0.419200
⏱️ Lookback: 3600 seconds
3️⃣ SEI Price Analysis...
💎 SEI (usei) Details:
💲 Current Price: $0.421500
⏰ Last Update: 2024-01-15T15:45:32.000Z
🔄 Price Age: 45 seconds
📊 Est. Market Cap: $164.4M
4️⃣ Advanced DeFi Example - Multi-asset portfolio...
💼 Portfolio Analysis:
🪙 usei: 1000 tokens × $0.421500 = $421.50
🪙 uusdc: 500 tokens × $1.000100 = $500.05
🪙 uatom: 50 tokens × $9.875000 = $493.75
📊 Portfolio Summary:
💰 Total Value: $1415.30
📈 usei: $421.50 (29.8%)
📈 uusdc: $500.05 (35.3%)
📈 uatom: $493.75 (34.9%)
🏦 Max Borrowing Power (75% LTV): $1061.48
5️⃣ Gas cost analysis on mainnet...
⛽ Mainnet Gas Estimates:
📊 getExchangeRates(): 52341 gas
📈 getOracleTwaps(): 58967 gas
💰 Exchange Rate Cost: ~0.002617 SEI
💰 TWAP Cost: ~0.002948 SEI
💵 Exchange Rate Cost: ~$0.0011 USD
💵 TWAP Cost: ~$0.0012 USD
==================================================
✅ Oracle demo completed successfully on Sei Mainnet!
==================================================
Production Best Practices
Mainnet Production Considerations:
- Real Money at Risk: Always test thoroughly on testnet first
- Gas Optimization: Oracle calls cost real SEI - optimize frequency
- Price Validation: Implement multiple layers of price validation: Always validate price freshness before usage
- Fallback Mechanisms: Have backup price sources for critical applications
- Monitoring: Set up alerts for oracle failures or stale data
- Rate Limiting: Respect RPC rate limits to avoid being blocked
Error Code Reference
Error | Cause | Solution |
---|---|---|
no oracle data | Oracle module not active | Check network configuration |
denom not found | Asset not in oracle | Verify supported denoms |
stale price data | Old timestamp | Check lastUpdateTimestamp |
invalid lookback | Lookback too long | Use shorter TWAP period |