Hongbai Experimental Oracle

Explore the Hongbai Oracle Framework

The design of the Hongbai Oracle is a simple architecture. A single Oracle contract stores the latest price for a list of assets. This current price can be queried by both on-chain and off-chain consumers. The maximum frequency will be once per block, which is currently ~6 seconds in Hongbai. Initially, the prices will be updated every 60 seconds.

Lookup Prices within your CosmWasm Smart Contract

Queries Available

The Oracle contract supports several queries that you can use to retrieve price data within your smart contract. Here are the available queries:

  1. GetPrice: Retrieve the price of a specific asset by its symbol.

    • QueryMsg: GetPrice { symbol: String }

    • Response: PriceResponse { price: i64, expo: i32, timestamp: u64 }

  2. GetAllSymbols: Retrieve a list of all symbols for which prices are available.

    • QueryMsg: GetAllSymbols {}

    • Response: Vec<String>

  3. GetAllPrices: Retrieve all stored prices.

    • QueryMsg: GetAllPrices {}

    • Response: Vec<(String, Price)>

  4. GetPublisher: Retrieve the address of the publisher (creator) of the prices.

    • QueryMsg: GetPublisher

    • Response: Addr


Price/PriceResponse Structure Explanation

The Price/PriceResponse struct is designed to provide pricing information for an Asset returned from the Hongbai Oracle contract. This response includes three key pieces of data: price, expo, and timestamp.

  • Response: PriceResponse { price: i64, expo: i32, timestamp: u64 }

Fields:

  1. price (i64):

    • Description: The price field represents the price of the requested asset in a fixed-point integer format.

    • Details:

      • This value is scaled by a factor of 10^expo. For instance, if price is 712163 and expo is 6, the actual price is 712163 * 10^-6 = 0.712163.

      • Using an integer type (i64) for the price ensures precision and avoids issues with floating-point arithmetic, which can introduce rounding errors.

    • Example: If the asset's price is 0.712163, price would be 712163 with an expo of 6.

  2. expo (i32):

    • Description: The expo field indicates the exponent used to scale the price value.

    • Details:

      • This scaling factor is crucial for converting the integer price back to its floating-point representation. The actual price is calculated as price * 10^expo.

      • The use of an exponent allows the contract to represent very large or very small prices accurately.

    • Example: An expo value of 6 means the price should be divided by 1,000,000 (10^6) to get the actual price.

  3. timestamp (u64):

    • Description: The timestamp field records the time at which the price data was retrieved from the oracle.

    • Details:

      • The timestamp is represented as a Unix epoch time (the number of seconds since January 1, 1970).

      • This field is essential for determining the freshness of the price data, which is particularly important in fast-moving markets.

    • Example: A timestamp value of 1716372480 corresponds to a specific point in time (e.g., May 22, 2024, 16:48:00 UTC).

Example Usage:

When querying the price of a symbol, you might receive a response formatted as follows:

Copy

{
  "price": 712163,
  "expo": 6,
  "timestamp": 1716372480
}

To interpret this data:

  • Price: 712163

  • Exponent: 6

  • Actual Price: 712163 * 10^-6 = 0.712163

  • Timestamp: 1716372480 (convert to human-readable time if needed)

This structured approach ensures that you can obtain accurate and timely price information from the Hongbai Oracle contract, facilitating reliable and efficient data handling in your decentralized applications.


How to Get a Price from within your CosmWasm Smart Contract

To query a price from within your CosmWasm smart contract, you need to send a query message to the Oracle contract. Here is an example of how to do this:

fn query_price(deps: Deps, symbol: String) -> StdResult<PriceResponse> {
    let oracle_address = ORACLE_ADDRESS.load(deps.storage)?;

    let msg = QueryPrice {
        get_price: GetPrice { symbol },
    };

    let request = QueryRequest::Wasm(WasmQuery::Smart {
        contract_addr: oracle_address.to_string(),
        msg: to_json_binary(&msg)?,
    });

    let res: PriceResponse = deps.querier.query(&request)?;

    Ok(res)
}

fn query_all_symbols(deps: Deps) -> StdResult<Vec<String>> {
    let oracle_address = ORACLE_ADDRESS.load(deps.storage)?;

    let msg = QueryAllSymbols {
        get_all_symbols: GetAllSymbols {},
    };

    let request = QueryRequest::Wasm(WasmQuery::Smart {
        contract_addr: oracle_address.to_string(),
        msg: to_json_binary(&msg)?,
    });

    let res: Vec<String> = deps.querier.query(&request)?;
    Ok(res)
}

In this example:

  • Deps is a dependency injection for accessing the chain state.

  • QueryMsg::GetPrice { symbol } constructs the query message to get the price of the specified symbol.

  • deps.querier.query_wasm_smart sends the query message to the Oracle contract and parses the response.


Lookup Prices within your WebApp

To integrate the Hongbai Oracle with your web application, you can use the automatically generated TypeScript classes. Here is how you can fetch prices using these classes.

Generating the client code

The generated TypeScript code from @cosmwasm/ts-codegen provides a convenient and type-safe way to interact with the Hongbai Oracle contract from your web applications. This code includes classes and interfaces that represent the contract's queries and execution messages, enabling you to easily fetch price data, symbols, and all stored prices. By using the HongbaiOracleQueryClient and HongbaiOracleClient classes, developers can abstract away the complexities of directly constructing and sending query messages to the blockchain. The HongbaiOracleQueryClient class provides methods for read-only operations such as getPrice, getAllSymbols, and getAllPrices, while the HongbaiOracleClient class extends this functionality to include write operations, like publishPrice. This auto-generated code streamlines the integration process, ensuring that developers can quickly and efficiently build dApps that leverage the Hongbai Oracle's price feeds with minimal effort. The schema files used for generating this code are included in the sample repository located at https://github.com/MANTRA-Finance/hongbai-oracle-sample.

Example using the Generated TypeScript Classes

First, ensure you have the necessary dependencies installed:

npm install @cosmjs/cosmwasm-stargate @cosmjs/amino

Then, use the generated classes to interact with the Oracle contract:

import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate';
import { HongbaiOracleQueryClient } from './path-to-generated-code/HongbaiOracleClient';

// Initialize the client
const client = await CosmWasmClient.connect('<https://rpc.hongbai.mantrachain.io>');
const contractAddress = 'mantra1q44nqkfcude7je0tqhu0u8mm7x8uhgj73n94k2vkx87tsr6yaujsdu3s4a';

// Create an instance of the query client
const queryClient = new HongbaiOracleQueryClient(client, contractAddress);

// Fetch the price of a specific asset
const priceResponse = await queryClient.getPrice({ symbol: 'BTC' });
console.log(priceResponse);

// Fetch all symbols
const symbols = await queryClient.getAllSymbols();
console.log(symbols);

// Fetch all prices
const allPrices = await queryClient.getAllPrices();
console.log(allPrices);

In this example:

  • CosmWasmClient.connect connects to the specified RPC endpoint.

  • HongbaiOracleQueryClient is the generated class for querying the Oracle contract.

  • The methods getPrice, getAllSymbols, and getAllPrices are used to fetch data from the contract.

This approach simplifies interacting with the Oracle contract and allows you to easily integrate price feeds into your web application.

Last updated