NOVO: Helius adquire a Light Protocol
getTransfersByAddress
Blog/Atualizações

getTransfersByAddress: histórico analisado de transferências da Solana em 1 chamada

Produto na HeliusKiryl Miranovich no XKiryl Miranovich no LinkedIn
5 min de leitura

getTransfersByAddress é um novo método RPC exclusivo da Helius para a Solana que retorna registros analisados e legíveis de transferências de tokens e SOL para um endereço de carteira, com filtros nativos por mint, horário, valor, slot, direção e contraparte.

Ele é o complemento perfeito para o getTransactionsForAddress (gTFA). Enquanto o gTFA retorna payloads completos de transações, getTransfersByAddress retorna objetos de transferência concisos: quem enviou o quê, para quem, quando e quanto.

Por que precisamos de um método RPC específico para transferências?

A maioria dos produtos de carteiras, pagamentos e portfólios não precisa do payload completo da transação. Eles precisam das transferências.

Então, o que fazem? Cada equipe escreve uma versão diferente do mesmo parser de transferências e, infelizmente, a maioria trata os casos extremos de forma incorreta.

Até agora, criar um histórico organizado de transferências na Solana exigia que os desenvolvedores:

  1. Buscassem assinaturas com getSignaturesForAddress
  2. Buscassem cada assinatura com getTransaction
  3. Analisassem saldos anteriores e posteriores, saldos de tokens e instruções internas
  4. Reconstruíssem transferências, tratassem as diferenças semânticas de taxas entre SPL Token e Token-2022 e separassem o ruído de wrap/unwrap de WSOL
  5. Repetissem o processo em várias páginas, tratassem novas tentativas e armazenassem os resultados

Mesmo com o método getTransactionsForAddress condensando as etapas 1 e 2 em uma única chamada, as etapas 3 a 5 ainda ficam a cargo do desenvolvedor.

Agora, getTransfersByAddress faz esse trabalho para você e retorna o resultado como uma lista estruturada.

Resposta do getTransfersByAddress

Cada objeto de transferência inclui assinatura, slot, horário do bloco, tipo de transferência, remetente, destinatário, mint, valor (bruto e de UI), casas decimais, status de confirmação e índices precisos das instruções, para que você possa associar cada transferência à transação de origem.

Código
{
  "signature": "<TX_SIGNATURE>",
  "slot": 315073428,
  "blockTime": 1736159420,
  "type": "transfer",
  "fromUserAccount": "<SENDER_WALLET>",
  "toUserAccount": "<RECIPIENT_WALLET>",
  "fromTokenAccount": "<SENDER_TOKEN_ACCOUNT>",
  "toTokenAccount": "<RECIPIENT_TOKEN_ACCOUNT>",
  "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "amount": "2500000",
  "decimals": 6,
  "uiAmount": "2.5",
  "confirmationStatus": "finalized",
  "transactionIdx": 35,
  "instructionIdx": 1,
  "innerInstructionIdx": 0
}

O campo de tipo informa exatamente o que aconteceu — transfer, transferFee, mint, burn, wrap, unwrap, changeAccountOwner ou withdrawWithheldFee — para que você não precise deduzir o comportamento com base em dados brutos do programa.

Por que é difícil analisar transferências na Solana?

Uma transferência em uma transação da Solana não é um conceito único.

É uma categoria que oculta diversos casos extremos, e qualquer erro neles compromete seus dados.

SOL vs. WSOL

SOL nativo e Wrapped SOL parecem o mesmo ativo para o usuário, mas ficam em partes diferentes de uma transação.

SOL nativo é movimentado por meio dos saldos de lamports anteriores e posteriores em contas do sistema. WSOL é movimentado por meio dos saldos de tokens em contas de token.

Um usuário que faz um swap na Jupiter pode converter SOL em WSOL, trocar WSOL por USDC e nunca fazer o unwrap, deixando para trás uma conta de token WSOL.

Do ponto de vista do usuário, ele gastou SOL. Do ponto de vista da rede, houve três transferências e um wrap.

Para piorar, o wrap em si não é uma transferência para outro proprietário: é a mesma carteira movendo lamports para sua própria conta de token. Contabilizá-lo como transferência duplica a atividade do usuário.

Taxas de transferência do Token-2022

O Token-2022 introduziu TransferCheckedWithFee, em que o débito do remetente não corresponde ao crédito do destinatário.

A diferença fica retida como taxa na conta de token do destinatário e pode ser paga posteriormente a uma autoridade de taxas por meio de withdrawWithheldFee.

Um parser ingênuo vê uma transferência e calcula o valor incorretamente. Um parser cuidadoso detecta a extensão de taxa, divide a instrução em uma transferência e um acúmulo de taxa retida e acompanha a conta de taxas separadamente.

Emissões e queimas

Tokens emitidos em uma conta não têm remetente. Tokens queimados não têm destinatário. Ambos parecem "transferências" nas diferenças entre os saldos anteriores e posteriores, mas agrupá-los com transferências entre carteiras distorce a análise de contrapartes: você veria carteiras "recebendo" fundos do endereço zero e "enviando" fundos para o vazio.

getTransfersByAddress representa essas operações como os tipos mint e burn, com fromUserAccount ou toUserAccount definido como null, para que você possa incluí-las ou excluí-las de acordo com o que estiver criando.

Benefícios do getTransfersByAddress

O método getTransfersByAddress aceita filtros que antes exigiam buscar e analisar históricos completos de transações no cliente. 

Buscar por mint

Retorne apenas as transferências de um token específico.

Código
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "<WALLET_ADDRESS>",
    { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }
  ]
}

Buscar por valor

Filtre pelo valor bruto usando as comparações gt, gte, lt e lte. Isso é útil para identificar baleias, ignorar valores residuais (ou seja, contas com quantidades insignificantes de tokens) ou sinalizar atividades incomuns.

Código
{
  "params": [
    "<WALLET_ADDRESS>",
    {
      "mint": "So11111111111111111111111111111111111111112",
      "filters": {
        "amount": { "gte": 1000000000, "lt": 10000000000 }
      }
    }
  ]
}

Buscar por horário

O horário do bloco aceita um intervalo de timestamps Unix. Intervalos de slots funcionam da mesma forma para consultas com precisão de slot.

Código
{
  "params": [
    "<WALLET_ADDRESS>",
    {
      "filters": {
        "blockTime": { "gte": 1735718400, "lt": 1738396800 }
      }
    }
  ]
}

Buscar por contraparte

Combine os parâmetros with e direction para consultar transferências entre duas carteiras específicas, em qualquer direção.

Código
{
  "params": [
    "<WALLET_ADDRESS>",
    {
      "with": "<COUNTERPARTY_WALLET>",
      "direction": "in"
    }
  ]
}

Modo SOL

Como SOL nativo e WSOL aparecem de formas diferentes na Solana, mas geralmente significam a mesma coisa para o usuário, o método getTransfersByAddress disponibiliza um parâmetro solMode.

merged (padrão)

WSOL é tratado como SOL nativo.

As linhas de wrap e unwrap são excluídas, e a consulta pelo mint de SOL nativo retorna transferências de SOL nativo e WSOL.

separate

Nesse modo, WSOL é preservado como um mint distinto, e as linhas do ciclo de vida de wrap e unwrap são incluídas para permitir uma auditoria completa.

Na maioria dos casos de uso de produtos, merged costuma ser a melhor opção. Para reconciliação, contabilidade e análises no nível do protocolo, separate costuma ser mais adequado.

Paginação e ordenação

Paginação padrão baseada em cursor por meio de paginationToken, com até 100 registros por página. sortOrder aceita asc e desc.

Código
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "<WALLET_ADDRESS>",
    { "limit": 50, "paginationToken": "315069220:308:2:1" }
  ]
}

Quando usar getTransfersByAddress

getTransfersByAddress e getTransactionsForAddress são semelhantes, mas atendem a finalidades diferentes. 

NecessidadeMétodo
Transferências analisadas de tokens e SOL, com filtrosgetTransfersByAddress
Payloads completos de transações ou atividades que não sejam transferênciasgetTransactionsForAddress
Instruções decodificadas para qualquer assinatura ou endereçoParsed Events API
Apenas assinaturasgetTransactionsForAddress com transactionDetails: 'signatures'
Streaming de transferências em tempo realLaserStream

Comece agora

O método getTransfersByAddress já está disponível em todos os planos pagos, a partir do plano Developer. Ele custa 10 créditos por solicitação e faz parte do seu grupo de limites de taxa padrão de RPC.

Use-o com sua URL RPC existente da Helius:

Código
const response = await fetch("https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: "1",
    method: "getTransfersByAddress",
    params: ["<WALLET_ADDRESS>"]
  })
});

const data = await response.json();
console.log(data.result.data);

Leia a referência da API para ver todos os detalhes sobre parâmetros e respostas.

Assine a Helius

Acompanhe as novidades mais recentes do desenvolvimento Solana e receba atualizações quando publicarmos