Oraichain
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();
Last updated