Query On-Chain State with SDKs
Introduction
Section titled “Introduction”Polkadot SDK-based blockchains store data in a key-value database that external applications can query. This on-chain state includes account balances, asset information, governance proposals, and any other data the runtime manages.
This guide demonstrates how to query on-chain storage using five popular SDKs:
- Polkadot API (PAPI): Modern TypeScript library with type-safe APIs
- Polkadot.js API: Comprehensive JavaScript library (maintenance mode)
- Dedot: Lightweight TypeScript library optimized for performance
- Python Substrate Interface: Python library for Substrate chains
- Subxt: Rust library with compile-time type safety
Select your preferred SDK below to see complete, runnable examples that query Polkadot Hub for account balances and asset information.
Query On-Chain Data
Section titled “Query On-Chain Data”Prerequisites
- Node.js v18 or higher
- npm, pnpm, or yarn package manager
Environment Setup
-
Create and initialize a new project:
Terminal window mkdir papi-query-example && cd papi-query-example && \npm init -y && npm pkg set type=module -
Install dependencies:
Terminal window npm install polkadot-api@3.3.0 && \npm install --save-dev @types/node tsx typescript -
Generate types for Polkadot Hub:
Terminal window npx papi add pah -n polkadot_asset_hub
Query Account Balance
The following example queries the System.Account storage to retrieve an account's native token balance.
Create a file named query-balance.ts and add the following code to it:
import { createClient } from 'polkadot-api';import { getWsProvider } from 'polkadot-api/ws';import { pah } from '@polkadot-api/descriptors';
const ASSET_HUB_RPC = 'INSERT_WS_ENDPOINT';
// Example address to query (Polkadot Hub address)const ADDRESS = 'INSERT_ADDRESS';
async function main() { // Create the client connection const client = createClient(getWsProvider(ASSET_HUB_RPC));
// Get the typed API for Polkadot Hub const api = client.getTypedApi(pah);
console.log('Connected to Polkadot Hub'); console.log(`Querying balance for: ${ADDRESS}\n`);
// Query the System.Account storage const accountInfo = await api.query.System.Account.getValue(ADDRESS);
// Extract balance information const { data, nonce } = accountInfo; const { free, reserved, frozen } = data;
console.log('Account Information:'); console.log(` Nonce: ${nonce}`); console.log(` Free Balance: ${free}`); console.log(` Reserved: ${reserved}`); console.log(` Frozen: ${frozen}`);
// Disconnect the client client.destroy();}
main().catch(console.error);Run the script:
npx tsx query-balance.tsYou should see output similar to:
Query Asset Information
The following example queries the Assets pallet to retrieve metadata and balance information for USDT (asset ID 1984).
Create a file named query-asset.ts and add the following code to it:
import { Binary, createClient } from 'polkadot-api';import { getWsProvider } from 'polkadot-api/ws';import { pah } from '@polkadot-api/descriptors';
const ASSET_HUB_RPC = 'INSERT_WS_ENDPOINT';
// USDT on Polkadot Hubconst USDT_ASSET_ID = 1984;
// Example address to query asset balanceconst ADDRESS = 'INSERT_ADDRESS';
async function main() { // Create the client connection const client = createClient(getWsProvider(ASSET_HUB_RPC));
// Get the typed API for Polkadot Hub const api = client.getTypedApi(pah);
console.log('Connected to Polkadot Hub'); console.log(`Querying asset ID: ${USDT_ASSET_ID}\n`);
// Query asset metadata const assetMetadata = await api.query.Assets.Metadata.getValue(USDT_ASSET_ID);
if (assetMetadata) { console.log('Asset Metadata:'); console.log(` Name: ${Binary.toText(assetMetadata.name)}`); console.log(` Symbol: ${Binary.toText(assetMetadata.symbol)}`); console.log(` Decimals: ${assetMetadata.decimals}`); }
// Query asset details const assetDetails = await api.query.Assets.Asset.getValue(USDT_ASSET_ID);
if (assetDetails) { console.log('\nAsset Details:'); console.log(` Owner: ${assetDetails.owner}`); console.log(` Supply: ${assetDetails.supply}`); console.log(` Accounts: ${assetDetails.accounts}`); console.log(` Min Balance: ${assetDetails.min_balance}`); console.log(` Status: ${assetDetails.status.type}`); }
// Query account's asset balance console.log(`\nQuerying asset balance for: ${ADDRESS}`); const assetAccount = await api.query.Assets.Account.getValue( USDT_ASSET_ID, ADDRESS );
if (assetAccount) { console.log('\nAsset Account:'); console.log(` Balance: ${assetAccount.balance}`); console.log(` Status: ${assetAccount.status.type}`); } else { console.log('\nNo asset balance found for this account'); }
// Disconnect the client client.destroy();}
main().catch(console.error);Run the script:
npx tsx query-asset.tsYou should see output similar to:
Prerequisites
- Node.js v18 or higher
- npm, pnpm, or yarn package manager
Environment Setup
-
Create and initialize a new project:
Terminal window mkdir pjs-query-example && cd pjs-query-example && \npm init -y && npm pkg set type=module -
Install dependencies:
Terminal window npm install @polkadot/api
Query Account Balance
The following example queries the System.Account storage to retrieve an account's native token balance.
Create a file named query-balance.js and add the following code to it:
import { ApiPromise, WsProvider } from '@polkadot/api';
const ASSET_HUB_RPC = 'INSERT_WS_ENDPOINT';
// Example address to query (Polkadot Hub address)const ADDRESS = 'INSERT_ADDRESS';
async function main() { // Create a WebSocket provider const wsProvider = new WsProvider(ASSET_HUB_RPC);
// Initialize the API const api = await ApiPromise.create({ provider: wsProvider });
console.log('Connected to Polkadot Hub'); console.log(`Querying balance for: ${ADDRESS}\n`);
// Query the system.account storage const accountInfo = await api.query.system.account(ADDRESS);
// Extract balance information const { nonce, data } = accountInfo; const { free, reserved, frozen } = data;
console.log('Account Information:'); console.log(` Nonce: ${nonce.toString()}`); console.log(` Free Balance: ${free.toString()}`); console.log(` Reserved: ${reserved.toString()}`); console.log(` Frozen: ${frozen.toString()}`);
// Disconnect from the node await api.disconnect();}
main().catch(console.error);Run the script:
node query-balance.jsYou should see output similar to:
Query Asset Information
The following example queries the Assets pallet to retrieve metadata and balance information for USDT (asset ID 1984).
Create a file named query-asset.js and add the following code to it:
import { ApiPromise, WsProvider } from '@polkadot/api';
const ASSET_HUB_RPC = 'INSERT_WS_ENDPOINT';
// USDT on Polkadot Hubconst USDT_ASSET_ID = 1984;
// Example address to query asset balanceconst ADDRESS = 'INSERT_ADDRESS';
async function main() { // Create a WebSocket provider const wsProvider = new WsProvider(ASSET_HUB_RPC);
// Initialize the API const api = await ApiPromise.create({ provider: wsProvider });
console.log('Connected to Polkadot Hub'); console.log(`Querying asset ID: ${USDT_ASSET_ID}\n`);
// Query asset metadata const assetMetadata = await api.query.assets.metadata(USDT_ASSET_ID);
console.log('Asset Metadata:'); console.log(` Name: ${assetMetadata.name.toUtf8()}`); console.log(` Symbol: ${assetMetadata.symbol.toUtf8()}`); console.log(` Decimals: ${assetMetadata.decimals.toString()}`);
// Query asset details const assetDetails = await api.query.assets.asset(USDT_ASSET_ID);
if (assetDetails.isSome) { const details = assetDetails.unwrap(); console.log('\nAsset Details:'); console.log(` Owner: ${details.owner.toString()}`); console.log(` Supply: ${details.supply.toString()}`); console.log(` Accounts: ${details.accounts.toString()}`); console.log(` Min Balance: ${details.minBalance.toString()}`); console.log(` Status: ${details.status.type}`); }
// Query account's asset balance console.log(`\nQuerying asset balance for: ${ADDRESS}`); const assetAccount = await api.query.assets.account(USDT_ASSET_ID, ADDRESS);
if (assetAccount.isSome) { const account = assetAccount.unwrap(); console.log('\nAsset Account:'); console.log(` Balance: ${account.balance.toString()}`); console.log(` Status: ${account.status.type}`); } else { console.log('\nNo asset balance found for this account'); }
// Disconnect from the node await api.disconnect();}
main().catch(console.error);Run the script:
node query-asset.jsYou should see output similar to:
Prerequisites
- Node.js v18 or higher
- npm, pnpm, or yarn package manager
Environment Setup
-
Create and initialize a new project:
Terminal window mkdir dedot-query-example && cd dedot-query-example && \npm init -y && npm pkg set type=module -
Install dependencies:
Terminal window npm install dedot && \npm install --save-dev @dedot/chaintypes @types/node tsx typescript
Query Account Balance
The following example queries the System.Account storage to retrieve an account's native token balance.
Create a file named query-balance.ts and add the following code to it:
import { DedotClient, WsProvider } from 'dedot';import type { PolkadotAssetHubApi } from '@dedot/chaintypes';
const ASSET_HUB_RPC = 'INSERT_WS_ENDPOINT';
// Example address to query (Polkadot Hub address)const ADDRESS = 'INSERT_ADDRESS';
async function main() { // Initialize provider and client with Asset Hub types const provider = new WsProvider(ASSET_HUB_RPC); const client = await DedotClient.new<PolkadotAssetHubApi>(provider);
console.log('Connected to Polkadot Hub'); console.log(`Querying balance for: ${ADDRESS}\n`);
// Query the system.account storage const accountInfo = await client.query.system.account(ADDRESS);
// Extract balance information const { nonce, data } = accountInfo; const { free, reserved, frozen } = data;
console.log('Account Information:'); console.log(` Nonce: ${nonce}`); console.log(` Free Balance: ${free}`); console.log(` Reserved: ${reserved}`); console.log(` Frozen: ${frozen}`);
// Disconnect the client await client.disconnect();}
main().catch(console.error);Run the script:
npx tsx query-balance.tsYou should see output similar to:
Query Asset Information
The following example queries the Assets pallet to retrieve metadata and balance information for USDT (asset ID 1984).
Create a file named query-asset.ts and add the following code to it:
import { DedotClient, WsProvider } from 'dedot';import { hexToString } from 'dedot/utils';import type { PolkadotAssetHubApi } from '@dedot/chaintypes';
const ASSET_HUB_RPC = 'INSERT_WS_ENDPOINT';
// USDT on Polkadot Hubconst USDT_ASSET_ID = 1984;
// Example address to query asset balanceconst ADDRESS = 'INSERT_ADDRESS';
async function main() { // Initialize provider and client with Asset Hub types const provider = new WsProvider(ASSET_HUB_RPC); const client = await DedotClient.new<PolkadotAssetHubApi>(provider);
console.log('Connected to Polkadot Hub'); console.log(`Querying asset ID: ${USDT_ASSET_ID}\n`);
// Query asset metadata const assetMetadata = await client.query.assets.metadata(USDT_ASSET_ID);
console.log('Asset Metadata:'); console.log(` Name: ${hexToString(assetMetadata.name)}`); console.log(` Symbol: ${hexToString(assetMetadata.symbol)}`); console.log(` Decimals: ${assetMetadata.decimals}`);
// Query asset details const assetDetails = await client.query.assets.asset(USDT_ASSET_ID);
if (assetDetails) { console.log('\nAsset Details:'); console.log(` Owner: ${assetDetails.owner.address()}`); console.log(` Supply: ${assetDetails.supply}`); console.log(` Accounts: ${assetDetails.accounts}`); console.log(` Min Balance: ${assetDetails.minBalance}`); console.log(` Status: ${JSON.stringify(assetDetails.status)}`); }
// Query account's asset balance console.log(`\nQuerying asset balance for: ${ADDRESS}`); const assetAccount = await client.query.assets.account([ USDT_ASSET_ID, ADDRESS, ]);
if (assetAccount) { console.log('\nAsset Account:'); console.log(` Balance: ${assetAccount.balance}`); console.log(` Status: ${JSON.stringify(assetAccount.status)}`); } else { console.log('\nNo asset balance found for this account'); }
// Disconnect the client await client.disconnect();}
main().catch(console.error);Run the script:
npx tsx query-asset.tsYou should see output similar to:
Prerequisites
- Python 3.8 or higher
- pip package manager
Environment Setup
-
Create a new project directory and set up a virtual environment:
Terminal window mkdir psi-query-example && cd psi-query-example && \python3 -m venv venv && source venv/bin/activate -
Install the substrate-interface package:
Terminal window pip install substrate-interface
Query Account Balance
The following example queries the System.Account storage to retrieve an account's native token balance.
Create a file named query_balance.py and add the following code to it:
from substrateinterface import SubstrateInterface
ASSET_HUB_RPC = "INSERT_WS_ENDPOINT"
# Example address to query (Polkadot Hub address)ADDRESS = "INSERT_ADDRESS"
def main(): # Connect to Polkadot Hub substrate = SubstrateInterface(url=ASSET_HUB_RPC)
print("Connected to Polkadot Hub") print(f"Querying balance for: {ADDRESS}\n")
# Query the System.Account storage account_info = substrate.query( module="System", storage_function="Account", params=[ADDRESS], )
# Extract balance information nonce = account_info.value["nonce"] data = account_info.value["data"] free = data["free"] reserved = data["reserved"] frozen = data["frozen"]
print("Account Information:") print(f" Nonce: {nonce}") print(f" Free Balance: {free}") print(f" Reserved: {reserved}") print(f" Frozen: {frozen}")
# Close connection substrate.close()
if __name__ == "__main__": main()Run the script:
python query_balance.pyYou should see output similar to:
Query Asset Information
The following example queries the Assets pallet to retrieve metadata and balance information for USDT (asset ID 1984).
Create a file named query_asset.py and add the following code to it:
from substrateinterface import SubstrateInterface
ASSET_HUB_RPC = "INSERT_WS_ENDPOINT"
# USDT on Polkadot HubUSDT_ASSET_ID = 1984
# Example address to query asset balanceADDRESS = "INSERT_ADDRESS"
def main(): # Connect to Polkadot Hub substrate = SubstrateInterface(url=ASSET_HUB_RPC)
print("Connected to Polkadot Hub") print(f"Querying asset ID: {USDT_ASSET_ID}\n")
# Query asset metadata asset_metadata = substrate.query( module="Assets", storage_function="Metadata", params=[USDT_ASSET_ID], )
if asset_metadata.value: metadata = asset_metadata.value print("Asset Metadata:") print(f" Name: {metadata['name']}") print(f" Symbol: {metadata['symbol']}") print(f" Decimals: {metadata['decimals']}")
# Query asset details asset_details = substrate.query( module="Assets", storage_function="Asset", params=[USDT_ASSET_ID], )
if asset_details.value: details = asset_details.value print("\nAsset Details:") print(f" Owner: {details['owner']}") print(f" Supply: {details['supply']}") print(f" Accounts: {details['accounts']}") print(f" Min Balance: {details['min_balance']}") print(f" Status: {details['status']}")
# Query account's asset balance print(f"\nQuerying asset balance for: {ADDRESS}") asset_account = substrate.query( module="Assets", storage_function="Account", params=[USDT_ASSET_ID, ADDRESS], )
if asset_account.value: account = asset_account.value print("\nAsset Account:") print(f" Balance: {account['balance']}") print(f" Status: {account['status']}") else: print("\nNo asset balance found for this account")
# Close connection substrate.close()
if __name__ == "__main__": main()Run the script:
python query_asset.pyYou should see output similar to:
Subxt is a Rust library that provides compile-time type safety through code generation from chain metadata.
Prerequisites
- Rust toolchain (latest stable)
- Cargo package manager
Environment Setup
-
Create a new Rust project:
Terminal window cargo new subxt-query-example && cd subxt-query-example -
Install the Subxt CLI:
Terminal window cargo install subxt-cli@0.50.1 -
Download the Polkadot Hub metadata:
Terminal window subxt metadata --url INSERT_WS_ENDPOINT -o asset_hub_metadata.scale -
Update
Cargo.tomlwith the required dependencies:Cargo.toml [package]name = "subxt-query-example"version = "0.1.0"edition = "2021"[[bin]]name = "query_balance"path = "src/bin/query_balance.rs"[[bin]]name = "query_asset"path = "src/bin/query_asset.rs"[dependencies]subxt = "0.50.0"tokio = { version = "1", features = ["rt", "macros"] }
Query Account Balance
The following example queries the System.Account storage to retrieve an account's native token balance.
Create a file at src/bin/query_balance.rs and add the following code to it:
use std::str::FromStr;use subxt::utils::AccountId32;use subxt::{OnlineClient, PolkadotConfig};
// Generate an interface from the node's metadata#[subxt::subxt(runtime_metadata_path = "asset_hub_metadata.scale")]pub mod asset_hub {}
const ASSET_HUB_RPC: &str = "INSERT_WS_ENDPOINT";
// Example address to query (Polkadot Hub address)const ADDRESS: &str = "INSERT_ADDRESS";
#[tokio::main(flavor = "current_thread")]async fn main() -> Result<(), Box<dyn std::error::Error>> { // Initialize the Subxt client let api = OnlineClient::<PolkadotConfig>::from_url(ASSET_HUB_RPC).await?;
// Anchor to the current block let at_block = api.at_current_block().await?;
println!("Connected to Polkadot Hub"); println!("Querying balance for: {}\n", ADDRESS);
// Parse the address let account = AccountId32::from_str(ADDRESS)?;
// Build storage entry for System.Account let account_storage = at_block .storage() .entry(asset_hub::storage().system().account())?;
// Fetch the account information let info = account_storage .fetch((account,)) .await? .decode()?;
println!("Account Information:"); println!(" Nonce: {}", info.nonce); println!(" Free Balance: {}", info.data.free); println!(" Reserved: {}", info.data.reserved); println!(" Frozen: {}", info.data.frozen);
Ok(())}Run the script:
cargo run --bin query_balanceYou should see output similar to:
Query Asset Information
The following example queries the Assets pallet to retrieve metadata and balance information for USDT (asset ID 1984).
Create a file at src/bin/query_asset.rs and add the following code to it:
use std::str::FromStr;use subxt::utils::AccountId32;use subxt::{OnlineClient, PolkadotConfig};
// Generate an interface from the node's metadata#[subxt::subxt(runtime_metadata_path = "asset_hub_metadata.scale")]pub mod asset_hub {}
const ASSET_HUB_RPC: &str = "INSERT_WS_ENDPOINT";
// USDT on Polkadot Hubconst USDT_ASSET_ID: u32 = 1984;
// Example address to query asset balanceconst ADDRESS: &str = "INSERT_ADDRESS";
#[tokio::main(flavor = "current_thread")]async fn main() -> Result<(), Box<dyn std::error::Error>> { // Initialize the Subxt client let api = OnlineClient::<PolkadotConfig>::from_url(ASSET_HUB_RPC).await?;
// Anchor to the current block let at_block = api.at_current_block().await?;
println!("Connected to Polkadot Hub"); println!("Querying asset ID: {}\n", USDT_ASSET_ID);
// Query asset metadata let metadata_storage = at_block .storage() .entry(asset_hub::storage().assets().metadata())?; let meta = metadata_storage .fetch((USDT_ASSET_ID,)) .await? .decode()?;
println!("Asset Metadata:"); println!( " Name: {}", String::from_utf8_lossy(&meta.name.0) ); println!( " Symbol: {}", String::from_utf8_lossy(&meta.symbol.0) ); println!(" Decimals: {}", meta.decimals);
// Query asset details let asset_storage = at_block .storage() .entry(asset_hub::storage().assets().asset())?; let details = asset_storage .fetch((USDT_ASSET_ID,)) .await? .decode()?;
println!("\nAsset Details:"); println!(" Owner: {}", details.owner); println!(" Supply: {}", details.supply); println!(" Accounts: {}", details.accounts); println!(" Min Balance: {}", details.min_balance);
// Query account's asset balance let account = AccountId32::from_str(ADDRESS)?; println!("\nQuerying asset balance for: {}", ADDRESS);
let account_storage = at_block .storage() .entry(asset_hub::storage().assets().account())?; let asset_account = account_storage .fetch((USDT_ASSET_ID, account)) .await? .decode()?;
println!("\nAsset Account:"); println!(" Balance: {}", asset_account.balance);
Ok(())}Run the script:
cargo run --bin query_assetYou should see output similar to:
Where to Go Next
Section titled “Where to Go Next”-
Runtime API Calls
Execute runtime APIs for specialized queries.
-
Send Transactions
Learn how to construct and submit transactions.