← Retour au fil
getTransfersByAddress : l'historique des transferts Solana parsé en un seul appel
Helius4 mai, 15h · il y a 2 mois

getTransfersByAddress : l'historique des transferts Solana parsé en un seul appel

Helius lance une méthode RPC qui structure automatiquement tous les transferts SOL et tokens d'un portefeuille, éliminant le parsing manuel fastidieux pour les développeurs.

Helius introduit getTransfersByAddress, une méthode RPC exclusive à Solana qui renvoie des enregistrements de transferts lisibles pour n'importe quelle adresse. Elle inclut des filtres natifs par mint, montant, période, direction et contrepartie, supprimant les 5 étapes de parsing manuel que les développeurs devaient jusqu'ici enchaîner.

L'enjeu technique est réel : distinguer le SOL natif du WSOL, gérer les frais de transfert Token-2022, ou identifier les mints et burns comme des types distincts sont autant de cas particuliers qui corrompent les données mal parsées. La méthode gère tous ces edge cases et propose un mode SOL fusionné qui traité le WSOL comme du SOL natif.

Solana

Détails

Source
Helius
Publication
4 mai à 15h50

Contenu source (brut)

<p><a href="https://www.helius.dev/docs/rpc/gettransfersbyaddress">getTransfersByAddress</a> is a new Helius-exclusive Solana RPC method that returns parsed, human-readable token and SOL transfer records for a wallet address — with native filters for mint, time, amount, slot, direction, and counterparty.</p><p>It&#39;s the perfect counterpart to <a href="https://www.helius.dev/blog/introducing-gettransactionsforaddress">getTransactionsForAddress</a> (gTFA). Where gTFA returns full transaction payloads, <code>getTransfersByAddress</code> returns concise transfer objects: who sent what, to whom, when, and how much.</p><h2>Why do we need a transfer-specific RPC method?</h2><p>Most wallet, payments, and portfolio products don&#39;t need the entire transaction payload. They need transfers.</p><p>So, what do they do? Each team writes a different version of the same transfer parser, and unfortunately most get the edge cases wrong.</p><p>Until now, building a clean Solana transfer history required devs to:</p><ol class="list-number"><li value=1>Pull signatures with <code>getSignaturesForAddress</code></li><li value=2>Fetch each signature with <code>getTransaction</code></li><li value=3>Parse pre/post balances, token balances, and inner instructions</li><li value=4>Reconstruct transfers, handle SPL Token vs Token-2022 fee semantics, and untangle WSOL wrap/unwrap noise</li><li value=5>Repeat across multiple pages, handle retries, and store results</li></ol><p>Even with the <a href="https://www.helius.dev/docs/rpc/gettransactionsforaddress">getTransactionsForAddress method</a> collapsing steps 1 and 2 into one call, steps 3–5 still fall on the developer. </p><p>Now, <code>getTransfersByAddress</code> does this work for you and returns the result as a structured list.</p><h2>getTransfersByAddress Response</h2><p>Each transfer object includes the signature, slot, block time, transfer type, sender, recipient, mint, amount (raw and UI), decimals, confirmation status, and precise instruction indices so you can map each transfer back to the source transaction.</p><pre><code>{   "signature": "&lt;TX_SIGNATURE&gt;",   "slot": 315073428,   "blockTime": 1736159420,   "type": "transfer",   "fromUserAccount": "&lt;SENDER_WALLET&gt;",   "toUserAccount": "&lt;RECIPIENT_WALLET&gt;",   "fromTokenAccount": "&lt;SENDER_TOKEN_ACCOUNT&gt;",   "toTokenAccount": "&lt;RECIPIENT_TOKEN_ACCOUNT&gt;",   "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",   "amount": "2500000",   "decimals": 6,   "uiAmount": "2.5",   "confirmationStatus": "finalized",   "transactionIdx": 35,   "instructionIdx": 1,   "innerInstructionIdx": 0 }</code></pre><p>The type field tells you exactly what happened — <code>transfer</code>, <code>transferFee</code>, <code>mint</code>, <code>burn</code>, <code>wrap</code>, <code>unwrap</code>, <code>changeAccountOwner</code>, or <code>withdrawWithheldFee</code> — so you don&#39;t have to infer behavior from raw program data.</p><h2>Why is parsing Solana transfers difficult?</h2><p>A transfer in a Solana transaction isn&#39;t a single concept. </p><p>It&#39;s a category that hides a half-dozen edge cases, and getting any of them wrong corrupts your data.</p><h3>SOL vs. WSOL</h3><p>Native SOL and Wrapped SOL look like the same asset to a user, but they live in different parts of a transaction. </p><p>Native SOL moves through pre/post lamport balances on system accounts. WSOL moves through SPL token balances on <a href="https://www.helius.dev/blog/solana-token-accounts-history">token accounts</a>.</p><p>A user swapping on Jupiter may wrap SOL into WSOL, swap WSOL for USDC, then never unwrap — leaving a WSOL token account behind. </p><p>From the user&#39;s perspective, they spent SOL. From the network’s perspective, there were three transfers and a wrap.</p><p>Worse, the wrap itself isn&#39;t a transfer to a different owner — it&#39;s the same wallet moving lamports into its own token account. Counting it as a transfer double-counts the user&#39;s activity.</p><h3>Token-2022 Transfer Fees</h3><p><a href="https://www.helius.dev/blog/what-is-token-2022">Token-2022</a> introduced <code>TransferCheckedWithFee</code>, where the sender&#39;s debit doesn&#39;t match the recipient&#39;s credit. </p><p>The difference is withheld in the recipient&#39;s token account as a fee, payable later to a fee authority via <code>withdrawWithheldFee</code>.</p><p>A naive parser sees one transfer and gets the amount wrong. A careful parser detects the fee extension, split the instruction into a transfer plus a withheld-fee accrual, and track the fee account separately.</p><h3>Mints and Burns</h3><p>Tokens minted into an account have no sender. Burned tokens have no recipient. Both look like &quot;transfers&quot; in pre/post balance deltas, but conflating them with wallet-to-wallet transfers distorts counterparty analytics — you&#39;d see wallets &quot;receiving&quot; funds from the zero address and &quot;sending&quot; funds into the void.</p><p><code>getTransfersByAddress</code> represents these as <code>mint</code> and <code>burn</code> types with <code>fromUserAccount</code> or <code>toUserAccount</code> set to <code>null</code>, so you can include or exclude them depending on what you&#39;re building.</p><h2>Benefits of getTransfersByAddress</h2><p>The <code>getTransfersByAddress</code> method accepts filters that previously required pulling and parsing entire transaction histories client-side. </p><h3>Search by Mint</h3><p>Return only transfers for a specific token.</p><pre><code>{   "jsonrpc": "2.0",   "id": "1",   "method": "getTransfersByAddress",   "params": [     "&lt;WALLET_ADDRESS&gt;",     { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }   ] }</code></pre><h3>Search by Amount</h3><p>Filter by raw amount with <code>gt</code>, <code>gte</code>, <code>lt</code>, <code>lte</code> comparisons. Useful for surfacing whales, ignoring dust (i.e., accounts with insignificant token amounts), or flagging unusual activity.</p><pre><code>{   "params": [     "&lt;WALLET_ADDRESS&gt;",     {       "mint": "So11111111111111111111111111111111111111112",       "filters": {         "amount": { "gte": 1000000000, "lt": 10000000000 }       }     }   ] }</code></pre><h3>Search by Time</h3><p>Block time is supported as a Unix-timestamp range. Slot ranges work the same way for slot-precise queries.</p><pre><code>{   "params": [     "&lt;WALLET_ADDRESS&gt;",     {       "filters": {         "blockTime": { "gte": 1735718400, "lt": 1738396800 }       }     }   ] }</code></pre><h3>Search by Counterparty</h3><p>Combine <code>with</code> and <code>direction</code> parameters to query transfers between two specific wallets, in either direction.</p><pre><code>{   "params": [     "&lt;WALLET_ADDRESS&gt;",     {       "with": "&lt;COUNTERPARTY_WALLET&gt;",       "direction": "in"     }   ] }</code></pre><h3>SOL Mode</h3><p>Because native SOL and WSOL appear differently on Solana, but usually mean the same thing to a user, the <code>getTransfersByAddress</code> method exposes a <code>solMode</code> parameter.</p><h4><code>merged</code> (default)</h4><p>WSOL is treated as native SOL. </p><p>Wrap and unwrap rows are excluded, and querying by the native SOL mint returns both native SOL and WSOL transfers.</p><h4><code>separate</code></h4><p>In this mode, WSOL is preserved as a distinct mint, and wrap and unwrap lifecycle rows are included for full auditability.</p><p>Most product use cases will often want <code>merged</code>. Reconciliation, accounting, and protocol-level analytics often want <code>separate</code>.</p><h3>Pagination and Ordering</h3><p>Standard cursor-based pagination via <code>paginationToken</code>, up to 100 records per page. <code>sortOrder</code> accepts <code>asc</code> and <code>desc</code>.</p><pre><code>{   "jsonrpc": "2.0",   "id": "1",   "method": "getTransfersByAddress",   "params": [     "&lt;WALLET_ADDRESS&gt;",     { "limit": 50, "paginationToken": "315069220:308:2:1" }   ]