Encoding utilities and token formatting for the @polkadot-apps ecosystem.
pnpm add @polkadot-apps/utils
General-purpose byte encoding/decoding functions for working with hex strings, UTF-8 text, and byte arrays.
import { bytesToHex, hexToBytes, utf8ToBytes, concatBytes } from "@polkadot-apps/utils";
const hex = bytesToHex(new Uint8Array([0xab, 0xcd])); // "abcd"
const bytes = hexToBytes("abcd"); // Uint8Array [0xab, 0xcd]
const text = utf8ToBytes("hello"); // Uint8Array [104, 101, 108, 108, 111]
const combined = concatBytes(header, payload);
Deterministic 32-byte hash functions used across the Polkadot ecosystem.
import { blake2b256, sha256, keccak256, bytesToHex } from "@polkadot-apps/utils";
const hash = blake2b256(new TextEncoder().encode("hello"));
console.log(bytesToHex(hash)); // 64-char hex string
// SHA2-256 (bulletin-deploy default)
const sha = sha256(data);
// Keccak-256 (Ethereum compatibility)
const kek = keccak256(data);
Convert between raw planck values (the smallest indivisible token unit on Substrate chains) and human-readable decimal strings.
import { formatPlanck, parseToPlanck } from "@polkadot-apps/utils";
// Format planck to human-readable (default: 10 decimals for DOT)
formatPlanck(10_000_000_000n); // "1.0"
formatPlanck(15_000_000_000n); // "1.5"
formatPlanck(12_345_678_900n); // "1.23456789"
formatPlanck(0n); // "0.0"
// Parse human-readable to planck
parseToPlanck("1.5"); // 15_000_000_000n
parseToPlanck("100"); // 1_000_000_000_000n
// Custom decimals for other chains
formatPlanck(1_000_000_000_000n, 12); // "1.0"
parseToPlanck("1.0", 12); // 1_000_000_000_000n
Format planck values for display with locale-aware thousand separators, configurable decimal precision, and optional token symbol.
import { formatBalance } from "@polkadot-apps/utils";
formatBalance(10_000_000_000n); // "1"
formatBalance(15_000_000_000n, { symbol: "DOT" }); // "1.5 DOT"
formatBalance(10_000_000_000_000n, { symbol: "DOT" }); // "1,000 DOT"
formatBalance(12_345_678_900n, { maxDecimals: 2 }); // "1.23"
formatBalance(0n, { symbol: "DOT" }); // "0 DOT"
// Custom chain decimals and locale
formatBalance(1_000_000_000_000n, { decimals: 12, symbol: "KSM", locale: "de-DE" });
Unlike the Number() approach used in some apps, formatBalance preserves full BigInt precision for balances of any size.
Query on-chain balances with a typed convenience wrapper. Works with any PAPI typed API via structural typing — no extra dependencies.
import { getBalance, formatBalance } from "@polkadot-apps/utils";
const balance = await getBalance(api.assetHub, aliceAddress);
console.log(formatBalance(balance.free, { symbol: "DOT" })); // "1,000.5 DOT"
console.log(formatBalance(balance.reserved, { symbol: "DOT" })); // "50 DOT"
| Function | Signature | Returns |
|---|---|---|
bytesToHex |
(bytes: Uint8Array) |
string (lowercase, no 0x prefix) |
hexToBytes |
(hex: string) |
Uint8Array (no 0x prefix expected) |
utf8ToBytes |
(str: string) |
Uint8Array |
concatBytes |
(...arrays: Uint8Array[]) |
Uint8Array |
| Function | Signature | Returns | Description |
|---|---|---|---|
blake2b256 |
(data: Uint8Array) |
Uint8Array (32 bytes) |
BLAKE2b-256 — Polkadot default |
sha256 |
(data: Uint8Array) |
Uint8Array (32 bytes) |
SHA2-256 — bulletin-deploy default |
keccak256 |
(data: Uint8Array) |
Uint8Array (32 bytes) |
Keccak-256 — Ethereum compatibility |
| Function | Signature | Returns |
|---|---|---|
formatPlanck |
(planck: bigint, decimals?: number) |
string |
parseToPlanck |
(amount: string, decimals?: number) |
bigint |
formatBalance |
(planck: bigint, options?: FormatBalanceOptions) |
string |
| Function | Signature | Returns |
|---|---|---|
getBalance |
(api: BalanceApi, address: string) |
Promise<AccountBalance> |
formatPlanck(planck, decimals = 10)
Convert a planck bigint to a human-readable decimal string. Trailing zeros are trimmed but at least one fractional digit is always shown (e.g. "1.0", not "1").
RangeError if planck < 0n.RangeError if decimals is not a non-negative integer.parseToPlanck(amount, decimals = 10)
Parse a decimal string into its planck bigint representation. If the fractional part exceeds decimals, excess digits are truncated with a warning.
Error if amount is empty or contains invalid characters.RangeError if amount is negative or decimals is invalid.formatBalance(planck, options?)
Format a planck value for display with locale-aware thousand separators. Builds on formatPlanck for BigInt precision.
Options: { decimals?: number, maxDecimals?: number, symbol?: string, locale?: string }. Defaults: decimals = 10, maxDecimals = 4, no symbol, user's locale.
RangeError if planck < 0n or decimals is invalid (delegated to formatPlanck).getBalance(api, address): Promise<AccountBalance>
Query the free, reserved, and frozen balances for an address. Returns { free: bigint, reserved: bigint, frozen: bigint }. Uses structural typing — works with any PAPI typed API that has System.Account.
0x-prefixed string to hexToBytes. The @noble/hashes implementation expects raw hex without a prefix. Strip it first: hexToBytes(hex.slice(2)).formatPlanck with the wrong decimals for a chain. DOT uses 10, KSM uses 12, many parachains use 18. Always check the chain's token metadata.parseToPlanck rounds excess decimals. It truncates, not rounds. parseToPlanck("1.999999999999", 10) gives the same result as parseToPlanck("1.9999999999", 10).Number() to format large balances. Number(raw) / 10**decimals loses precision for values > 2^53 planck (~900 DOT). Use formatBalance which preserves full BigInt precision.getBalance. Pass the chain-specific TypedApi (e.g., client.assetHub), not the multi-chain ChainClient object.Apache-2.0
@polkadot-apps/utils — Encoding, hashing, token formatting, and balance querying for the Polkadot app ecosystem.
Provides general-purpose byte encoding/decoding (
bytesToHex,hexToBytes,utf8ToBytes,concatBytes), 32-byte hash functions (blake2b256,sha256,keccak256), Substrate token formatting (formatPlanck,parseToPlanck,formatBalance), and typed balance queries (getBalance). All functions are framework-agnostic.