Biblioteca da API Polkadot.js¶
Introdução¶
Polkadot.js é um conjunto de ferramentas que permite interagir com blockchains baseadas em Substrate, como a sua rede com Tanssi! A API Polkadot.js é um de seus componentes: uma biblioteca que permite aos desenvolvedores consultar a rede e interagir com as interfaces Substrate do nó usando JavaScript, possibilitando ler e escrever dados na rede.
Você pode usar a API Polkadot.js para consultar dados on-chain e enviar transações pelo lado Substrate da sua rede Tanssi. É possível consultar constantes do runtime, estado da cadeia, eventos, dados de transações (extrínsecas) e muito mais.
Aqui você encontra uma visão geral das funcionalidades disponíveis e exemplos de código em TypeScript para começar a interagir com sua rede Tanssi usando a biblioteca Polkadot.js API.
Nota do editor (atualização 2025)
Polkadot.js é o nome do conjunto de ferramentas para interação com blockchains Substrate. Embora o nome faça referência ao Polkadot, a biblioteca é agnóstica de cadeia e funciona com qualquer rede baseada em Substrate, incluindo o Tanssi.
Note
Os exemplos deste guia partem de um ambiente MacOS ou Ubuntu 20.04. Se estiver usando Windows, adapte os comandos conforme necessário.
Verifique também se você tem o Node.js e um gerenciador de pacotes (como npm ou yarn) instalados. Para saber como instalar o Node.js, consulte a documentação oficial.
Além disso, certifique-se de ter inicializado um arquivo package.json para módulos ES6. Você pode criar um package.json padrão com npm executando npm init --yes.
Instalar a API Polkadot.js¶
Primeiro, instale a biblioteca Polkadot.js API e a biblioteca RLP usando um gerenciador de pacotes como yarn. Ambas são necessárias para executar os exemplos deste guia.
Instale no diretório do projeto com:
npm i @polkadot/api
npm i @polkadot/util-rlp
yarn add @polkadot/api
yarn add @polkadot/util-rlp
A biblioteca também inclui outros componentes centrais, como o Keyring para gerenciamento de contas e utilitários usados ao longo do guia.
Criar uma instância do provedor da API¶
Para interagir com sua rede Tanssi usando a Polkadot.js API, crie uma instância da API. Construa o WsProvider usando o endpoint WebSocket da sua rede Tanssi.
// Importar
import { ApiPromise, WsProvider } from '@polkadot/api';
const main = async () => {
// Construir provedor da API
const wsProvider = new WsProvider('INSERT_NETWORK_WSS_ENDPOINT');
const api = await ApiPromise.create({ provider: wsProvider });
// Seu código aqui
await api.disconnect();
};
main();
Metadata e decoração dinâmica da API¶
Quando a API Polkadot.js se conecta a um nó, uma das primeiras ações é recuperar a metadata e decorar a API com base nela. A metadata fornece a estrutura:
api.<type>.<module>.<section>
Onde <type> pode ser:
query— endpoints de leitura de estadotx— endpoints relacionados a transaçõesrpc— endpoints específicos para chamadas RPCconsts— endpoints para constantes do runtime
Nada em api.{query, tx, rpc, consts}.<module>.<method> é hardcoded. Isso torna a biblioteca modular e adaptável a qualquer cadeia Substrate com diferentes módulos, como sua rede Tanssi.
Consultar dados on-chain¶
Consultas de estado¶
Recuperam informações sobre o estado atual da cadeia. Esses endpoints geralmente têm a forma api.query.<module>.<method>, decorados a partir da metadata. Liste endpoints inspecionando api.query, por exemplo:
console.log(api.query);
Após inicializar a API, você pode obter informações básicas de conta com:
// Definir endereço da carteira
const addr = 'INSERT_ADDRESS';
// Obter o último timestamp
const now = await api.query.timestamp.now();
// Obter saldo da conta e nonce atual via módulo system
const { nonce, data: balance } = await api.query.system.account(addr);
console.log(
`${now}: balance of ${balance.free} and a current nonce of ${nonce}`
);
Veja o script completo
import '@polkadot/api-augment';
import { ApiPromise, WsProvider } from '@polkadot/api';
const main = async () => {
// Construct API provider
const wsProvider = new WsProvider('INSERT_NETWORK_WSS_ENDPOINT');
const api = await ApiPromise.create({ provider: wsProvider });
// Define wallet address
const addr = 'INSERT_ADDRESS';
// Retrieve the last timestamp via the timestamp module
const now = await api.query.timestamp.now();
// Retrieve the account balance & current nonce via the system module
const { nonce, data: balance } = await api.query.system.account(addr);
console.log(
`${now}: balance of ${balance.free} and a current nonce of ${nonce}`
);
// Disconnect the API
await api.disconnect();
};
main();
Consultas RPC¶
As chamadas RPC são a base para transmissão de dados com o nó. Endpoints como api.query, api.tx ou api.derive encapsulam chamadas RPC, fornecendo informações no formato esperado pelo nó. Liste endpoints via:
console.log(api.rpc);
O api.rpc segue formato semelhante ao api.query. Por exemplo, após inicializar a API, obtenha dados da cadeia e o cabeçalho mais recente:
// Obter nome da cadeia
const chain = await api.rpc.system.chain();
// Obter o cabeçalho mais recente
const lastHeader = await api.rpc.chain.getHeader();
// Registrar as informações
console.log(
`${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}`
);
Veja o script completo
import { ApiPromise, WsProvider } from '@polkadot/api';
const main = async () => {
// Construct API provider
const wsProvider = new WsProvider('INSERT_NETWORK_WSS_ENDPOINT');
const api = await ApiPromise.create({ provider: wsProvider });
// Retrieve the chain name
const chain = await api.rpc.system.chain();
// Retrieve the latest header
const lastHeader = await api.rpc.chain.getHeader();
// Log the information
console.log(
`${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}`
);
// Disconnect the API
await api.disconnect();
};
main();
Consultas por assinatura¶
O rpc também oferece endpoints de assinatura. Após inicializar a API, você pode ouvir novos blocos:
// Obter nome da cadeia
const chain = await api.rpc.system.chain();
// Assinar novos cabeçalhos
await api.rpc.chain.subscribeNewHeads((lastHeader) => {
console.log(
`${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}`
);
});
O padrão geral em api.rpc.subscribe* é passar um callback que é acionado a cada novo item importado.
Chamadas em api.query.* também aceitam callbacks para modo assinado, inclusive chamadas com parâmetros. Exemplo para monitorar saldo de uma conta:
// Definir endereço da carteira
const addr = 'INSERT_ADDRESS';
// Assinar mudanças de saldo para uma conta específica
await api.query.system.account(addr, ({ nonce, data: balance }) => {
console.log(
`Free balance is ${balance.free} with ${balance.reserved} reserved and a nonce of ${nonce}`
);
});
Veja o script completo
import '@polkadot/api-augment';
import { ApiPromise, WsProvider } from '@polkadot/api';
const main = async () => {
// Construct API provider
const wsProvider = new WsProvider('INSERT_NETWORK_WSS_ENDPOINT');
const api = await ApiPromise.create({ provider: wsProvider });
// Retrieve the chain name
const chain = await api.rpc.system.chain();
// Subscribe to the new headers
await api.rpc.chain.subscribeNewHeads((lastHeader) => {
console.log(
`${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}`
);
});
// Define wallet address
const addr = 'INSERT_ADDRESS';
// Subscribe to balance changes for a specified account
await api.query.system.account(addr, ({ nonce, data: balance }) => {
console.log(
`Free balance is ${balance.free} with ${balance.reserved} reserved and a nonce of ${nonce}`
);
// Handle API disconnect here if needed
});
};
main();
Criar um Keyring para uma conta¶
O objeto Keyring mantém pares de chaves e assina quaisquer dados, seja transferência, mensagem ou interação com contrato.
Criar uma instância de Keyring¶
Instancie a classe Keyring e defina o tipo padrão de endereço. O padrão é sr25519, mas para redes Tanssi compatíveis com EVM use ethereum.
// Importe o keyring conforme necessário
import Keyring from '@polkadot/keyring';
// Crie uma instância de keyring (ECDSA)
const keyringECDSA = new Keyring({ type: 'ethereum' });
// Crie uma instância de keyring (SR25519)
const keyring = new Keyring({ type: 'sr25519' });
Adicionar uma conta ao Keyring¶
Há várias formas de adicionar contas, incluindo frase mnemônica e chave privada curta. Exemplos:
// Import the required packages
import Keyring from '@polkadot/keyring';
import { u8aToHex } from '@polkadot/util';
import { mnemonicToLegacySeed, hdEthereum } from '@polkadot/util-crypto';
// Import Ethereum account from mnemonic
const keyringECDSA = new Keyring({ type: 'ethereum' });
const mnemonic = 'INSERT_MNEMONIC';
// Define index of the derivation path and the derivation path
const index = 0;
const ethDerPath = "m/44'/60'/0'/0/" + index;
console.log(`Mnemonic: ${mnemonic}`);
console.log(`--------------------------\n`);
// Extract Ethereum address from mnemonic
const newPairEth = keyringECDSA.addFromUri(`${mnemonic}/${ethDerPath}`);
console.log(`Ethereum Derivation Path: ${ethDerPath}`);
console.log(`Derived Ethereum Address from Mnemonic: ${newPairEth.address}`);
// Extract private key from mnemonic
const privateKey = u8aToHex(
hdEthereum(mnemonicToLegacySeed(mnemonic, '', false, 64), ethDerPath)
.secretKey
);
console.log(`Derived Private Key from Mnemonic: ${privateKey}`);
// Import the required packages
import Keyring from '@polkadot/keyring';
// Import Ethereum account from private key
const keyringECDSA = new Keyring({ type: 'ethereum' });
const privateKeyInput = 'INSERT_PK';
// Extract address from private key
const otherPair = keyringECDSA.addFromUri(privateKeyInput);
console.log(`Derived Address from provided Private Key: ${otherPair.address}`);
// Import the required packages
import Keyring from '@polkadot/keyring';
import { cryptoWaitReady } from '@polkadot/util-crypto';
const main = async () => {
await cryptoWaitReady();
// Import SR25519 account from mnemonic
const keyring = new Keyring({ type: 'sr25519' });
const mnemonic = 'INSERT_MNEMONIC';
// Extract SR25519 address from mnemonic
const newPair = keyring.addFromUri(`${mnemonic}`);
console.log(`Derived SR25519 Address from Mnemonic: ${newPair.address}`);
};
main();
Enviando transações¶
Endpoints de transação têm a forma api.tx.<module>.<method>, decorados via metadata. Eles permitem enviar transações para inclusão em blocos — transferências, interações com pallets, ou qualquer coisa suportada. Liste endpoints via:
console.log(api.tx);
Enviar uma transação básica¶
A Polkadot.js API pode enviar transações. Supondo que você tenha inicializado a API e um keyring, use:
// Inicializar pares de chaves da carteira
const alice = keyring.addFromUri('INSERT_ALICES_PRIVATE_KEY');
// Montar a transação
const tx = await api.tx.balances.transferAllowDeath(
'INSERT_BOBS_ADDRESS',
BigInt(INSERT_VALUE)
);
// Obter o calldata codificado da transação
const encodedCallData = tx.method.toHex()
console.log(`Encoded calldata: ${encodedCallData}`);
// Assinar e enviar a transação
const txHash = await tx.signAndSend(alice);
// Exibir o hash da transação
console.log(`Submitted with hash ${txHash}`);
Veja o script completo
import { ApiPromise, WsProvider } from '@polkadot/api';
import Keyring from '@polkadot/keyring';
const main = async () => {
// Construct API provider
const wsProvider = new WsProvider('INSERT_NETWORK_WSS_ENDPOINT');
const api = await ApiPromise.create({ provider: wsProvider });
// Create a keyring instance (ECDSA)
const keyring = new Keyring({ type: 'ethereum' });
// Initialize wallet key pairs
const alice = keyring.addFromUri('INSERT_ALICES_PRIVATE_KEY');
// Form the transaction
const tx = await api.tx.balances.transferAllowDeath(
'INSERT_BOBS_ADDRESS',
BigInt(INSERT_VALUE)
);
// Retrieve the encoded calldata of the transaction
const encodedCalldata = tx.method.toHex();
console.log(`Encoded calldata: ${encodedCalldata}`);
// Sign and send the transaction
const txHash = await tx.signAndSend(alice);
// Show the transaction hash
console.log(`Submitted with hash ${txHash}`);
// Disconnect the API
await api.disconnect();
};
main();
Observe que signAndSend aceita parâmetros opcionais, como nonce, por exemplo signAndSend(alice, { nonce: aliceNonce }). Você pode usar o código da seção Consultas de estado para obter o nonce correto, incluindo transações no mempool.
Informações de taxa¶
Os endpoints de transação também oferecem um método para obter o peso de um api.tx.<module>.<method>. Use paymentInfo após montar a transação com o módulo e método específicos.
paymentInfo retorna informações de peso em refTime e proofSize, que podem ser usadas para determinar a taxa da transação — útil ao criar execuções remotas via XCM.
Exemplo, após inicializar a API, para obter peso de uma transferência simples:
// Transação para obter informações de peso
const tx = api.tx.balances.transferAllowDeath('INSERT_BOBS_ADDRESS', BigInt(INSERT_VALUE));
// Obter informações de peso
const { partialFee, weight } = await tx.paymentInfo('INSERT_SENDERS_ADDRESS');
console.log(`Transaction weight: ${weight}`);
console.log(`Transaction fee: ${partialFee.toHuman()}`);
Veja o script completo
import { ApiPromise, WsProvider } from '@polkadot/api';
const main = async () => {
// Construct API provider
const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT');
const api = await ApiPromise.create({ provider: wsProvider });
// Transaction to get weight information
const tx = api.tx.balances.transferAllowDeath('INSERT_BOBS_ADDRESS', BigInt(INSERT_VALUE));
// Get weight info
const { partialFee, weight } = await tx.paymentInfo('INSERT_SENDERS_ADDRESS');
console.log(`Transaction weight: ${weight}`);
console.log(`Transaction fee: ${partialFee.toHuman()}`);
// Disconnect the API
await api.disconnect();
};
main();
Eventos de transação¶
Qualquer transação emite eventos; no mínimo, haverá system.ExtrinsicSuccess ou system.ExtrinsicFailed, indicando sucesso ou falha na execução. Dependendo da transação, outros eventos podem ser emitidos, por exemplo balances.Transfer em uma transferência.
Agrupar transações¶
A Polkadot.js API permite processar transações em lote via api.tx.utility.batch. As transações são processadas sequencialmente de um único remetente. A taxa pode ser estimada com paymentInfo.
Assumindo que você tenha inicializado a API, um keyring e adicionado uma conta, o exemplo abaixo faz duas transferências em uma transação:
// Construir lista de transações para o batch
const txs = [
api.tx.balances.transferAllowDeath('INSERT_BOBS_ADDRESS', BigInt(INSERT_VALUE)),
api.tx.balances.transferAllowDeath('INSERT_CHARLEYS_ADDRESS', BigInt(INSERT_VALUE)),
];
// Estime as taxas como RuntimeDispatchInfo usando o assinante
// (endereço ou par de chaves bloqueado/desbloqueado)
const info = await api.tx.utility
.batch(txs)
.paymentInfo(alice);
console.log(`Estimated fees: ${info}`);
// Construir o batch e enviar as transações
await api.tx.utility
.batch(txs)
.signAndSend(alice, ({ status }) => {
if (status.isInBlock) {
console.log(`included in ${status.asInBlock}`);
// Desconecte a API aqui!
}
});
Veja o script completo
import { ApiPromise, WsProvider } from '@polkadot/api';
import Keyring from '@polkadot/keyring';
const main = async () => {
// Construct API provider
const wsProvider = new WsProvider('INSERT_NETWORK_WSS_ENDPOINT');
const api = await ApiPromise.create({ provider: wsProvider });
// Create a keyring instance (ECDSA)
const keyring = new Keyring({ type: 'ethereum' });
// Initialize wallet key pairs
const alice = keyring.addFromUri('INSERT_ALICES_PRIVATE_KEY');
// Construct a list of transactions to batch
const txs = [
api.tx.balances.transferAllowDeath('INSERT_BOBS_ADDRESS', BigInt(INSERT_VALUE)),
api.tx.balances.transferAllowDeath('INSERT_CHARLEYS_ADDRESS', BigInt(INSERT_VALUE)),
];
// Estimate the fees as RuntimeDispatchInfo, using the signer (either
// address or locked/unlocked keypair)
const info = await api.tx.utility.batch(txs).paymentInfo(alice);
console.log(`Estimated fees: ${info}`);
// Construct the batch and send the transactions
await api.tx.utility.batch(txs).signAndSend(alice, async ({ status }) => {
if (status.isInBlock) {
console.log(`Included in ${status.asInBlock}`);
// Disconnect the API
await api.disconnect();
}
});
};
main();
Código de exemplo para monitorar transferências do token nativo¶
Os códigos a seguir mostram como escutar transferências do token nativo, enviadas via Substrate ou Ethereum API, usando a biblioteca Polkadot.js ou o Substrate API Sidecar. Os snippets são para demonstração e precisam de ajustes e testes antes de produção.
O snippet abaixo usa subscribeFinalizedHeads para assinar cabeçalhos de blocos finalizados, percorre as extrínsecas do bloco e recupera eventos de cada extrínseca. Se encontrar um evento balances.Transfer, extrai from, to, amount e o tx hash e mostra no console. O amount aparece na menor unidade (Wei). Veja a documentação oficial para detalhes da API Polkadot.js e do JSON RPC do Substrate.
import '@polkadot/api-augment';
import { ApiPromise, WsProvider } from '@polkadot/api';
// This script will listen to all Native token transfers (Substrate & Ethereum) and extract the tx hash
// It can be adapted for any Tanssi-powered network
const main = async () => {
// Define the provider
const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT');
// Create the provider
const polkadotApi = await ApiPromise.create({
provider: wsProvider,
});
// Subscribe to finalized blocks
await polkadotApi.rpc.chain.subscribeFinalizedHeads(
async (lastFinalizedHeader) => {
const [{ block }, records] = await Promise.all([
polkadotApi.rpc.chain.getBlock(lastFinalizedHeader.hash),
(await polkadotApi.at(lastFinalizedHeader.hash)).query.system.events(),
]);
block.extrinsics.forEach((extrinsic, index) => {
const {
method: { args, method, section },
} = extrinsic;
const isEthereum = section == 'ethereum' && method == 'transact';
// Gets the transaction object
const tx = args[0] as any;
// Convert to the correct Ethereum Transaction format
const ethereumTx =
isEthereum &&
((tx.isLegacy && tx.asLegacy) ||
(tx.isEip1559 && tx.asEip1559) ||
(tx.isEip2930 && tx.asEip2930));
// Check if the transaction is a transfer
const isEthereumTransfer =
ethereumTx &&
ethereumTx.input.length === 0 &&
ethereumTx.action.isCall;
// Retrieve all events for this extrinsic
const events = records.filter(
({ phase }) =>
phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index)
);
// This hash will only exist if the transaction was executed through Ethereum.
let ethereumHash = '';
if (isEthereum) {
// Search for Ethereum execution
events.forEach(({ event }) => {
if (event.section == 'ethereum' && event.method == 'Executed') {
ethereumHash = event.data[2].toString();
}
});
}
// Search if it is a transfer
events.forEach(({ event }) => {
if (event.section == 'balances' && event.method == 'Transfer') {
const from = event.data[0].toString();
const to = event.data[1].toString();
const balance = (event.data[2] as any).toBigInt();
const substrateHash = extrinsic.hash.toString();
console.log(
`Transfer from ${from} to ${to} of ${balance} (block #${lastFinalizedHeader.number})`
);
console.log(` - Triggered by extrinsic: ${substrateHash}`);
if (isEthereum) {
console.log(
` - Ethereum (isTransfer: ${isEthereumTransfer}) hash: ${ethereumHash}`
);
}
}
});
});
}
);
};
main();
Há mais exemplos de transferências neste gist.
Funções utilitárias¶
A API Polkadot.js inclui utilitários para primitivas criptográficas e funções de hash.
O exemplo a seguir calcula o hash determinístico de uma transação Ethereum legacy crua: primeiro gera a codificação RLP (Recursive Length Prefix) e depois aplica keccak256.
import { encode } from '@polkadot/util-rlp';
import { keccakAsHex } from '@polkadot/util-crypto';
import { numberToHex } from '@polkadot/util';
// Defina o tipo da chave como string
type txType = {
[key: string]: any;
};
// Defina a transação assinada bruta
const txData: txType = {
nonce: numberToHex(1),
gasPrice: numberToHex(21000000000),
gasLimit: numberToHex(21000),
to: '0xc390cC49a32736a58733Cf46bE42f734dD4f53cb',
value: numberToHex(1000000000000000000),
data: '',
v: '0507',
r: '0x5ab2f48bdc6752191440ce62088b9e42f20215ee4305403579aa2e1eba615ce8',
s: '0x3b172e53874422756d48b449438407e5478c985680d4aaa39d762fe0d1a11683',
};
// Extraia os valores para um array
var txDataArray = Object.keys(txData).map(function (key) {
return txData[key];
});
// Calcule a transação codificada em RLP
var encoded_tx = encode(txDataArray);
// Faça o hash da transação codificada usando keccak256
console.log(keccakAsHex(encoded_tx));
Consulte o repositório NPM para a lista de métodos disponíveis em @polkadot/util-crypto e suas descrições.
| Criada: 9 de dezembro de 2025