The InitiaJS SDK offers a powerful RESTClient that simplifies the process of querying data from both the Initia L1 and rollups. This client encapsulates various endpoints and methods into user-friendly helper functions, organized under sub-categories of the rest client based on their corresponding Cosmos SDK modules.

In this tutorial, we’ll explore several examples demonstrating how to leverage these helper functions to retrieve key data points efficiently using the SDK.

For demonstration purposes, we will assume that all of these examples are implemented in a file named src/query.ts.

Querying Account Balance

To query the balance of an account, we can use the balance function from the bank module. This function takes in an address and returns the balance of the account.

First, we will make the necessary imports and initialize the RESTClient.

import { RESTClient, Coin } from '@initia/initia.js';

const restClient = new RESTClient('https://rest.testnet.initia.xyz', {
    chainId: 'initiation-2',
    gasPrices: '0.015uinit', // default gas prices
    gasAdjustment: '2.0',   // default gas adjustment for fee estimation
});
Adjust gasPrices and gasAdjustment according to current network conditions for optimal transaction processing.

Next, we will create a function to query the balance of an account. This function will take in an address and return the balance of the account.

Note that response from the query is paginated, so we need to handle the pagination properly in the function. Specifically, response that are paginated will return a next_key in the pagination object, which we can use to get the next page of results. We will then keep looping through the results until we have all the pages, which we will know is the case when next_key is null.

async function queryBalance(address: string) {
  let allCoins: Coin[] = [];
  let nextKey: string | null = null;

  do {
    const [coins, pagination] = await restClient.bank.balance(address, { 'pagination.key': nextKey || undefined });
    allCoins = [...allCoins, ...coins];
    nextKey = pagination.next_key || null;
  } while (nextKey);

  console.log(`${address} has:`);
  allCoins.forEach((coin: Coin) => {
    console.log(`- ${coin.amount.toString()} ${coin.denom}`);
  });
}

We can then call the function with an address to query the balance of the account.

queryBalance('init1w4cqq6udjqtvl5xx0x6gjeyzgwtze8c05kysnu');

If successful, you should see an output similar to the following:

init1w4cqq6udjqtvl5xx0x6gjeyzgwtze8c05kysnu has:
- 721662 uinit
- 1000000 uinit

Complete Example

src/query.ts
import { RESTClient, Coin } from '@initia/initia.js';

const restClient = new RESTClient('https://rest.testnet.initia.xyz');

async function queryBalance(address: string) {
  let allCoins: Coin[] = [];
  let nextKey: string | null = null;

  do {
    const [coins, pagination] = await restClient.bank.balance(address, { 'pagination.key': nextKey || undefined });
    allCoins = [...allCoins, ...coins];
    nextKey = pagination.next_key || null;
  } while (nextKey);

  console.log(`${address} has:`);
  allCoins.forEach((coin: Coin) => {
    console.log(`- ${coin.amount.toString()} ${coin.denom}`);
  });
}

queryBalance('init1w4cqq6udjqtvl5xx0x6gjeyzgwtze8c05kysnu');

VM-Agnostic Queries

VM-agnostic queries are queries that can be used across all VMs.

  • balance() : query the balance of an account
const balances = await restClient.bank.balance('init14l3c2vxrdvu6y0sqykppey930s4kufsvt97aeu')
  • blockInfo(): query the block information
const blockInfo = await restClient.tendermint.blockInfo(10000) // If no height is given, the latest block is returned. 
  • txInfo(): query the transaction information
const txInfo = await restClient.tx.txInfo('6DFEE8E4BFC38341E8AADBD74A23588D8DE94FA38052CB5721DDA780A24F8B1D')
  • price(): query the oracle price
const currenyPair = new CurrencyPair('BTC', 'USD')
const price = await restClient.oracle.price(currenyPair)

VM-Specific Queries

MoveVM

  • viewfunction(): query the move contract view functions
// `object.move`
// 
// #[view]
// public fun owner<T: key>(object: Object<T>): address acquires ObjectCore {
//     ...
// }

const res = await restClient.move.viewFunction(
    '0x1',                                               // owner of the module
    'object',                                            // name of the module
    'owner',                                             // function name
    ["0x1::object::ObjectCore"],                         // type arguments
    [
        bcs.object().serialize('0xc4f0b3c2300c99b0d7717ce43cd76821407a34c79587542919876a8c241a2f94').toBase64(),
    ]                                                    // arguments
)
  • viewJSON(): query the move contract view functions with JSON arguments
const res = await restClient.move.viewJSON(
    '0x1',                                               // owner of the module
    'object',                                            // name of the module
    'owner',                                             // function name
    ["0x1::object::ObjectCore"],                         // type arguments
    [
        `"0xc4f0b3c2300c99b0d7717ce43cd76821407a34c79587542919876a8c241a2f94"`,
    ]                                                    // arguments
)
  • resources(): query the move contract resources
const resources = await restClient.move.resources('0x1')
const resource = await restClient.move.resource('0x1', '0x1::code::ModuleStore')
  • modules(): query the move contract modules
const modules = await restClient.move.module('0x1')
const module = await restClient.move.module('0x1', 'object')
  • tableInfo(): query the move contract table info
const tableHandle = '0xc8c40eef193fc150fcb54264419bd3e39339c2ee8ba5834aed7826a9841cfb53'
const entryKeyBytes = 'A0vD7ATVOvfCWo1T7H8Pz2MOt5k6rvsScYEGgXe0QDw='

const tableInfo = await restClient.move.tableInfo(tableHandle)
const tableEntries = await restClient.move.tableEntries(tableHandle)
const tableEntry = await restClient.move.tableEntry(tableHandle,entryKeyBytes)

WasmVM

  • contractInfo(): query the wasm contract info
const contractInfo = await restClient.wasm.contractInfo('init14mv62l7x4ducykg0crfa9a22egf8yrltmxzy84zn0wqgmr496jqs5z7k0c')
const contracts = await restClient.wasm.contractsByCode(1) 
  • smartContractState(): query the wasm smart contract state
const contractState = await restClient.wasm
  .smartContractState(
    'init1jue5rlc9dkurt3etr57duutqu7prchqrk2mes2227m52kkrual3qdrydg6',  // contract address
    Buffer.from(
      JSON.stringify({                                                  // query data 
        get_stage_info: {
            stage: 1,
        },
      })
    ).toString('base64')
  )
const allContractStates = await restClient.wasm.allContractState('init14mv62l7x4ducykg0crfa9a22egf8yrltmxzy84zn0wqgmr496jqs5z7k0c')

EVM

  • call(): query the evm contract
const contractInfo = JSON.parse(
  fs
    .readFileSync(
      '../solidity/evm-example/artifacts/contracts/example.sol/example.json' // path of build response
    )
    .toString()
);
const contract = new ethers.Contract(contractAddress, contractInfo.abi)

const res = await restClient.evm
  .call(
    'init1jvxywa6dmdxumr9nhdez838af06f9v42w0rd26',    // sender
    '0x16e999092BF37913a3eff185949997b6f7bd698c',     // contract_addr
    contract.interface.encodeFunctionData(
      'getPoints', [2, 0, 10]                         // hex encoded execution input bytes
    ).slice(2),
    false                                             // whether to return the trace
  )