Usando o Substrate API Sidecar¶
Introdução¶
O Substrate API Sidecar permite que aplicações acessem blocos, saldo de contas e outras informações de blockchains baseadas em Substrate por meio de uma API REST. Isso é útil para exchanges, carteiras ou outras aplicações que precisam acompanhar saldo e mudanças de estado em uma rede powered by Tanssi. Esta página descreve como instalar e executar o Substrate API Sidecar para uma rede Tanssi e os endpoints mais usados.
Instalando e Executando o Substrate API Sidecar¶
Existem várias formas de instalar e executar o Substrate API Sidecar. Este guia descreve os passos para instalá-lo e executá-lo localmente via NPM. Para uso via Docker ou build e execução a partir do código-fonte, consulte o repositório oficial do Substrate API Sidecar.
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.
Instalando o Substrate API Sidecar¶
Para instalar o serviço localmente no diretório atual, execute:
npm install @substrate/api-sidecar@20.2.2
Note
Se a pasta não tiver um projeto Node.js, crie manualmente node_modules com mkdir node_modules.
O Substrate API Sidecar v20.2.2 é a versão estável atual testada com redes Tanssi. Verifique a instalação a partir da raiz do diretório:
node_modules/.bin/substrate-api-sidecar --version
Configurando o Substrate API Sidecar¶
No terminal em que o Sidecar rodará, exporte a variável de ambiente com o endpoint WS da rede que deseja usar. Exemplos:
export SAS_SUBSTRATE_URL=wss://services.tanssi-mainnet.network/tanssi
export SAS_SUBSTRATE_URL=wss://services.tanssi-testnet.network/dancelight
export SAS_SUBSTRATE_URL=wss://services.tanssi-testnet.network/dancelight-2001/
export SAS_SUBSTRATE_URL=INSERIR_ENDPOINT_WSS_DA_REDE
Depois de definir, confirme com:
echo $SAS_SUBSTRATE_URL
Ele deve exibir o endpoint configurado.
Executando o Substrate API Sidecar¶
Com a variável de ambiente configurada e a partir da raiz da instalação, execute:
node_modules/.bin/substrate-api-sidecar
Se a instalação e configuração estiverem corretas, verá uma saída semelhante a:
Endpoints do Substrate API Sidecar¶
Endpoints comuns:
- GET /blocks/head — bloco finalizado mais recente. O parâmetro opcional
finalized=falseretorna o bloco mais novo, possivelmente não finalizado - GET /blocks/head/header — cabeçalho do último bloco.
finalized=falseopcional - GET /blocks/{blockId} — bloco por altura ou hash
- GET /accounts/{accountId}/balance-info — saldo e informações da conta
- GET /node/version — implementação e versão do nó Substrate
- GET /runtime/metadata — metadata do runtime em JSON decodificado
Para a lista completa, consulte a documentação oficial.
Mapeamento de Campos no Objeto JSON do Bloco¶
O Sidecar retorna blocos em JSON. Parte do objeto é a estrutura aninhada das extrínsecas processadas em um bloco específico. Cada extrínseca chama um método de um módulo. Em linhas gerais, a estrutura é:
RESPONSE JSON Block Object:
|--extrinsics
|--{extrinsic_number}
|--method
|--pallet: "MODULE_NAME"
|--method: "METHOD_NAME"
|--signature
|--nonce
|--args
|--transaction
|--{transaction_type}
|--hash
|--events
|--{event_number}
|--method
|--pallet: "MODULE_NAME"
|--method: "METHOD_EVENT_NAME"
|--data
|--0
|--1
|--2
|--3
...
Saber o módulo e método chamados permite extrair informações específicas (por exemplo, transferências de saldo).
Mapeamento EVM em Blocos¶
Para redes EVM da Tanssi, execuções EVM são identificadas por:
{extrinsic_number}.method.pallet = "ethereum"
{extrinsic_number}.method.method = "transact"
Estrutura aninhada:
RESPONSE JSON Block Object:
|--extrinsics
|--{extrinsic_number}
|--method
|--pallet: "ethereum"
|--method: "transact"
|--signature
|--nonce
|--args
|--transaction
|--{transaction_type}
|--hash
|--events
|--{event_number}
|--method
|--pallet: "ethereum"
|--method: "Executed"
|--data
|--0
|--1
|--2
|--3
...
Para transações Substrate, campos como “Nonce” e “Signature” ficam em:
extrinsics[extrinsic_number]
Tipos de Transação EVM e Payload¶
As redes EVM da Tanssi suportam legacy, eip1559 e eip2930. Cada tipo contém o seguinte payload:
...
|--eip1559
|--chainId
|--nonce
|--maxPriorityFeePerGas
|--maxFeePerGas
|--gasLimit
|--action
|--value
|--input
|--accessList
|--oddYParity
|--r
|--s
...
...
|--legacy
|--nonce
|--gasPrice
|--gasLimit
|--action
|--value
|--input
|--signature
...
...
|--eip2930
|--chainId
|--nonce
|--gasPrice
|--gasLimit
|--action
|--value
|--input
|--accessList
|--oddYParity
|--r
|--s
...
Para mais detalhes sobre EIP1559 e EIP2930, veja as especificações oficiais.
Mapeamento de Campos da Transação¶
Para obter remetente, destinatário e hash EVM de qualquer transação, verifique o evento em que:
{event_number}.method.pallet: "ethereum"
{event_number}.method.method: "Executed"
Mapeamentos:
| Campo EVM | Campo JSON do bloco |
|---|---|
| Chain ID | extrinsics[extrinsic_number].args.transaction.eip1559.chainId |
| Nonce | extrinsics[extrinsic_number].args.transaction.eip1559.nonce |
| Max priority fee/gas | extrinsics[extrinsic_number].args.transaction.eip1559.maxPriorityFeePerGas |
| Max fee per gas | extrinsics[extrinsic_number].args.transaction.eip1559.maxFeePerGas |
| Gas limit | extrinsics[extrinsic_number].args.transaction.eip1559.gasLimit |
| Access list | extrinsics[extrinsic_number].args.transaction.eip1559.accessList |
| Assinatura | extrinsics[extrinsic_number].args.transaction.eip1559.oddYParity/r/s |
| Endereço remetente | extrinsics[extrinsic_number].events[event_number].data[0] |
| Endereço destinatário | extrinsics[extrinsic_number].events[event_number].data[1] |
| Hash EVM | extrinsics[extrinsic_number].events[event_number].data[2] |
| Status de execução | extrinsics[extrinsic_number].events[event_number].data[3] |
| Campo EVM | Campo JSON do bloco |
|---|---|
| Nonce | extrinsics[extrinsic_number].args.transaction.legacy.nonce |
| Gas price | extrinsics[extrinsic_number].args.transaction.legacy.gasPrice |
| Gas limit | extrinsics[extrinsic_number].args.transaction.legacy.gasLimit |
| Valor | extrinsics[extrinsic_number].args.transaction.legacy.value |
| Assinatura | extrinsics[extrinsic_number].args.transaction.legacy.signature |
| Remetente EVM | extrinsics[extrinsic_number].events[event_number].data[0] |
| Destinatário EVM | extrinsics[extrinsic_number].events[event_number].data[1] |
| Hash EVM | extrinsics[extrinsic_number].events[event_number].data[2] |
| Status execução | extrinsics[extrinsic_number].events[event_number].data[3] |
| Campo EVM | Campo JSON do bloco |
|---|---|
| Chain ID | extrinsics[extrinsic_number].args.transaction.eip2930.chainId |
| Nonce | extrinsics[extrinsic_number].args.transaction.eip2930.nonce |
| Gas price | extrinsics[extrinsic_number].args.transaction.eip2930.gasPrice |
| Gas limit | extrinsics[extrinsic_number].args.transaction.eip2930.gasLimit |
| Valor | extrinsics[extrinsic_number].args.transaction.eip2930.value |
| Access list | extrinsics[extrinsic_number].args.transaction.eip2930.accessList |
| Assinatura | extrinsics[extrinsic_number].args.transaction.eip2930.oddYParity/r/s |
| Remetente EVM | extrinsics[extrinsic_number].events[event_number].data[0] |
| Destinatário EVM | extrinsics[extrinsic_number].events[event_number].data[1] |
| Hash EVM | extrinsics[extrinsic_number].events[event_number].data[2] |
| Status execução | extrinsics[extrinsic_number].events[event_number].data[3] |
Para transações EVM, campos como “Nonce” e “Signature” ficam em:
extrinsics[extrinsic_number].args.transaction[transaction_type]
Assim, “Nonce” e “Signature” no nível Substrate (extrinsics[extrinsic_number]) ficam null.
Uma transação EVM bem-sucedida retorna succeed: "Stopped" ou succeed: "Returned" no campo de status de execução EVM.
Monitorar Transferências de Tokens¶
Os trechos a seguir mostram como escutar transferências do token nativo enviadas via Substrate ou Ethereum API, e transferências de tokens ERC-20 via Ethereum API, usando o Substrate API Sidecar. Transferências pela Ethereum API se aplicam apenas a redes EVM da Tanssi.
Transferências de Token Nativo¶
Redes Tanssi EVM e não-EVM podem fazer transferências de saldo nativas baseadas em Substrate.
O snippet abaixo usa Axios para consultar o endpoint /blocks/head para o último bloco finalizado, e decodifica from, to, value, tx hash e transaction status de transferências nativas tanto no nível EVM quanto Substrate.
import axios from 'axios';
// This script will decode all native token transfers (Substrate & Ethereum)
// in a given Sidecar block, and extract the tx hash. It can be adapted for
// any Tanssi-powered network.
// Endpoint to retrieve the latest block
const endpoint = 'http://127.0.0.1:8080/blocks/head';
async function main() {
try {
// Retrieve the block from the Sidecar endpoint
const response = await axios.get(endpoint);
// Retrieve the block height of the current block
console.log('Block Height: ' + response.data.number);
// Iterate through all extrinsics in the block
response.data.extrinsics.forEach((extrinsic) => {
// Retrieve Ethereum Transfers
if (
extrinsic.method.pallet === 'ethereum' &&
extrinsic.method.method === 'transact'
) {
// Get the value for any of the three EIP transaction standards supported
const value =
(extrinsic.args.transaction.legacy &&
extrinsic.args.transaction.legacy.value) ||
(extrinsic.args.transaction.eip1559 &&
extrinsic.args.transaction.eip1559.value) ||
(extrinsic.args.transaction.eip2930 &&
extrinsic.args.transaction.eip2930.value);
// Iterate through the events to get transaction details
extrinsic.events.forEach((event) => {
if (
event.method.pallet === 'ethereum' &&
event.method.method === 'Executed'
) {
console.log('From: ' + event.data[0]);
console.log('To: ' + event.data[1]);
console.log('Tx Hash: ' + event.data[2]);
console.log('Value: ' + value);
// Check the execution status
if (event.data[3].succeed) {
console.log('Status: Success');
} else {
console.log('Status: Failed');
}
}
});
}
// Retrieve Substrate Transfers
if (
extrinsic.method.pallet === 'balances' &&
(extrinsic.method.method === 'transferKeepAlive' ||
extrinsic.method.method === 'transfer')
) {
// Iterate through the events to get transaction details
extrinsic.events.forEach((event) => {
if (
event.method.pallet === 'balances' &&
event.method.method === 'Transfer'
) {
console.log('From: ' + event.data[0]);
console.log('To: ' + event.data[1]);
console.log('Tx Hash: ' + extrinsic.hash);
console.log('Value: ' + event.data[2]);
// Check the execution status
if (extrinsic.success) {
console.log('Status: Success');
} else {
console.log('Status: Failed');
}
}
});
}
});
} catch (err) {
console.log(err);
}
}
main();
Transferências de Tokens ERC-20¶
Eventos emitidos por smart contracts (como um contrato ERC-20 implantado em redes EVM da Tanssi) podem ser decodificados a partir do JSON do bloco. A estrutura é:
RESPONSE JSON Block Object:
|--extrinsics
|--{extrinsic_number}
|--method
|--pallet: "ethereum"
|--method: "transact"
|--signature:
|--nonce:
|--args
|--transaction
|--{transaction_type}
|--hash
|--events
|--{event_number}
|--method
|--pallet: "evm"
|--method: "Log"
|--data
|--0
|-- address
|-- topics
|--0
|--1
|--2
\t\t\t\t |-- data
...
...
Transferências ERC-20 emitem o evento Transfer, que pode ser decodificado assim:
| Informação da tx | Campo JSON do bloco |
|---|---|
| Endereço do contrato | extrinsics[extrinsic_number].events[event_number].data[0].address |
| Hash da assinatura | extrinsics[extrinsic_number].events[event_number].data[0].topics[0] |
| Endereço remetente | extrinsics[extrinsic_number].events[event_number].data[0].topics[1] |
| Endereço destinatário | extrinsics[extrinsic_number].events[event_number].data[0].topics[2] |
| Quantia | extrinsics[extrinsic_number].events[event_number].data[0].data |
Outros eventos de contratos EVM podem ser decodificados de modo semelhante; o conteúdo de topics e data muda conforme a definição do evento.
Note
A quantia transferida leva em conta as casas decimais e vem em hexadecimal.
Taxas de Transação na Substrate API¶
Para redes Tanssi EVM e não-EVM, todas as informações sobre taxas de transações enviadas via Substrate API podem ser extraídas do endpoint:
GET /blocks/{blockId}
Os endpoints de bloco retornam dados de um ou mais blocos. Saiba mais na documentação oficial do Sidecar.
Lendo como JSON, para um pallet (módulo) e method, a taxa da transação vem de um evento com:
{event_number}.method.pallet: "transactionPayment"
{event_number}.method.method: "TransactionFeePaid"
Estrutura relevante:
RESPONSE JSON Block Object:
...
|--number
|--extrinsics
|--{extrinsic_number}
|--method
|--signature
|--nonce
|--args
|--tip
|--hash
|--info
|--era
|--events
|--{event_number}
|--method
|--pallet: "transactionPayment"
|--method: "TransactionFeePaid"
|--data
|--0
|--1
|--2
...
Mapeamento:
| Informação da tx | Campo JSON do bloco |
|---|---|
| Conta que paga | extrinsics[extrinsic_number].events[event_number].data[0] |
| Taxas totais | extrinsics[extrinsic_number].events[event_number].data[1] |
| Gorjeta (tip) | extrinsics[extrinsic_number].events[event_number].data[2] |
A taxa total paga para a extrínseca está em:
extrinsics[extrinsic_number].events[event_number].data[1]
Taxas de Transação na Ethereum API¶
Para redes EVM da Tanssi, usuários também podem enviar fundos via Ethereum API. Para calcular a taxa de uma transação Ethereum, use:
GasPrice = BaseFee + MaxPriorityFeePerGas < MaxFeePerGas ?
BaseFee + MaxPriorityFeePerGas :
MaxFeePerGas;
Transaction Fee = (GasPrice * TransactionWeight) / 25000
Transaction Fee = (GasPrice * TransactionWeight) / 25000
Transaction Fee = (GasPrice * TransactionWeight) / 25000
As seções a seguir detalham cada componente.
Base Fee¶
A BaseFee é o valor mínimo cobrado para enviar uma transação e é definida pela rede. Foi introduzida na EIP-1559. Redes EVM da Tanssi usam um mecanismo dinâmico semelhante ao da EIP-1559, ajustando a base fee conforme congestionamento.
No template EVM da Tanssi, a gas price mínima é 1 GWei.
A BaseFee pode ser obtida em baseFeePerGas do módulo baseFee:
GET /pallets/baseFee/storage/baseFeePerGas?at={blockId}
Estrutura relevante:
RESPONSE JSON Storage Object:
|--at
|--hash
|--height
|--pallet
|--palletIndex
|--storageItem
|--keys
|--value
O valor está em value (fixed point); divida pelas casas decimais para obter o valor real.
GasPrice, MaxFeePerGas e MaxPriorityFeePerGas¶
GasPrice define o gas price em transações legacy (pré‑EIP-1559). MaxFeePerGas e MaxPriorityFeePerGas foram introduzidos com a EIP-1559 junto da BaseFee. MaxFeePerGas define a taxa máxima por unidade de gas (BaseFee + MaxPriorityFeePerGas). MaxPriorityFeePerGas é a gorjeta máxima configurada para priorizar a transação.
Embora redes EVM da Tanssi sejam compatíveis com Ethereum, são cadeias Substrate, e prioridades funcionam de forma diferente: no Substrate transações não são priorizadas por gas price. O Tanssi usa um sistema de priorização ajustado que reordena transações Substrate com base na taxa por gas (derivada de tip e weight). Para transações Ethereum, a prioridade é definida pela priority fee.
Nota: prioridade não é o único fator para ordenar transações; longevidade também influencia.
Os valores de GasPrice, MaxFeePerGas e MaxPriorityFeePerGas podem ser lidos do JSON do bloco conforme descrito em Mapeamento EVM.
Os dados de uma transação Ethereum em um bloco podem ser obtidos de:
GET /blocks/{blockId}
Trajetos relevantes:
| Campo EVM | Campo JSON |
|---|---|
| MaxFeePerGas | extrinsics[extrinsic_number].args.transaction.eip1559.maxFeePerGas |
| MaxPriorityFeePerGas | extrinsics[extrinsic_number].args.transaction.eip1559.maxPriorityFeePerGas |
| Campo EVM | Campo JSON |
|---|---|
| GasPrice | extrinsics[extrinsic_number].args.transaction.legacy.gasPrice |
| Campo EVM | Campo JSON |
|---|---|
| GasPrice | extrinsics[extrinsic_number].args.transaction.eip2930.gasPrice |
Transaction Weight¶
TransactionWeight mede o Runtime de uma transação no bloco. Para todos os tipos, pode ser obtido no evento da extrínseca em que:
pallet: "system", method: "ExtrinsicSuccess"
E então TransactionWeight está em:
extrinsics[extrinsic_number].events[event_number].data[0].weight
| Criada: 7 de janeiro de 2026
