CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-polkadot--api

Promise and RxJS wrappers around the Polkadot JS RPC for interacting with Polkadot and Substrate-based blockchains

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

blockchain-queries.mddocs/

Blockchain Queries

Query blockchain state, constants, and runtime information through dynamically generated interfaces. The @polkadot/api provides structured access to all runtime storage items, constants, and derived data.

Capabilities

Storage Queries

Access chain state through the query interface, dynamically generated from runtime metadata.

interface QueryableStorage<ApiType> {
  [section: string]: {
    [method: string]: QueryableStorageEntry<ApiType>;
  };
}

interface QueryableStorageEntry<ApiType> {
  /**
   * Query storage with optional parameters
   * @param ...args - Storage query parameters (if any)
   * @returns Storage value or subscription
   */
  (...args: any[]): ApiType extends 'rxjs' 
    ? Observable<any>
    : Promise<any>;
    
  /**
   * Query storage with subscription callback
   * @param ...args - Storage query parameters and callback
   * @returns Unsubscribe function
   */
  (...args: any[], callback: (value: any) => void): ApiType extends 'rxjs'
    ? Observable<any>
    : UnsubscribePromise;
    
  /**
   * Get the storage key for this query
   * @param ...args - Storage query parameters
   * @returns Storage key
   */
  key(...args: any[]): StorageKey;
  
  /**
   * Get the raw storage key  
   * @param ...args - Storage query parameters
   * @returns Raw key bytes
   */
  keysPaged(options?: PaginationOptions): ApiType extends 'rxjs'
    ? Observable<StorageKey[]>
    : Promise<StorageKey[]>;
}

interface PaginationOptions {
  args?: any[];
  pageSize?: number;
  startKey?: string;
}

Multi-Query Interface

Query multiple storage entries efficiently in a single subscription.

interface QueryableStorageMulti<ApiType> {
  /**
   * Query multiple storage entries
   * @param queries - Array of storage queries
   * @param callback - Optional callback for subscriptions
   * @returns Query results or unsubscribe function
   */
  <T extends any[]>(
    queries: (QueryableStorageEntry<'rxjs'> | [QueryableStorageEntry<'rxjs'>, ...any[]])[],
    callback?: (values: T) => void
  ): ApiType extends 'rxjs' 
    ? Observable<T>
    : Promise<T>;
}

Runtime Constants

Access module constants (parameter types) from the runtime.

interface QueryableConsts<ApiType> {
  [section: string]: {
    [constant: string]: any;
  };
}

Derived Queries

Access computed data that combines multiple storage queries.

interface AllDerives<ApiType> {
  [section: string]: {
    [method: string]: (...args: any[]) => ApiType extends 'rxjs'
      ? Observable<any>
      : Promise<any>;
  };
}

Runtime Calls

Execute runtime API calls for specialized chain operations.

interface QueryableCalls<ApiType> {
  [api: string]: {
    [method: string]: (...args: any[]) => ApiType extends 'rxjs'
      ? Observable<any>
      : Promise<any>;
  };
}

Usage Examples

Basic Storage Queries

import { ApiPromise } from "@polkadot/api";

const api = await ApiPromise.create();

// Query account information
const account = "1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg";
const accountInfo = await api.query.system.account(account);
console.log(`Free balance: ${accountInfo.data.free.toHuman()}`);

// Query current timestamp
const timestamp = await api.query.timestamp.now();
console.log(`Current timestamp: ${timestamp.toNumber()}`);

// Query all validator candidates
const validators = await api.query.staking.validators.entries();
validators.forEach(([key, prefs]) => {
  const validator = key.args[0].toString();
  console.log(`Validator: ${validator}, Commission: ${prefs.commission.toNumber() / 10000000}%`);
});

Storage Subscriptions

import { ApiPromise } from "@polkadot/api";

const api = await ApiPromise.create();

// Subscribe to account balance changes
const account = "1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg";
const unsubscribe = await api.query.system.account(account, (accountInfo) => {
  console.log(`New balance: ${accountInfo.data.free.toHuman()}`);
});

// Stop subscription
// unsubscribe();

// Subscribe to block number changes
const unsubBlockNumber = await api.query.system.number((blockNumber) => {
  console.log(`Current block: ${blockNumber.toNumber()}`);
});

Multi-Query Operations

import { ApiPromise } from "@polkadot/api";

const api = await ApiPromise.create();

const account = "1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg";

// Query multiple storage entries at once
const [accountInfo, blockNumber, timestamp] = await api.queryMulti([
  [api.query.system.account, account],
  api.query.system.number,
  api.query.timestamp.now
]);

console.log(`Account: ${accountInfo.data.free.toHuman()}`);
console.log(`Block: ${blockNumber.toNumber()}`);
console.log(`Time: ${timestamp.toNumber()}`);

// Subscribe to multiple storage entries
const unsubscribe = await api.queryMulti([
  [api.query.system.account, account],
  api.query.system.number
], ([accountInfo, blockNumber]) => {
  console.log(`Block ${blockNumber}: Balance ${accountInfo.data.free.toHuman()}`);
});

Runtime Constants

import { ApiPromise } from "@polkadot/api";

const api = await ApiPromise.create();

// Access module constants
const existentialDeposit = api.consts.balances.existentialDeposit;
console.log(`Existential deposit: ${existentialDeposit.toHuman()}`);

const blockTime = api.consts.babe.expectedBlockTime;
console.log(`Expected block time: ${blockTime.toNumber()}ms`);

const maxNominators = api.consts.staking.maxNominatorRewardedPerValidator;
console.log(`Max nominators per validator: ${maxNominators.toNumber()}`);

Derived Queries

import { ApiPromise } from "@polkadot/api";

const api = await ApiPromise.create();

// Get best block number
const bestNumber = await api.derive.chain.bestNumber();
console.log(`Best block: ${bestNumber.toNumber()}`);

// Get account balance info with locks
const account = "1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg";
const balanceInfo = await api.derive.balances.all(account);
console.log(`Available balance: ${balanceInfo.availableBalance.toHuman()}`);
console.log(`Locked balance: ${balanceInfo.lockedBalance.toHuman()}`);

// Get validator exposure for current era
const currentEra = await api.query.staking.currentEra();
const validator = "1KvKReVmUiTc2LW2a4qyHy3PeGk1RbFw67rZE4TaFvZw6Z3";
const exposure = await api.derive.staking.account(validator);
console.log(`Total stake: ${exposure.stakingLedger?.total.toHuman()}`);

Runtime API Calls

import { ApiPromise } from "@polkadot/api";

const api = await ApiPromise.create();

// Get account next nonce
const account = "1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg";
const nonce = await api.rpc.system.accountNextIndex(account);
console.log(`Next nonce: ${nonce.toNumber()}`);

// Validate a transaction
const tx = api.tx.balances.transferAllowDeath(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(tx.toHex(), tx.encodedLength);
console.log(`Transaction fee: ${info.partialFee.toHuman()}`);

Storage Keys and Pagination

import { ApiPromise } from "@polkadot/api";

const api = await ApiPromise.create();

// Get storage key for specific query
const account = "1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg";
const key = api.query.system.account.key(account);
console.log(`Storage key: ${key.toHex()}`);

// Paginated storage queries
const validatorKeys = await api.query.staking.validators.keysPaged({
  pageSize: 100
});
console.log(`Found ${validatorKeys.length} validators`);

// Get all entries with pagination
let allValidators = [];
let lastKey = null;

do {
  const pageKeys = await api.query.staking.validators.keysPaged({
    pageSize: 100,
    startKey: lastKey
  });
  
  if (pageKeys.length === 0) break;
  
  const pageEntries = await api.query.staking.validators.multi(pageKeys);
  allValidators = allValidators.concat(pageEntries);
  lastKey = pageKeys[pageKeys.length - 1].toHex();
} while (true);

console.log(`Total validators: ${allValidators.length}`);

RxJS Storage Queries

import { ApiRx } from "@polkadot/api";
import { switchMap, map, combineLatest } from "rxjs";

const api$ = ApiRx.create();

// Subscribe to account balance changes with RxJS
api$.pipe(
  switchMap(api => api.query.system.account("1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg"))
).subscribe(accountInfo => {
  console.log(`Balance: ${accountInfo.data.free.toHuman()}`);
});

// Combine multiple storage subscriptions
api$.pipe(
  switchMap(api => 
    combineLatest([
      api.query.system.number(),
      api.query.timestamp.now()
    ])
  )
).subscribe(([blockNumber, timestamp]) => {
  console.log(`Block ${blockNumber} at ${new Date(timestamp.toNumber())}`);
});

Install with Tessl CLI

npx tessl i tessl/npm-polkadot--api

docs

api-initialization.md

blockchain-queries.md

events-metadata.md

index.md

network-providers.md

rpc-operations.md

transaction-submission.md

tile.json