Skip to main content

Oracle Module

The Oracle module provides decentralized price feeds for DeFi operations.

Overview

┌─────────────────────────────────────────────────────────────┐
│ Oracle Architecture │
│ │
│ External Sources Validator Network │
│ ┌──────────┐ ┌──────────────────┐ │
│ │Chainlink │───────────▶│ │ │
│ │ Pyth │───────────▶│ Price Voting │ │
│ │ Band │───────────▶│ (Validators) │ │
│ │ Custom │───────────▶│ │ │
│ └──────────┘ └────────┬─────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Median Aggregation│ │
│ │ + TWAP │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ On-Chain Price │ │
│ │ (Consensus) │ │
│ └───────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Price Feed Mechanism

Vote Extensions (ABCI 2.0)

Validators include price votes in block proposals:

type PriceVote struct {
Validator string
Prices []Price
Timestamp time.Time
Signature []byte
}

type Price struct {
Symbol string // e.g., "BTC"
Price sdk.Dec // e.g., 42000.50
Source string // e.g., "chainlink"
}

Aggregation

  1. Collect votes from 2/3+ validators
  2. Remove outliers (>3σ deviation)
  3. Calculate weighted median
  4. Apply TWAP smoothing

Supported Assets

SymbolSourcesUpdate Frequency
BTCChainlink, Pyth, BinanceEvery block
ETHChainlink, Pyth, CoinbaseEvery block
SOLPyth, FTXEvery block
RP1Internal DEXEvery block
USDCFixed (1.00)N/A

Query Prices

Current Price

rp1d query oracle price BTC

Output:

{
"symbol": "BTC",
"price": "42150.500000000000000000",
"timestamp": "2024-01-15T10:30:00Z",
"sources": 12
}

All Prices

rp1d query oracle prices

Historical TWAP

rp1d query oracle twap BTC --period 1h

TypeScript SDK

import { OracleModule } from '@rp1/sdk';

const oracle = new OracleModule(client);

// Get current price
const btcPrice = await oracle.getPrice('BTC');
console.log(`BTC: $${btcPrice.price}`);

// Get all prices
const prices = await oracle.getAllPrices();
prices.forEach(p => console.log(`${p.symbol}: $${p.price}`));

// Get TWAP
const twap = await oracle.getTWAP('ETH', '1h');
console.log(`ETH 1h TWAP: $${twap}`);

// Subscribe to price updates
oracle.subscribePrices(['BTC', 'ETH'], (price) => {
console.log(`${price.symbol} updated: $${price.price}`);
});

Oracle Daemon

Validators run the oracle daemon to submit prices:

Configuration

# oracle-config.yaml
sources:
- name: chainlink
endpoint: https://api.chainlink.com/v1
assets: [BTC, ETH]
weight: 0.4

- name: pyth
endpoint: https://pyth.network/api
assets: [BTC, ETH, SOL]
weight: 0.4

- name: binance
endpoint: wss://stream.binance.com
assets: [BTC, ETH, SOL]
weight: 0.2

settings:
update_interval: 500ms
max_deviation: 0.01 # 1% max deviation
timeout: 5s

Running the Daemon

rp1d oracle-daemon start --config oracle-config.yaml

Price Deviation Alerts

# Alert if price deviates >5% from TWAP
rp1d query oracle deviation BTC --threshold 0.05

Message Types

MsgSubmitPrice (Validator Only)

message MsgSubmitPrice {
string validator = 1;
repeated PriceData prices = 2;
bytes signature = 3;
}

message PriceData {
string symbol = 1;
string price = 2;
string source = 3;
google.protobuf.Timestamp timestamp = 4;
}

Parameters

ParameterDefaultDescription
vote_threshold66%Min validators for consensus
max_deviation3%Max price deviation allowed
slash_window100 blocksWindow for missed votes
slash_fraction0.01%Slash for missing votes
twap_period30 minDefault TWAP period

Events

EventTypePriceUpdated = "oracle_price_updated"
EventTypePriceDeviation = "oracle_price_deviation"
EventTypeMissedVote = "oracle_missed_vote"

Using Oracle in Smart Contracts

Solidity (EVM)

import "@rp1/contracts/interfaces/IOracle.sol";

contract MyDeFi {
IOracle public oracle;

function getCollateralValue(
address token,
uint256 amount
) public view returns (uint256) {
uint256 price = oracle.getPrice(token);
return amount * price / 1e18;
}
}

CosmWasm

use rp1_oracle::query_price;

pub fn execute_swap(
deps: DepsMut,
info: MessageInfo,
token_in: String,
token_out: String,
) -> Result<Response, ContractError> {
let price_in = query_price(deps.as_ref(), &token_in)?;
let price_out = query_price(deps.as_ref(), &token_out)?;
// ... swap logic
}

Security

  1. Multi-source aggregation: No single source can manipulate price
  2. Outlier rejection: Statistical filtering removes anomalies
  3. TWAP smoothing: Resists flash loan attacks
  4. Slashing: Validators penalized for bad data

Next Steps