Oraichain
Search…
Oraichain

Introduction

Oraichain Oracle Price Feeds enable developers to integrate on-chain price data from crypto markets into their smart contracts with ease.
Oraichain Oracle Price Feeds meanwhile supports a wide range of blockchain networks such as Ethereum, Binance Chain, Oraichain, and more in the future.
Data have been extracted from trustworthy exchanges in addition to timely updates with low latency.
Supported assets supported by Oraichain Oracle at the moment are as follows:

Smart contract

Contract address on Oraichain testnet: orai1s60a2vntfuv2ps6fs75fcrlrmea9xzr4k65zlg
Price Data Requests

Integrate with Node.js

const path = require('path');
const fetch = require('isomorphic-fetch');
const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing");
const { stringToPath } = require("@cosmjs/crypto");
const cosmwasm = require('@cosmjs/cosmwasm-stargate');
const { GasPrice } = require('@cosmjs/cosmwasm-stargate/node_modules/@cosmjs/stargate/build');
require('dotenv').config({ path: path.resolve(__dirname, process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : ".env") })
// .env file
/**
* MNEMONIC=""
WEBSOCKET_URL=ws://testnet-rpc.orai.io // testnet ip
LCD_URL=http://testnet-lcd.orai.io
CONTRACT_ADDRESS=orai1s60a2vntfuv2ps6fs75fcrlrmea9xzr4k65zlg // testnet contract
BACKEND_URL=https://testnet-aioracle-svr.orai.io
*/
const network = {
rpc: process.env.NETWORK_RPC || "https://testnet-rpc.orai.io",
prefix: "orai",
}
const collectWallet = async (mnemonic) => {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(
mnemonic,
{
hdPaths: [stringToPath("m/44'/118'/0'/0/0")],
prefix: network.prefix,
}
);
return wallet;
}
const execute = async ({ mnemonic, address, handleMsg, memo, amount, gasData = undefined }) => {
try {
const wallet = await collectWallet(mnemonic);
const [firstAccount] = await wallet.getAccounts();
const client = await cosmwasm.SigningCosmWasmClient.connectWithSigner(network.rpc, wallet, { gasPrice: gasData ? GasPrice.fromString(`${gasData.gasAmount}${gasData.denom}`) : undefined, prefix: network.prefix, gasLimits: { exec: 20000000 } });
const input = JSON.parse(handleMsg);
const result = await client.execute(firstAccount.address, address, input, memo, amount);
return result.transactionHash;
} catch (error) {
console.log("error in executing contract: ", error);
throw error;
}
}
const demo = async () => {
const contractAddr = process.env.CONTRACT_ADDRESS;
console.log("contract addr: ", contractAddr)
const wallet = process.env.MNEMONIC;
const threshold = process.env.THRESHOLD || 1;
const service = process.env.SERVICE || "price";
const lcdUrl = process.env.LCD_URL || "https://testnet-lcd.orai.io";
const backendUrl = process.env.BACKEND_URL || "https://testnet-aioracle-svr.orai.io";
const [feeAmount, boundExecutorFee] = await getServiceFees(contractAddr, lcdUrl, service, threshold);
// const feeAmount = [{ denom: "orai", amount: "1000" }]
let finalFeeAmount = feeAmount.filter(fee => fee.amount !== '0');
if (finalFeeAmount.length === 0) finalFeeAmount = undefined;
const input = JSON.stringify({
request: {
threshold: parseInt(threshold),
service,
preference_executor_fee: boundExecutorFee
}
})
console.log("input: ", input)
// store the merkle root on-chain
const txHash = await execute({ mnemonic: wallet, address: contractAddr, handleMsg: input, gasData: { gasAmount: "0", denom: "orai" }, amount: finalFeeAmount });
console.log("execute result: ", txHash);
const requestId = await collectRequestId(lcdUrl, txHash);
console.log("request id: ", requestId);
console.log("Collecting the reports, please wait...")
const reports = await collectReports(backendUrl, contractAddr, requestId);
console.log("reports: ", JSON.stringify(reports));
}
const getServiceFees = async (contractAddr, lcdUrl, service, threshold) => {
const getServiceFeesMsg = JSON.stringify({
get_service_fees: {
service,
}
})
const boundExecutorFeeMsg = JSON.stringify({
get_bound_executor_fee: {}
})
let rawData = await fetch(`${lcdUrl}/wasm/v1beta1/contract/${contractAddr}/smart/${Buffer.from(getServiceFeesMsg).toString('base64')}`).then(data => data.json());
let data = rawData.data;
let boundFee = await fetch(`${lcdUrl}/wasm/v1beta1/contract/${contractAddr}/smart/${Buffer.from(boundExecutorFeeMsg).toString('base64')}`).then(data => data.json());
let boundExecutorFee = boundFee.data;
console.log("data: ", rawData);
data.push(["placeholder", boundExecutorFee.denom, boundExecutorFee.amount]);
// let data = [
// ['orai1y88tlgddntj66sn46qqlvtx3tp7tgl8sxxx6uk', 'orai', '1'],
// ['orai1v7ae3ptzqvztcx83fheafltq88hvdp2m5zas6f', 'orai', '1'],
// ['orai1v7ae3ptzqvztcx83fheafltq88hvdp2m5zas6f', 'foobar', '1'],
// ['orai1v7ae3ptzqvztcx83fheafltq88hvdp2m5zas6f', 'orai', '1'],
// ['orai1v7ae3ptzqvztcx83fheafltq88hvdp2m5zas6f', 'orai', '1'],
// ['orai1v7ae3ptzqvztcx83fheafltq88hvdp2m5zas6f', 'xyz', '1'],
// ['orai1v7ae3ptzqvztcx83fheafltq88hvdp2m5zas6f', 'foobar', '1'],
// ['orai1v7ae3ptzqvztcx83fheafltq88hvdp2m5zas6f', 'xyz', '1'],
// ];
data = data.map(reward => ({ denom: reward[1], amount: parseInt(reward[2]) })).reduce((prev, curr) => {
if (prev.constructor === Array) {
// find if the current denom exists already in the accumulator
const index = prev.findIndex(prevElement => prevElement.denom === curr.denom);
if (index !== -1) {
// if exist then we update the amount of the index in the accumulator, then keep the accumulator
prev[index].amount += curr.amount;
return prev;
}
// if does not exist then we append the current obj into the accumulator
return [...prev, curr];
} else {
if (prev.denom === curr.denom) return [{ ...prev, amount: prev.amount + curr.amount }];
}
return [...prev, curr];
}, []).map(reward => ({ ...reward, amount: String(reward.amount * threshold) }));
return [data, boundExecutorFee];
}
const collectRequestId = async (lcdUrl, txHash) => {
let requestId = -1;
let count = 0; // break the loop flag
let hasRequestId = true;
do {
hasRequestId = true;
try {
const result = await fetch(`${lcdUrl}/cosmos/tx/v1beta1/txs/${txHash}`).then(data => data.json());
const wasmEvent = result.tx_response.events.filter(event => event.type === "wasm")[0].attributes.filter(attr => attr.key === Buffer.from('stage').toString('base64'))[0].value;
requestId = Buffer.from(wasmEvent, 'base64').toString('ascii');
} catch (error) {
hasRequestId = false;
count++;
if (count > 10) break; // break the loop and return the request id.
// sleep for a few seconds then repeat
await new Promise(r => setTimeout(r, 3000));
}
} while (!hasRequestId);
return requestId;
}
const collectReports = async (url, contractAddr, requestId) => {
let count = 0;
let reports = {};
const reportUrl = `${url}/report/reports?contract_addr=${contractAddr}&request_id=${requestId}`;
console.log("report url: ", reportUrl)
do {
reports = await fetch(reportUrl).then(data => data.json());
console.log("reports.data.data.length: ", reports.data.data.length)
if (!reports.data || reports.data.data.length === 0) {
count++;
if (count > 20) break; // break the loop and return the request id.
// sleep for a few seconds then repeat
await new Promise(r => setTimeout(r, 5000));
}
} while (!reports.data || reports.data.data.length === 0);
return reports.data;
}
demo();
Copy link
Edit on GitHub
On this page
Introduction
Smart contract