
getTransfersByAddress:一次调用获取解析后的 Solana 转账历史
getTransfersByAddress 是 Helius 独有的新 Solana RPC 方法,可返回钱包地址经过解析、易于理解的代币和 SOL 转账记录,并原生支持按铸币地址、时间、金额、slot、方向和交易对手方筛选。
它是 getTransactionsForAddress(gTFA)的理想搭档。gTFA 返回完整的交易载荷,而 getTransfersByAddress 返回简洁的转账对象:谁在何时向谁发送了什么,以及金额是多少。
为什么需要专用于转账的 RPC 方法?
大多数钱包、支付和投资组合产品并不需要完整的交易载荷。它们需要的是转账记录。
那么,它们怎么做?每个团队都会编写一套不同版本的转账解析器,但遗憾的是,大多数解析器都无法正确处理边界情况。
在此之前,要构建清晰的 Solana 转账历史,开发者必须:
- 使用
getSignaturesForAddress拉取签名 - 使用
getTransaction获取每个签名 - 解析交易前后的余额、代币余额和内部指令
- 重建转账,处理 SPL Token 与 Token-2022 的不同费用语义,并理清 WSOL 封装和解封装产生的干扰数据
- 对多个分页重复上述操作、处理重试并存储结果
即使 getTransactionsForAddress 方法 已将第 1 步和第 2 步合并为一次调用,第 3–5 步仍需开发者自行完成。
现在,getTransfersByAddress 会替你完成这些工作,并以结构化列表的形式返回结果。
getTransfersByAddress 响应
每个转账对象都包含签名、slot、区块时间、转账类型、发送方、接收方、铸币地址、金额(原始值和 UI 值)、小数位数、确认状态和精确的指令索引,因此你可以将每笔转账映射回源交易。
{
"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
}类型字段会准确说明发生了什么,包括 transfer、transferFee、mint、burn、wrap、unwrap、changeAccountOwner 或 withdrawWithheldFee,因此你无需根据原始程序数据推断行为。
为什么解析 Solana 转账如此困难?
Solana 交易中的转账并不是单一概念。
它是一个涵盖了多个边界情况的类别,只要其中任何一种处理出错,就会破坏你的数据。
SOL 与 WSOL
对用户而言,原生 SOL 和封装 SOL 看起来是同一种资产,但它们存在于交易的不同部分。
原生 SOL 通过系统账户交易前后的 lamport 余额转移。WSOL 则通过代币账户中的 SPL 代币余额转移。
用户在 Jupiter 上兑换时,可能会先将 SOL 封装为 WSOL,再将 WSOL 兑换为 USDC,最后却不执行解封装,从而留下一个 WSOL 代币账户。
从用户的角度看,他们花费了 SOL。从网络的角度看,则发生了三笔转账和一次封装。
更糟的是,封装本身并不是向其他所有者转账,而是同一个钱包将 lamport 转入自己的代币账户。若将其计为转账,就会重复计算用户的活动。
Token-2022 转账费用
Token-2022 引入了 TransferCheckedWithFee,此时发送方扣除的金额与接收方到账的金额并不相同。
差额会作为费用暂扣在接收方的代币账户中,之后可通过 withdrawWithheldFee 支付给费用管理方。
简单的解析器只会看到一笔转账,并算错金额。严谨的解析器会检测费用扩展,将指令拆分为一笔转账和一笔暂扣费用的累积,并单独跟踪费用账户。
铸造与销毁
铸造到某个账户的代币没有发送方,被销毁的代币没有接收方。两者在交易前后余额差值中看起来都像“转账”,但若将它们与钱包间转账混为一谈,就会扭曲交易对手方分析——你会看到钱包从零地址“接收”资金,或将资金“发送”到虚空中。
getTransfersByAddress 将它们表示为 mint 和 burn 类型,并将 fromUserAccount 或 toUserAccount 设为 null,因此你可以根据所构建的产品决定是否包含它们。
getTransfersByAddress 的优势
getTransfersByAddress 方法支持多种筛选条件,而这些筛选过去需要在客户端拉取并解析完整的交易历史才能实现。
按铸币地址搜索
仅返回特定代币的转账。
{
"jsonrpc": "2.0",
"id": "1",
"method": "getTransfersByAddress",
"params": [
"<WALLET_ADDRESS>",
{ "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }
]
}按金额搜索
使用 gt、gte、lt 和 lte 比较条件,按原始金额筛选。适用于发现巨鲸、忽略小额资产(即代币数量微不足道的账户)或标记异常活动。
{
"params": [
"<WALLET_ADDRESS>",
{
"mint": "So11111111111111111111111111111111111111112",
"filters": {
"amount": { "gte": 1000000000, "lt": 10000000000 }
}
}
]
}按时间搜索
区块时间支持 Unix 时间戳范围。slot 范围的工作方式相同,可用于精确到 slot 的查询。
{
"params": [
"<WALLET_ADDRESS>",
{
"filters": {
"blockTime": { "gte": 1735718400, "lt": 1738396800 }
}
}
]
}按交易对手方搜索
组合使用 with 和 direction 参数,可查询两个指定钱包之间任意方向的转账。
{
"params": [
"<WALLET_ADDRESS>",
{
"with": "<COUNTERPARTY_WALLET>",
"direction": "in"
}
]
}SOL 模式
原生 SOL 和 WSOL 在 Solana 上的表现形式不同,但对用户而言通常代表同一种资产,因此 getTransfersByAddress 方法提供了 solMode 参数。
merged(默认)
WSOL 会被视为原生 SOL。
封装和解封装记录会被排除,而按原生 SOL 铸币地址查询时,会同时返回原生 SOL 和 WSOL 转账。
separate
在此模式下,WSOL 会保留为独立的铸币地址,并包含封装和解封装生命周期记录,以支持完整审计。
大多数产品用例通常适合使用 merged。对账、会计和协议级分析通常适合使用 separate。
分页与排序
通过 paginationToken 实现标准的游标分页,每页最多 100 条记录。sortOrder 接受 asc 和 desc。
{
"jsonrpc": "2.0",
"id": "1",
"method": "getTransfersByAddress",
"params": [
"<WALLET_ADDRESS>",
{ "limit": 50, "paginationToken": "315069220:308:2:1" }
]
}何时使用 getTransfersByAddress
getTransfersByAddress 和 getTransactionsForAddress 功能相近,但用途不同。
| 需求 | 方法 |
| 经过解析且支持筛选的代币和 SOL 转账 | getTransfersByAddress |
| 完整交易载荷或非转账活动 | getTransactionsForAddress |
| 解析任意签名或地址的指令 | Parsed Events API |
| 仅获取签名 | getTransactionsForAddress 搭配 transactionDetails: 'signatures' |
| 实时流式传输转账 | LaserStream |
开始使用
getTransfersByAddress 方法现已面向所有付费计划开放,最低为 Developer 计划。每次请求消耗 10 个积分,并归入你的标准 RPC 速率限制组。
通过现有的 Helius RPC URL 即可使用:
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);阅读 API 参考文档,了解完整的参数和响应详情。
相关文章
订阅 Helius
及时了解 Solana 开发的最新动态,并在我们发布新内容时收到更新


