Skip to content

feat: getTransfersByAddress method#41

Open
ChiefWoods wants to merge 3 commits into
solana-rpc:mainfrom
ChiefWoods:feat/get-transfers-by-address
Open

feat: getTransfersByAddress method#41
ChiefWoods wants to merge 3 commits into
solana-rpc:mainfrom
ChiefWoods:feat/get-transfers-by-address

Conversation

@ChiefWoods

@ChiefWoods ChiefWoods commented Jul 6, 2026

Copy link
Copy Markdown

Adds support for the getTransfersByAddress method, largely inspired by the Helius specification.

On backwards compatibility

This implementation does not provide a 100% parity match with the Helius getTransferByAddress method. The responses returned from Helius are found to be inconsistent and does not strictly conform to their own specification. For this reason, this Superbank implementation is based on a modified specification detailed below.

Divergence from Helius' specification

  • The transfer materialized view preserves instruction-level atomicity.
  • All events are parsed on ingestion and do not undergo further processing at query time. Query parameters only filter the returned results.
  • The solMode setting only affects response projection for Transfer and TransferChecked events. It changes the mint and the presence of fromTokenAccount and toTokenAccount in the returned event: merged returns native SOL, while separate returns the WSOL mint.
  • wrap and unwrap event types are not emitted. WSOL movement is represented through the covered transfer and closeAccount rows.
  • fromTokenAccount and toTokenAccount are omitted for native SOL transfer rows because token-account endpoints are not meaningful for those rows.
  • paginationToken is returned only when another matching page exists after applying all request filters and the current cursor. When absent or null, the page is exhausted. Superbank uses its own documented cursor format rather than Helius' opaque 5- or 6-field token variants: slot:transactionIdx:instructionIdx:innerInstructionIdx:type.
    • slot is the returned row's slot.
    • transactionIdx is the returned row's transaction index within the slot.
    • instructionIdx is Superbank's transfer event index used for ordering the materialized transfer rows.
    • innerInstructionIdx is the inner instruction index recorded for the transfer event.
    • type is Superbank's public response transfer type, such as transfer, mint, burn, closeAccount, changeOwner, or withdrawWithheldFee.
      The token points to the last row returned by the current page and must be interpreted with the same filter and sort parameters used to produce it.
  • Events are stored so that chronological accounting can derive net balance changes for addresses from the amount and whether the account appears in fromUserAccount, toUserAccount, fromTokenAccount, or toTokenAccount.
  • In each event, fromUserAccount and toUserAccount represent either an authority/sender or recipient non-token account, and fromTokenAccount and toTokenAccount represent the token accounts for which the sender and recipient are authorities.
  • Token::InitializeAccount, Token::InitializeAccount2, and Token::InitializeAccount3 do not have associated transfer events. Token account lifecycle lamport changes are represented by SystemProgram::CreateAccount and Token::CloseAccount.
  • P-Token lamport recovery instructions (WithdraExcessLamports, UnwrapLamports) are represented as native SOL rows with the native SOL mint and 9 decimals.
  • Lamport increments to an account without going through a parsed CPI instruction such as SystemProgram::Transfer are not registered as events. For example, direct lamport subtraction from a PDA and addition to another address will not appear.

Covered Instructions

Program instruction Transfer type Description fromUserAccount toUserAccount fromTokenAccount toTokenAccount Notes
SystemProgram::Transfer transfer Native SOL transfer between lamport accounts. Amount is the instruction lamports.
SystemProgram::TransferWithSeed transfer Native SOL transfer from a derived source account. Source owner inference may require transaction context.
SystemProgram::WithdrawNonceAccount transfer Native SOL withdrawn from a nonce account. Treat as SOL movement when amount is positive.
SystemProgram::CreateAccount transfer Native SOL funding sent to a newly created account. toUserAccount is the new account receiving lamports, not its eventual owner.
SystemProgram::CreateAccountWithSeed transfer Native SOL funding sent to a seeded account. toUserAccount is the new account receiving lamports, not its eventual owner.
SystemProgram::CreateAccountAllowPrefund transfer Native SOL funding for account creation where prefunding is allowed. Include only when represented in decoded instruction data.
Token::Transfer transfer SPL token transfer between token accounts. Owners come from token balance metadata where available.
Token::TransferChecked transfer SPL token transfer with mint and decimals checked by instruction data. Decimals can be read from instruction data.
Token-2022::Transfer transfer Token-2022 transfer between token accounts. Same account semantics as SPL token transfer.
Token-2022::TransferChecked transfer Token-2022 checked transfer. Decimals can be read from instruction data.
Token-2022::TransferCheckedWithFee transfer Token-2022 checked transfer with withheld transfer fee. feeAmount records the withheld fee; amount records destination credit.
Token::MintTo mint New tokens minted to a destination token account. One-sided inbound row.
Token::MintToChecked mint Checked mint to a destination token account. Decimals can be read from instruction data.
Token::Burn burn Tokens burned from a source token account. One-sided outbound row.
Token::BurnChecked burn Checked burn from a source token account. Decimals can be read from instruction data.
Token::CloseAccount on WSOL with positive token balance closeAccount Closes a WSOL token account and returns remaining SOL value. Amount is inferred through token balances; fromUserAccount is the close authority and toUserAccount is the rent receiver.
Token::CloseAccount rent recovery closeAccount Recovers rent from a non-WSOL token account, or a WSOL account with zero token balance. Amount is inferred through token balances; fromUserAccount is the close authority and toUserAccount is the rent receiver.
Token::WithdrawExcessLamports transfer Withdraws excess lamports from a mint, token account, or multisig source. fromUserAccount is the authority, toUserAccount is the destination, and fromTokenAccount is the source account. Amount is inferred from the source lamport balance delta.
Token::UnwrapLamports(Some(amount)) transfer Transfers an explicit lamport amount from a native token account to a destination. fromUserAccount is the authority, toUserAccount is the destination, and fromTokenAccount is the source account. Amount is read from instruction data.
Token::UnwrapLamports(None) closeAccount Unwraps the full native token balance from a native token account. fromUserAccount is the authority, toUserAccount is the destination, and fromTokenAccount is the source account. Amount is the source account's full pre-token balance.
Token::SetAuthority(AccountOwner) changeOwner Changes token account owner authority. One row linking old and new owners.
Token-2022::WithdrawWithheldTokensFromMint withdrawWithheldFee Withdraws withheld Token-2022 fees from a mint. Amount is the collected withheld fee.
Token-2022::WithdrawWithheldTokensFromAccounts withdrawWithheldFee Withdraws withheld Token-2022 fees from one or more token accounts. fromUserAccount is the withdraw authority. Amount is the collected withheld fee derived from destination token balance deltas.

@ChiefWoods
ChiefWoods force-pushed the feat/get-transfers-by-address branch 3 times, most recently from 487b69d to ad012f7 Compare July 14, 2026 07:55
@ChiefWoods
ChiefWoods force-pushed the feat/get-transfers-by-address branch from ad012f7 to 258a9ae Compare July 14, 2026 07:56
@ChiefWoods
ChiefWoods marked this pull request as ready for review July 14, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant