Price Oracle and Feeds
Overview
By leveraging oracles, the OpenGradient network provides access to trusted, real-time and historical price data that powers AI model execution and decision-making.
Why We Need Oracle Integration
Oracles are essential for the following reasons:
- Real-time data feeds: AI models may need external inputs like cryptocurrency prices to execute predictions and decisions in real-time. Oracles allow smart contracts to access this data securely and in a decentralized manner.
- Verification of inputs: AI models must rely on authentic and untampered inputs, especially when handling off-chain data. Oracles help ensure the security and reliability of these inputs, which are critical for secure AI inference.
- Dynamic pricing of resources: For running AI models and secure inference, compute resources are priced based on demand. Oracles help provide real-time pricing information for these resources, ensuring that execution costs remain fair and decentralized.
Oracle Integration Overview
We are integrating oracles using Skip's Connect solution. This out-of-process service efficiently fetches price data from multiple sources, aggregates it into a single price feed, and periodically updates our chain using the new values. We are fetching the latest prices for each new block in our chain. Users and dApps can query the most recent prices directly from the blockchain.
In the rest of this document, we will provide two approaches to interact with the oracle and market map modules: API and Smart-contract.
Usage
API Endpoints
1. Get All Currency Pairs
- Endpoint:
/connect/oracle/v2/get_all_tickers
- Method:
GET
- Description: Retrieve all currency pairs tracked by the oracle module.
2. Get Market Map
- Endpoint:
/connect/marketmap/v2/marketmap
- Method: GET
- Description: Retrieves the entire market map, including all markets and configurations.
3. Get price
- Endpoint:
/connect/oracle/v2/get_price
- Method: GET
- Description: This endpoint is responsible for fetching the current price of a specific currency pair tracked by the oracle.
curl http://NODE_IP_ADDRESS:1317/connect/oracle/v2/get_price?currency_pair=ETH/USD
Response:
{
"price": {
"price": "2610437225",
"block_timestamp": "2024-10-15T09:27:10.734785284Z",
"block_height": "5753"
},
"nonce": "5480",
"decimals": "6",
"id": "25"
}
Querying Real-Time Data
The following Solidity smart contract demonstrates how to interact with the Oracle module to retrieve prices. Latest oracle price data is exposed through the ICosmos
interface.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
// Import the ICosmos interface
import "x/evm/contracts/i_cosmos/ICosmos.sol";
contract OracleTest {
// The ICosmos contract's address on the EVM module
ICosmos public cosmosContract;
// Constructor that sets the address of the ICosmos contract
constructor() {
address cosmosContractAddress = 0x00000000000000000000000000000000000000f1;
cosmosContract = ICosmos(cosmosContractAddress);
}
// Function to query the price of a given token pair (e.g., "ETH/USD")
function queryCosmosPrice(string memory tokenPair) public view returns (uint256) {
// Path to the oracle module's GetPrices endpoint
string memory path = "/connect.oracle.v2.Query/GetPrices";
// Create the request body with the token pair
string memory request = string(abi.encodePacked('{"currency_pair_ids": ["', tokenPair, '"]}'));
// Call the query_cosmos function to send the request to Cosmos
string memory result = cosmosContract.query_cosmos(path, request);
// Convert the result string to uint256 (assuming the result is numeric)
uint256 price = parsePrice(result); // Implement a parsePrice function to extract the numeric value.
return price;
}
}
Explanation: queryCosmosPrice: Queries the price of a specific currency pair (e.g., "ETH/USD") and returns the price as a uint256.
Querying Historical Data (OGHistorical
)
In addition to real-time data, you can retrieve historical price candles for a given currency pair using the OGHistorical contract. This functionality is useful for AI models that rely on time-series data or need to observe price history for analytics.
Historical Contract Interface
struct HistoricalInputQuery {
string currency_pair;
uint32 total_candles;
uint32 candle_duration_in_mins; // e.g., 1 for 1 minute, 60 for 1 hour
CandleOrder order;
CandleType[] candle_types;
}
interface OGHistorical {
function queryHistoricalCandles(
HistoricalInputQuery memory input
) external returns (TensorLib.Number[] memory);
function runInferenceOnPriceFeed(
string memory model_id,
string memory input_name,
HistoricalInputQuery memory input
) external returns (ModelOutput memory);
}
Key Methods:
queryHistoricalCandles
: retrieves a specified number of candles (e.g., open, high, low, close) for a given currency pair in ascending or descending order.currency_pair
: e.g., "ETH/USD".total_candles
: Number of candles to fetch (e.g., 100).candle_duration_in_mins
: Duration of each candle in minutes.order
: Ascending or descending.candle_types
: Which candle data you want (e.g., [CandleType.High, CandleType.Low]).
runInferenceOnPriceFeed
runs an AI inference job on historical price data. For instance, you can supply a model ID, input name, and HistoricalInputQuery in order to do on-chain predictions or analysis using historical price data.
Example: Getting Historical Candles On-Chain
Suppose you want to get the last 24 hours of hourly candles (24 candles) for ETH/USD in ascending order. You might write a contract function like:
function fetch24HPriceHistory() external {
HistoricalInputQuery memory query = HistoricalInputQuery({
currency_pair: "ETH/USD",
total_candles: 24,
candle_duration_in_mins: 60,
order: CandleOrder.Ascending,
candle_types: new CandleType[](4)
});
// Populate candleTypes with Open, High, Low, Close (or any subset)
query.candle_types[0] = CandleType.Open;
query.candle_types[1] = CandleType.High;
query.candle_types[2] = CandleType.Low;
query.candle_types[3] = CandleType.Close;
// Now call the OGHistorical contract
TensorLib.Number[] memory historicalData = OGHistorical_CONTRACT.queryHistoricalCandles(query);
}