API de saldos de tokens de carteira: ativos ERC-20 e histórico de transferências

Crie uma página de ativos de carteira com saldos ERC-20 diferentes de zero, histórico de transferências e metadados em lote. Verifique a cobertura da rede, pagine resultados e ajuste quantidades inteiras pelas casas decimais.

Crie uma página de ativos de carteira com a API de dados de carteiras blockchain: use a API de saldos de tokens para posições ERC-20 diferentes de zero e a API de transferências de tokens para o histórico da carteira. Desenvolvedores e agentes de IA usam as mesmas requisições autenticadas. Antes de consultar, leia GET /v1/status e verifique data_features e data_status da rede selecionada; a cobertura de saldos varia por rede. Os parâmetros de requisição e esquemas de resposta estão na referência da Data API.

Tarefas que este guia ajuda a concluir

Os três tipos de dados de uma página de ativos de carteira

Uma página de ativos de carteira pode exibir os saldos de tokens ERC-20, o histórico de transferências de tokens e os metadados de tokens de um endereço. A Data API oferece um endpoint para cada tipo:

  • Saldos: GET /{chain}/addresses/{address}/balances retorna os saldos ERC-20 diferentes de zero do endereço, ordenados por endereço token em ordem crescente, com symbol e decimals do token quando disponíveis. Um endereço sem saldos retorna 200 com data: [].
  • Transferências: GET /{chain}/addresses/{address}/transfers retorna transferências de tokens envolvendo o endereço dentro de uma janela de blocos obrigatória, ordenadas por (block_number, log_index) em ordem decrescente.
  • Metadados de tokens: GET /{chain}/tokens/{token} consulta nome, símbolo, casas decimais e oferta total de um token pelo endereço do contrato; POST /{chain}/tokens:batch consulta os mesmos metadados para até 100 endereços em uma requisição.

Os três usam https://api.blockvectra.com/v1/data como URL base e o cabeçalho de requisição x-api-key, com robinhood_mainnet como rede de exemplo. Pertencem aos recursos balances, transfers e token_metadata, respectivamente; para saber quais redes oferecem cada recurso, consulte Redes compatíveis. Em uma rede sem o recurso, o endpoint retorna 422 no_coverage.

Requisição 1: saldos do endereço

Este endpoint recebe menos parâmetros, por isso é uma boa primeira requisição para uma página:

  • {chain} (parâmetro de caminho, obrigatório): identificador da rede, o valor chain de uma entrada de GET /chains (por exemplo, robinhood_mainnet). A correspondência é exata e diferencia maiúsculas e minúsculas; aliases e Chain IDs numéricos não são aceitos.
  • {address} (parâmetro de caminho, obrigatório): endereço de 20 bytes; o prefixo 0x é opcional e maiúsculas e minúsculas são aceitas.
  • limit (parâmetro de consulta, opcional): tamanho da página. O padrão é 50; valores acima de 500 são limitados a 500; 0 ou um valor não inteiro retorna 400 bad_request.
  • cursor (parâmetro de consulta, opcional): o next_cursor da resposta anterior, enviado sem alterações para obter a próxima página. Um cursor é válido apenas para a rede, o endpoint e os parâmetros de consulta que o emitiram; reutilizá-lo em outro contexto retorna 400 bad_request.

A paginação é por chave: next_cursor aparece apenas quando há outra página. Na última página, a chave fica totalmente ausente, nunca null.

export BLOCKVECTRA_API_KEY=rgw_your_api_key

curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/balances?limit=50" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

O envelope de resposta é AddressBalanceListEnvelope, com data e meta. Cada item de data é um AddressBalance:

CampoTipoDescrição
tokenstring (endereço)Endereço do contrato do token; a forma canônica é 0x seguido de 40 dígitos hexadecimais em letras minúsculas.
balancestring (decimal)Saldo inteiro bruto, que pode ultrapassar 2^53, retornado como string decimal simples — nunca como número JSON, notação científica ou hexadecimal.
symbolstring ou nullSímbolo do token ou null quando indisponível.
decimalsinteger ou nullCasas decimais do token, 0–255, ou null quando indisponíveis.

Requisição 2: transferências do endereço

O endpoint de transferências exige uma janela explícita de blocos: from_block e to_block são obrigatórios e devem satisfazer from_block <= to_block. Ele recebe mais alguns parâmetros:

  • standard (parâmetro de consulta, obrigatório): erc20 ou erc721. Consultas por endereço não cobrem erc1155; enviá-lo retorna 422 no_coverage.
  • direction (parâmetro de consulta, opcional): in, out ou any; o padrão é any e filtra pela direção em relação ao endereço.
  • token (parâmetro de consulta, opcional): restringe resultados a um contrato de token.
  • clamp (parâmetro de consulta, opcional): apenas a string literal true o habilita; qualquer outro valor é tratado como false.

Limites da janela e finalidade: um to_block explícito acima de as_of_block retorna 409 not_indexed_yet, a menos que clamp=true o reduza a as_of_block; uma janela maior que o limite da rede (limits.max_window_blocks de GET /chains) retorna 409 window_too_large, a menos que clamp=true a reduza pelo lado mais antigo (aumentando from_block e mantendo to_block fixo). Se o próprio from_block já estiver acima de as_of_block, continua sendo um 409 obrigatório, mesmo com clamp=true. Quando a janela é reduzida ou parcialmente coberta, meta.coverage da resposta é "partial"; caso contrário, é "full".

Nos registros de transferências, itens ERC-20 acrescentam amount; itens ERC-721 acrescentam token_id. Ambos incluem token, standard, from, to, block_number, block_timestamp, tx_hash, tx_index e log_index.

export BLOCKVECTRA_API_KEY=rgw_your_api_key

# 1) Read as_of_block from the balances response.
AS_OF_BLOCK=$(curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/balances" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" | grep -o '"as_of_block":[0-9]*' | cut -d: -f2)

# 2) clamp=true truncates a too-wide window, or a to_block above as_of_block, instead of returning 409.
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/transfers?standard=erc20&from_block=0&to_block=$AS_OF_BLOCK&direction=any&clamp=true" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

Paginar todas as transferências

O next_cursor do endpoint de transferências de endereços é otimista: aparece apenas quando a página retornou exatamente limit linhas, portanto uma página pode ter next_cursor e ainda ser a última. Não pare quando uma página estiver vazia; siga next_cursor até que a chave esteja ausente.

O código abaixo obtém todas as transferências da janela:

const address = "0x1111111111111111111111111111111111111111";
const head = await fetch(
  `https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/balances`,
  { headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! } },
).then((r) => r.json());
const asOfBlock = head.meta.as_of_block;
const transfers: unknown[] = [];
let cursor: string | undefined;

do {
  const url = new URL(
    `https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/transfers`,
  );
  url.searchParams.set("standard", "erc20");
  url.searchParams.set("from_block", "0");
  url.searchParams.set("to_block", String(asOfBlock));
  url.searchParams.set("limit", "500");
  // clamp truncates from the older end
  url.searchParams.set("clamp", "true");
  if (cursor) url.searchParams.set("cursor", cursor);

  const res = await fetch(url, {
    headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! },
  });
  const page = await res.json();
  transfers.push(...page.data);
  cursor = page.next_cursor; // absent on the last page
} while (cursor);

Requisição 3: metadados de tokens e tokens:batch

Consulte um token com GET /{chain}/tokens/{token}; o caminho recebe apenas {chain} e {token}, sem paginação. O envelope da resposta é TokenEnvelope, e data é um Token:

CampoTipoDescrição
addressstring (endereço)Endereço do contrato do token.
standardstringerc20, erc721 ou unknown.
namestring ou nullNome do token ou null quando indisponível.
symbolstring ou nullSímbolo do token ou null quando indisponível.
decimalsinteger ou nullCasas decimais do token, 0–255, ou null quando indisponíveis.
total_supplystring ou nullOferta total bruta; a API não aplica escala por decimals. null quando indisponível.
first_seen_blockinteger (int64)Altura do bloco em que o token foi visto pela primeira vez.
metadata_updated_atstring (timestamp)Horário UTC da última atualização dos metadados.
metadata_blockinteger (int64)Altura do bloco em que os metadados foram lidos.
metadata_statusstringok, partial ou unavailable.
metadata_issuesobjectRegistros de problemas por campo, com chaves name, symbol, decimals, total_supply e valores reverted, no_data, invalid_encoding ou temporarily_unavailable.

Um {token} que não seja um endereço válido de 20 bytes retorna 400 bad_request; um {token} desconhecido retorna 404 not_found; um {chain} desconhecido retorna 404 unknown_chain.

O endpoint de saldos já inclui symbol e decimals quando disponíveis, mas ambos podem ser null. Para completar o nome e as casas decimais de cada token em uma carteira, use POST /{chain}/tokens:batch:

  • O corpo da requisição é {"addresses": [...]} com no máximo 100 endereços por requisição; mais de 100 entradas ou uma entrada que não seja um endereço válido de 20 bytes retorna 400 bad_request (falha no primeiro endereço inválido encontrado).
  • Endereços não encontrados não geram erro; são listados em data.missing, enquanto data.tokens contém apenas os tokens cujos metadados foram encontrados.
  • Endereços duplicados são deduplicados em tokens e missing, ambos na ordem da primeira ocorrência na requisição.
export BLOCKVECTRA_API_KEY=rgw_your_api_key

# Single token
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

# Batch: up to 100 addresses per request
curl -s -X POST "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens:batch" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"addresses":["0x1111111111111111111111111111111111111111","0x2222222222222222222222222222222222222222"]}'

Ajustar quantidades pelas casas decimais

O campo de saldo balance e o campo de transferência ERC-20 amount são inteiros brutos representados como strings decimais (UInt256String); o total_supply de um token também é um inteiro bruto on-chain sem escala por decimals. Para exibir uma quantidade legível, divida pelas casas decimais decimals desse token.

  • decimals vem dos campos symbol/decimals do próprio item de saldo ou de GET /{chain}/tokens/{token} e POST /{chain}/tokens:batch; pode ser null.
  • Esses valores podem ultrapassar 2^53, portanto não faça os cálculos com um número JSON: use BigInt em TypeScript e Decimal em Python, interpretando a string decimal sem alterações para evitar perda de precisão.
function toDisplayAmount(raw: string, decimals: number | null): string {
  if (decimals === null) return raw; // no decimals metadata: keep the raw integer
  const value = BigInt(raw);
  const base = 10n ** BigInt(decimals);
  const whole = value / base;
  const fraction = (value % base)
    .toString()
    .padStart(decimals, "0")
    .replace(/0+$/, "");
  return fraction ? `${whole}.${fraction}` : whole.toString();
}

// balance.balance is a raw decimal string; decimals comes from the same item or tokens:batch.
const display = toDisplayAmount(balance.balance, balance.decimals);

Atualização dos dados

Toda resposta bem-sucedida específica de uma rede contém meta:

  • as_of_block: o bloco mais recente da rede completamente gravado. Endpoints por bloco fornecem dados até essa altura.
  • safe_block: marcador da tag de bloco de consenso safe do nó (null enquanto desconhecido). Nunca abaixo de finalized_block e não reduz, rejeita ou atrasa respostas.
  • finalized_block: marcador da tag de bloco de consenso finalized do nó (null enquanto desconhecido). Não reduz, rejeita ou atrasa respostas; os clientes decidem a segurança necessária com base no marcador (como status de confirmação).
  • coverage: "full" ou "partial". Transferências de endereços e endpoints semelhantes informam "partial" quando clamp reduziu a janela atendida ou quando a janela começa antes do primeiro bloco indexado da rede.
  • refreshed_at: quando os dados da resposta foram atualizados pela última vez (UTC). Pode ser null: null significa que o horário de atualização é desconhecido e os dados devem ser tratados como desatualizados; endpoints baseados em blocos sempre retornam um valor.
  • Também repete chain, chain_slug e chain_external_id.

Um padrão comum: leia meta.as_of_block de qualquer primeira resposta para consultar até o bloco mais recente indexado e verifique meta.safe_block / meta.finalized_block se quiser exibir o status de confirmação.

Estimativa de CU para uma carga da página

Cada método é cobrado pelo seu peso de CU, consultado na API de planos da plataforma:

Peso de CU por chamada

MétodoCU por chamada
data.address_balances25
data.address_transfers25
data.tokens_batch10

Uma carga da página (estimativa)

1 requisição de saldos + 3 páginas de transferências + 1 requisição(ões) tokens:batch, 5 chamadas no total, cerca de 110 CU. O uso real depende da quantidade de páginas e tokens.

Para critérios de cobrança e respostas de erro sem cobrança, consulte as regras de cobrança. Se você precisa de logs dos blocos mais recentes em vez de histórico de transferências indexado, leia primeiro Dados recentes do nó e histórico indexado antes de decidir se deve usar eth_getLogs.

Próximos passos

Última atualização:

Nesta página