Ir para o conteúdo

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 estado
  • tx — endpoints relacionados a transações
  • rpc — endpoints específicos para chamadas RPC
  • consts — 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.

As informações apresentadas aqui foram fornecidas por terceiros e estão disponíveis apenas para fins informativos gerais. A Tanssi não endossa nenhum projeto listado e descrito no Site de Documentação da Tanssi (https://docs.tanssi.network/). A Tanssi Foundation não garante a precisão, integridade ou utilidade dessas informações. Qualquer confiança depositada nelas é de sua exclusiva responsabilidade. A Tanssi Foundation se exime de toda responsabilidade decorrente de qualquer confiança que você ou qualquer outra pessoa possa ter em qualquer parte deste conteúdo. Todas as declarações e/ou opiniões expressas nesses materiais são de responsabilidade exclusiva da pessoa ou entidade que as fornece e não representam necessariamente a opinião da Tanssi Foundation. As informações aqui não devem ser interpretadas como aconselhamento profissional ou financeiro de qualquer tipo. Sempre busque orientação de um profissional devidamente qualificado em relação a qualquer assunto ou circunstância em particular. As informações aqui podem conter links ou integração com outros sites operados ou conteúdo fornecido por terceiros, e tais sites podem apontar para este site. A Tanssi Foundation não tem controle sobre esses sites ou seu conteúdo e não terá responsabilidade decorrente ou relacionada a eles. A existência de qualquer link não constitui endosso desses sites, de seu conteúdo ou de seus operadores. Esses links são fornecidos apenas para sua conveniência, e você isenta e exonera a Tanssi Foundation de qualquer responsabilidade decorrente do uso dessas informações ou das informações fornecidas por qualquer site ou serviço de terceiros.
Última atualização: 9 de dezembro de 2025
| Criada: 9 de dezembro de 2025