Promise and RxJS wrappers around the Polkadot JS RPC for interacting with Polkadot and Substrate-based blockchains
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
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;
}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>;
}Access module constants (parameter types) from the runtime.
interface QueryableConsts<ApiType> {
[section: string]: {
[constant: string]: any;
};
}Access computed data that combines multiple storage queries.
interface AllDerives<ApiType> {
[section: string]: {
[method: string]: (...args: any[]) => ApiType extends 'rxjs'
? Observable<any>
: Promise<any>;
};
}Execute runtime API calls for specialized chain operations.
interface QueryableCalls<ApiType> {
[api: string]: {
[method: string]: (...args: any[]) => ApiType extends 'rxjs'
? Observable<any>
: Promise<any>;
};
}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}%`);
});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()}`);
});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()}`);
});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()}`);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()}`);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()}`);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}`);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