Solana中如何通过交易哈希调用getTransaction获取to-address
Solana 交易收款地址(to-address)提取及全量交易校验方案
Solana 交易为指令驱动模型,不存在 EVM 链上统一的全局 from/to 字段,你调用 getTransaction 拿到的 accountKeys 数组包含交易涉及的所有地址(付款方、收款方、程序地址、中间账户等),并非只有付款方,需要结合指令类型、元数据余额变动做筛选提取,具体落地步骤如下:
前置要求:正确配置RPC请求参数
如果参数配置不全,会返回截断的交易数据,无法解析完整信息,JS端调用参考:
const { Connection, PublicKey } = require('@solana/web3.js'); // 初始化RPC连接 const connection = new Connection("你的Solana RPC节点地址", "confirmed"); const txHash = "待查询的交易哈希"; // 必须加版本化交易支持参数,否则当前主网大部分交易会返回null const txDetail = await connection.getTransaction(txHash, { commitment: "confirmed", maxSupportedTransactionVersion: 0, });
分场景提取to-address及交易信息
根据交易类型不同,提取逻辑有区别,覆盖99%以上业务场景的两类转账如下:
1. 原生SOL转账场景
原生SOL转账由系统程序(地址为11111111111111111111111111111111)的transfer指令执行:
- 遍历
txDetail.transaction.message.instructions,找到programId等于上述系统程序地址的转账指令 - 该指令关联的
accounts数组中,索引0为付款方from地址(必须为交易签名者),索引1即为收款方to地址 - 转账金额可交叉校验:
txDetail.meta.postBalances[toIndex] - txDetail.meta.preBalances[toIndex]为实际到账金额(单位lamport,1 SOL = 10^9 lamport);付款方余额差值减去txDetail.meta.fee(交易手续费,单位lamport)应当和到账金额一致
2. SPL/SPL2022代币转账场景
代币转账由代币程序(旧版地址TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA,2022版地址TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb)执行,注意这类交易中直接出现的很多地址是用户的代币关联账户(ATA),不是用户实际的钱包收款地址:
- 最稳妥的提取方式不需要硬解析指令:直接遍历
txDetail.meta.postTokenBalances和txDetail.meta.preTokenBalances数组 - 数组中每个条目自带
owner字段(对应该代币账户所属的实际钱包地址)、uiAmount字段(已按代币精度转换的可读金额)、mint字段(代币合约地址) - 对比同一代币mint下的前后余额,余额净增加的
owner就是该笔代币转账的to地址,净减少的owner就是from地址,余额差值就是实际转账金额 - 如果要做指令级校验:
transfer/transferChecked指令关联的accounts数组中,索引0为转出方ATA,索引1为转入方ATA,索引2为转出方钱包地址,转入方ATA对应的owner可通过上述tokenBalances字段直接取,不需要额外链上查询
通用兜底校验方案
如果业务需要兼容所有交易类型(包括PDA转账、多签交易、程序交互类交易),不需要硬编码指令解析逻辑,直接通过余额变动做校验即可:
- 首先筛选所有签名地址:
accountKeys中signer属性为true的地址集合即为实际付款方from列表 - 遍历所有地址的SOL余额变动、代币余额变动,排除支付手续费的签名地址、程序地址后,余额净增加值和业务预期转账金额匹配的非程序地址,即为实际to地址
- 注意过滤交易执行过程中临时PDA地址的余额变动,这类地址余额最终会清零,不会持有实际资产
避坑提示:不要直接取
accountKeys数组中非from的第一个地址作为to地址,大部分交易中该位置会是程序地址、手续费接收地址或者中间账户,必须结合余额变动结果交叉校验,避免地址匹配错误。
内容的提问来源于stack exchange,提问作者raghav saraf
相关产品推荐
相关产品推荐

