Integrating off-chain data into your workflow is essential for creating robust and dynamic decentralized applications. This section provides a detailed guide on how to access eOracle's API off-chain.
import { ethers } from 'ethers';
// ABI of the IEOFeedManager interface
const IEOFeedManagerAbi = [
"function getLatestPriceFeed(uint16 symbol) external view returns (tuple(uint256 value, uint256 timestamp))",
"function getLatestPriceFeeds(uint16[] calldata symbols) external view returns (tuple(uint256 value, uint256 timestamp)[])"
];
// Address of the deployed IEOFeedManager contract on Holesky network
const IEOFeedManagerAddress = "0x723BD409703EF60d6fB9F8d986eb90099A170fd0";
async function main() {
// Connect to the Ethereum network (Holesky in this case)
const provider = new ethers.providers.JsonRpcProvider('https://some.holesky.rpc');
// Create a contract instance
const feedManagerContract = new ethers.Contract(IEOFeedManagerAddress, IEOFeedManagerAbi, provider);
// Example to get the latest price feed for a single symbol (e.g., BTC:USD with symbol ID 1)
async function getPrice(symbol: number) {
try {
const priceFeed = await feedManagerContract.getLatestPriceFeed(symbol);
console.log(`Price: ${priceFeed.value.toString()}, Timestamp: ${priceFeed.timestamp.toString()}`);
return priceFeed;
} catch (error) {
console.error('Error fetching price feed:', error);
}
}
// Example to get the latest price feeds for multiple symbols
async function getPrices(symbols: number[]) {
try {
const priceFeeds = await feedManagerContract.getLatestPriceFeeds(symbols);
priceFeeds.forEach((feed: { value: ethers.BigNumber, timestamp: ethers.BigNumber }, index: number) => {
console.log(`Symbol: ${symbols[index]}, Price: ${feed.value.toString()}, Timestamp: ${feed.timestamp.toString()}`);
});
return priceFeeds;
} catch (error) {
console.error('Error fetching price feeds:', error);
}
}
// Call the functions with example symbol(s)
await getPrice(1); // For BTC:USD
await getPrices([1, 2]); // Example for multiple symbols (e.g., BTC:USD and ETH:USD)
}
main().catch(console.error);
from web3 import Web3
# Connect to holesky
rpc_url = "https://some.holesky.rpc" # Replace with your rpc
web3 = Web3(Web3.HTTPProvider(rpc_url))
# Check if connected to the node
if not web3.isConnected():
print("Failed to connect to the Ethereum node.")
exit()
# Contract address and ABI
contract_address = '0x723BD409703EF60d6fB9F8d986eb90099A170fd0'
contract_abi = [
{
"inputs": [{"internalType": "uint16","name": "symbol","type": "uint16"}],
"name": "getLatestPriceFeed",
"outputs": [{"components": [{"internalType": "uint256","name": "value","type": "uint256"},{"internalType": "uint256","name": "timestamp","type": "uint256"}],"internalType": "struct IEOFeedManager.PriceFeed","name": "","type": "tuple"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{"internalType": "uint16[]","name": "symbols","type": "uint16[]"}],
"name": "getLatestPriceFeeds",
"outputs": [{"components": [{"internalType": "uint256","name": "value","type": "uint256"},{"internalType": "uint256","name": "timestamp","type": "uint256"}],"internalType": "struct IEOFeedManager.PriceFeed[]","name": "","type": "tuple[]"}],
"stateMutability": "view",
"type": "function"
}
]
# Initialize contract
contract = web3.eth.contract(address=contract_address, abi=contract_abi)
# Function to get the latest price feed for a single symbol
def get_latest_price_feed(symbol):
price_feed = contract.functions.getLatestPriceFeed(symbol).call()
return price_feed
# Function to get the latest price feeds for multiple symbols
def get_latest_price_feeds(symbols):
price_feeds = contract.functions.getLatestPriceFeeds(symbols).call()
return price_feeds
# Example usage
if __name__ == '__main__':
# Get the latest price feed for symbol 1 (e.g., BTC:USD)
symbol = 1
price_feed = get_latest_price_feed(symbol)
print(f'Price Feed for symbol {symbol}: Value = {price_feed[0]}, Timestamp = {price_feed[1]}')
# Get the latest price feeds for multiple symbols
symbols = [1, 2] # Example symbols
price_feeds = get_latest_price_feeds(symbols)
for i, feed in enumerate(price_feeds):
print(f'Price Feed for symbol {symbols[i]}: Value = {feed[0]}, Timestamp = {feed[1]}')
import { ethers } from "ethers";
// Define the ABI of the IEOFeedAdapter contract
const IEOFeedAdapterABI = [
"function latestRoundData() view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)"
];
// Define the address of the IEOFeedAdapter contract
const IEOFeedAdapterAddress = "0xDD8387185C9e0a173702fc4a3285FA576141A9cd";
async function getLatestRoundData() {
// Connect to the Ethereum provider (in this case holesky)
const provider = new ethers.JsonRpcProvider("https://some.holesky.rpc");
// Create a contract instance
const feedAdapterContract = new ethers.Contract(IEOFeedAdapterAddress, IEOFeedAdapterABI, provider);
// Call the latestRoundData function
const latestRoundData = await feedAdapterContract.latestRoundData();
// Destructure the returned data
const [roundId, answer, startedAt, updatedAt, answeredInRound] = latestRoundData;
// Log the data
console.log("Round ID:", roundId.toString());
console.log("Answer:", answer.toString());
console.log("Started At:", new Date(startedAt * 1000).toLocaleString());
console.log("Updated At:", new Date(updatedAt * 1000).toLocaleString());
console.log("Answered In Round:", answeredInRound.toString());
}
// Execute the function
getLatestRoundData().catch(console.error)
from web3 import Web3
# Connect to holesky
rpc_url = "https://some.holesky.rpc" # Replace with your rpc
web3 = Web3(Web3.HTTPProvider(rpc_url))
# Check if connected to the node
if not web3.isConnected():
print("Failed to connect to the Ethereum node.")
exit()
# Contract address and ABI
contract_address = web3.toChecksumAddress("0xDD8387185C9e0a173702fc4a3285FA576141A9cd")
contract_abi = [
{
"constant": True,
"inputs": [],
"name": "latestRoundData",
"outputs": [
{"name": "roundId", "type": "uint80"},
{"name": "answer", "type": "int256"},
{"name": "startedAt", "type": "uint256"},
{"name": "updatedAt", "type": "uint256"},
{"name": "answeredInRound", "type": "uint80"}
],
"payable": False,
"stateMutability": "view",
"type": "function"
}
]
# Initialize the contract
contract = web3.eth.contract(address=contract_address, abi=contract_abi)
# Call the latestRoundData function
try:
round_data = contract.functions.latestRoundData().call()
round_id, answer, started_at, updated_at, answered_in_round = round_data
print(f"Round ID: {round_id}")
print(f"Answer: {answer}")
print(f"Started At: {started_at}")
print(f"Updated At: {updated_at}")
print(f"Answered In Round: {answered_in_round}")
except Exception as e:
print(f"An error occurred: {e}")
The service allows users to easily query for recent price updates via a REST API or via a websocket
A user could use this endpoint to query symbol price quotes via REST API.
Our REST API endpoints could be found at: https://api.eoracle.network
Endpoint: /api/v1/get_rate
Method: GET
Parameters:
symbol
(string, required): The symbol for which to get the rate.
Authentication The REST API authentication method uses a username and password. The username is the API key provided to you by eOracle, and the password should be left blank.
$ curl -X GET -u your_api_key "https://api.testnet.eoracle.network/api/v1/get_feed?symbol=eth"
{
"symbol":"eth",
"rate":"2235520000000000000000",
"timestamp":1704645014000,
"data":"0x0c64cc6cb523085bac8aa2221d5458999...2309417974f4a72b98"
}
Endpoint: /api/v1/get_symbols
Method: GET
Example
curl -u your_api_key: 'https://api.eoracle.network/api/v1/get_symbols'
Response
["jpy", "eth", "btc"]
We provide a simple socket stream using the standard Socket.IO library. The message protocol is described in the following section and includes a connection, authentication and subscribe phases.
Connection is made to our eOracle api endpoint at https://api.testnet.eoracle.network. Once connected the consumer can initiate an authentication event.
Request Events
authenticate
name: authenticate
payload:
{
"token": "your_api_key" // your oracle api key
}
subscribe
name: subscribe
payload:
{
"topic": "feed", //(string, required): The topic to subscribe to (e.g., 'feed').
"symbols": ["btc", "eth", "jpy"] //(array of strings, optional): An array of symbols to subscribe to. If empty, subscribe to all symbols.
}
authenticated
This message is received when your client was successfully authenticated with a valid API key. Once you receive this it's a good trigger point for subscribing to quote feeds.
name: 'authenticated'
payload: none
quote
name: quote
payload:
{
"symbol": "eth",
"rate": "1923.45",
"timestamp": 1238971228,
"data": "0xbd3de674b8bd65........93c9220fb3202e405266", // provable merkle tree
}
import axios from 'axios';
import { ethers } from 'ethers';
const abi = [
"updatePriceFeeds((uint256,bytes,bytes32[])[],(uint256,uint256,bytes32,bytes32,uint256),uint256[2],bytes)"
]
const API_BASE_URL = 'https://api.eoracle.network/api/v1/get_rate';
const EORACLE_CHAINS = {
HOLESKY: {
ADDRESS: '0x723BD409703EF60d6fB9F8d986eb90099A170fd0',
RPC_URL: 'https://some.holesky.rpc',
},
}
const SYMBOL = 'btc'; // replace with your desired symbol
interface LeafInput {
leafIndex: BigInt;
unhashedLeaf: string;
proof: string;
}
interface Checkpoint {
epoch:BigInt:
blockNumber:BigInt;
eventRoot:string;
blockHash:string;
blockRound:BigInt;
}
interface IProvableFeed{
leafInput: LeafInput;
checkpoint:Checkpoint;
signature:BigInt[];
bitmap:string;
}
async function fetchFeed(symbol: string): Promise<IProvableFeed> {
const response = await axios.get(`${API_BASE_URL}?symbol=${symbol}`, {
auth: {
username: 'your_api_key', // replace with your actual authentication token
password: ''
}
});
const quote : IProvableFeed = {
symbol: response.data.symbol,
rate: response.data.rate,
timestamp: response.data.timestamp,
leafInput : response.data.leafinput,
checkpoint : reponse.data.checkpoint
signature: response.data.signature,
bitmap: response.data.bitmap
}
return quote;
}
async function main() {
const provider = new ethers.JsonRpcProvider(EORACLE_CHAINS.HOLESKY.RPC_URL); // replace `HOLESKY` with your network
const consumer = new ethers.Wallet(
'0xYOUR_PRIVATE_KEY',
provider
);
const contract = new ethers.Contract(EORACLE_CHAINS.HOLESKY.ADDRESS, contractAbi, consumer); // replace `HOLESKY` with your network
const feed = await fetchFeed(SYMBOL);
console.log(`received symbol for ${feed.symbol}: ${feed.rate} at timestamp ${feed.timestamp}`);
try {
const tx = await contract.updatePriceFeeds(feed);
console.log(`verifying price for symbol ${SYMBOL}. please wait...`)
await tx.wait();
const rate = await contract.getLatestFeed(SYMBOL);
console.log(`verified price of ${SYMBOL} is ${rate[0]} with timestamp ${rate[1]}`);
} catch (error) {
console.error('Error updating feeds:', error);
}
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
import requests
from web3 import Web3, AsyncWeb3
ABI = [
"updatePriceFeeds((uint256,bytes,bytes32[])[],(uint256,uint256,bytes32,bytes32,uint256),uint256[2],bytes)"
]
API_BASE_URL = 'https://api.eoracle.network/api/v1/get_rate'
EORACLE_CHAINS = {
"HOLESKY": {
"ADDRESS": '0x723BD409703EF60d6fB9F8d986eb90099A170fd0',
"RPC_URL": 'https://some.holesky.rpc',
}
}
SYMBOL = 'btc' # replace with your desired symbol
def fetch_feed(symbol: str):
response = requests.get(f"{API_BASE_URL}?symbol={symbol}", auth=('your_api_key', ''))
response_data = response.json()
quote = {
'symbol': response_data['symbol'],
'rate': response_data['rate'],
'timestamp': response_data['timestamp'],
'leafInput': response_data['leafinput'],
'checkpoint': response_data['checkpoint'],
'signature': response_data['signature'],
'bitmap': response_data['bitmap']
}
return quote
def main():
provider = Web3(Web3.HTTPProvider(EORACLE_CHAINS['HOLESKY']['RPC_URL']))
consumer = provider.eth.account.privateKeyToAccount('0xYOUR_PRIVATE_KEY')
contract = provider.eth.contract(address=EORACLE_CHAINS['HOLESKY']['ADDRESS'], abi=ABI)
feed = fetch_feed(SYMBOL)
print(f"received symbol for {feed['symbol']}: {feed['rate']} at timestamp {feed['timestamp']}")
try:
tx = contract.functions.updatePriceFeeds(feed).buildTransaction({
'chainId': 1,
'gas': 70000,
'gasPrice': provider.toWei('1', 'gwei'),
'nonce': provider.eth.getTransactionCount(consumer.address),
})
signed_tx = provider.eth.account.sign_transaction(tx, private_key='0xYOUR_PRIVATE_KEY')
tx_hash = provider.eth.sendRawTransaction(signed_tx.rawTransaction)
print(f"verifying price for symbol {SYMBOL}. please wait...")
receipt = provider.eth.waitForTransactionReceipt(tx_hash)
rate = contract.functions.getLatestFeed(SYMBOL).call()
print(f"verified price of {SYMBOL} is {rate[0]} with timestamp {rate[1]}")
except Exception as error:
print('Error updating feeds:', error)
if __name__ == "__main__":
main()
// example of using the socket.io eoracle API
import { io, Socket } from 'socket.io-client';
interface LeafInput {
leafIndex: BigInt;
unhashedLeaf: string;
proof: string;
}
interface Checkpoint {
epoch:BigInt:
blockNumber:BigInt;
eventRoot:string;
blockHash:string;
blockRound:BigInt;
}
interface IProvableFeed{
leafInput: LeafInput;
checkpoint:Checkpoint;
signature:BigInt[];
bitmap:string;
}
const serverUrl = 'https://api.eoracle.network';
// create a socket.io client instance
const socket: Socket = io(serverUrl);
// authenticate when the client connects
socket.on('connect', () => {
console.log('connected to server');
socket.emit('authenticate', { token: 'your_api_key' });
});
// subscribe to symbol rates when the client is authenticated
socket.on('authenticated', () => {
console.log('authenticated with server');
socket.emit('subscribe', { topic: 'feed', symbols: ['btc', 'eth'] });
})
// listen for symbol rate updates from the server
socket.on('feed', (feed: IProvableFeed) => {
console.log(`received symbol quote for ${feed.symbol}: ${feed.rate}`);
// TODO: implement your own logic here to handle the symbol rate update
});
// Handle disconnection
socket.on('disconnect', () => {
console.log('disconnected from server');
});
import socketio
# socket.IO connection URL
server_url = 'https://api.eoracle.network/api/v1/get_rate'
# create a Socket.IO client instance
sio = socketio.Client()
def on_connect():
print('connected to server')
sio.emit('authenticate', { 'token': 'your_api_key' })
# subscribe to a specific topic when the client is authenticated
def on_authenticated():
print('authenticated with server')
sio.emit('subscribe', { 'topic': 'feed', 'symbols': ['btc', 'eth'] })
sio.on('authenticated', on_authenticated)
sio.on('connect', on_connect)
# listen for updates on the specified topic
def on_feed(feed):
print(f"Received symbol feed for {feed['symbol']}: {feed['rate']}")
# TODO: implement your own logic here to handle the symbol rate update
sio.on('feed', on_feed)
# handle disconnection
def on_disconnect():
print('Disconnected from server')
sio.on('disconnect', on_disconnect)
# Connect to the server
sio.connect(server_url)
# Keep the script running
try:
sio.wait()
except KeyboardInterrupt:
print('Disconnecting...')
sio.disconnect()