NUEVO: Helius adquiere Light Protocol
getTransfersByAddress
Blog/Actualizaciones

getTransfersByAddress: historial de transferencias de Solana analizado en 1 llamada

Producto en HeliusKiryl Miranovich en XKiryl Miranovich en LinkedIn
5 min de lectura

getTransfersByAddress es un nuevo método RPC de Solana exclusivo de Helius que devuelve registros analizados y legibles de transferencias de tokens y SOL para una dirección de wallet, con filtros nativos por mint, tiempo, cantidad, slot, dirección y contraparte.

Es el complemento perfecto para getTransactionsForAddress (gTFA). Mientras que gTFA devuelve cargas útiles completas de transacciones, getTransfersByAddress devuelve objetos de transferencia concisos: quién envió qué, a quién, cuándo y cuánto.

¿Por qué necesitamos un método RPC específico para transferencias?

La mayoría de los productos de wallets, pagos y portafolios no necesitan la carga útil completa de la transacción. Necesitan las transferencias.

Entonces, ¿qué hacen? Cada equipo escribe una versión diferente del mismo analizador de transferencias y, por desgracia, la mayoría gestiona mal los casos límite.

Hasta ahora, para crear un historial limpio de transferencias de Solana, los desarrolladores debían:

  1. Obtener firmas con getSignaturesForAddress
  2. Obtener cada firma con getTransaction
  3. Analizar los saldos previos y posteriores, los saldos de tokens y las instrucciones internas
  4. Reconstruir las transferencias, gestionar la semántica de comisiones de SPL Token frente a Token-2022 y desenredar el ruido generado al envolver y desenvolver WSOL
  5. Repetir el proceso en varias páginas, gestionar los reintentos y almacenar los resultados

Incluso con el método getTransactionsForAddress, que combina los pasos 1 y 2 en una sola llamada, los pasos 3 a 5 siguen recayendo en el desarrollador.

Ahora, getTransfersByAddress hace este trabajo por ti y devuelve el resultado como una lista estructurada.

Respuesta de getTransfersByAddress

Cada objeto de transferencia incluye la firma, el slot, el tiempo de bloque, el tipo de transferencia, el remitente, el destinatario, el mint, la cantidad (sin procesar y de interfaz), los decimales, el estado de confirmación y los índices precisos de las instrucciones, para que puedas vincular cada transferencia con la transacción de origen.

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
}

El campo de tipo indica exactamente qué ocurrió: transfer, transferFee, mint, burn, wrap, unwrap, changeAccountOwner o withdrawWithheldFee, para que no tengas que inferir el comportamiento a partir de datos sin procesar del programa.

¿Por qué es difícil analizar las transferencias de Solana?

Una transferencia dentro de una transacción de Solana no es un concepto único.

Es una categoría que oculta media docena de casos límite. Gestionar mal cualquiera de ellos corrompe tus datos.

SOL frente a WSOL

SOL nativo y Wrapped SOL parecen el mismo activo para el usuario, pero se encuentran en distintas partes de una transacción.

SOL nativo se transfiere mediante los saldos de lamports previos y posteriores de las cuentas del sistema. WSOL se transfiere mediante los saldos de tokens SPL de las cuentas de tokens.

Un usuario que hace un swap en Jupiter puede envolver SOL en WSOL, intercambiar WSOL por USDC y nunca desenvolverlo, lo que deja una cuenta de tokens WSOL.

Desde la perspectiva del usuario, gastó SOL. Desde la perspectiva de la red, hubo tres transferencias y una operación de envoltura.

Peor aún, la operación de envoltura no es una transferencia a otro propietario: es la misma wallet moviendo lamports a su propia cuenta de tokens. Contarla como una transferencia duplica la actividad del usuario.

Comisiones de transferencia de Token-2022

Token-2022 introdujo TransferCheckedWithFee, donde el débito del remitente no coincide con el crédito del destinatario.

La diferencia se retiene como comisión en la cuenta de tokens del destinatario y puede pagarse más adelante a una autoridad de comisiones mediante withdrawWithheldFee.

Un analizador ingenuo ve una sola transferencia y calcula mal la cantidad. Un analizador cuidadoso detecta la extensión de comisión, divide la instrucción en una transferencia y una acumulación de comisión retenida, y realiza un seguimiento separado de la cuenta de comisiones.

Acuñaciones y quemas

Los tokens acuñados en una cuenta no tienen remitente. Los tokens quemados no tienen destinatario. Ambos parecen "transferencias" en las diferencias entre los saldos previos y posteriores, pero confundirlos con transferencias entre wallets distorsiona el análisis de contrapartes: verías wallets que "reciben" fondos de la dirección cero y "envían" fondos al vacío.

getTransfersByAddress los representa como tipos mint e burn, con fromUserAccount o toUserAccount establecidos en null, para que puedas incluirlos o excluirlos según lo que estés creando.

Ventajas de getTransfersByAddress

El método getTransfersByAddress acepta filtros que antes exigían obtener y analizar en el cliente historiales completos de transacciones. 

Buscar por mint

Devuelve solo las transferencias de un token específico.

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

Buscar por cantidad

Filtra por cantidad sin procesar con las comparaciones gt, gte, lt e lte. Es útil para detectar ballenas, ignorar el polvo (es decir, cuentas con cantidades insignificantes de tokens) o marcar actividad inusual.

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

Buscar por tiempo

El tiempo de bloque admite un intervalo de marcas de tiempo Unix. Los intervalos de slots funcionan de la misma manera para consultas precisas por slot.

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

Buscar por contraparte

Combina los parámetros with e direction para consultar transferencias entre dos wallets específicas, en cualquier dirección.

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

Modo SOL

SOL nativo y WSOL aparecen de forma diferente en Solana, pero suelen representar lo mismo para el usuario. Por eso, el método getTransfersByAddress ofrece un parámetro solMode.

merged (predeterminado)

WSOL se trata como SOL nativo.

Se excluyen las filas de envoltura y desenvoltura, y consultar por el mint de SOL nativo devuelve transferencias tanto de SOL nativo como de WSOL.

separate

En este modo, WSOL se conserva como un mint distinto y se incluyen las filas del ciclo de envoltura y desenvoltura para ofrecer una auditabilidad completa.

La mayoría de los casos de uso de productos suelen requerir merged. La conciliación, la contabilidad y los análisis a nivel de protocolo suelen requerir separate.

Paginación y orden

Paginación estándar basada en cursores mediante paginationToken, con hasta 100 registros por página. sortOrder acepta asc e desc.

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

Cuándo usar getTransfersByAddress

getTransfersByAddress e getTransactionsForAddress son similares, pero tienen propósitos diferentes. 

NecesidadMétodo
Transferencias analizadas de tokens y SOL, con filtrosgetTransfersByAddress
Cargas útiles completas de transacciones o actividad que no sea de transferenciagetTransactionsForAddress
Instrucciones decodificadas para cualquier firma o direcciónAPI de eventos analizados
Solo firmasgetTransactionsForAddress con transactionDetails: 'signatures'
Streaming de transferencias en tiempo realLaserStream

Comienza ahora

El método getTransfersByAddress ya está disponible en todos los planes de pago a partir del plan Developer. Cuesta 10 créditos por solicitud y forma parte de tu grupo de límites de solicitudes RPC estándar.

Úsalo con tu URL RPC actual de 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);

Consulta la referencia de la API para ver todos los detalles de los parámetros y la respuesta.

Suscríbete a Helius

Mantente al día con las novedades del desarrollo en Solana y recibe actualizaciones cuando publiquemos