Solana单交易内两次转账签名验证失败问题求助
问题:Solana单交易内两次Token转账签名验证失败
尝试在Solana的一笔交易中连续执行两次Token转账(A→B,再B→C),但触发交易签名验证失败提示。单独执行任意一笔转账均可成功,需排查失败原因、正确签名方式及是否存在平台限制。
失败场景代码
Account aWallet = new Account("4jNVZFAqR8Uo38pkF2D7VkrVkdkbQzYTyKwH8WVD3zFtRqVgqFk8RGv4jhbovbQJhwffsJArPm1f7zrEBBpz9wG6", "6Z8KwAWDiof9sRM4H9svhaR7kfJMNBxY143vXenr513p"); PublicKey aTokenAccount = new PublicKey("5Zf3vVtYBJWfQuKijSWLJUeg5ZjnTjf7wXJirGAMWHHL"); Account bWallet = new Account("5zRSNfYURSN8gBwqAJKhqQ3HcVDdfdQfD1o8bHGiFZdhzqtE85GHyqtHeCvjWwFNq3cz8fTEzWnyqfUqKfpJ4nDx", "6bUxHifHMYFTQva495nAFS4ShAtCKBAEV5Rya12nb4EE"); PublicKey bTokenAccount = new PublicKey("6TzpmTkmR76tKcYfT562QVonykyuvpAcWXGFsRJ8Mftt"); PublicKey cTokenAccount = new PublicKey("6mJTEchkfsKpVGAAnJRfrv6fhkh9n8x4zc1LziFMycgP"); var minBalanceForExemptionAcc = _rpcClient.GetMinimumBalanceForRentExemption(TokenProgram.TokenAccountDataSize).Result; var blockHash = _rpcClient.GetLatestBlockHash(); var txBytes = new TransactionBuilder(). SetRecentBlockHash(blockHash.Result.Value.Blockhash). SetFeePayer(_adminWallet.Account). AddInstruction(TokenProgram.Transfer( aTokenAccount, bTokenAccount, 1000, aWallet)). AddInstruction(TokenProgram.Transfer( bTokenAccount, cTokenAccount, 5000, bWallet)). Build(new List<Account> { _adminWallet.Account, aWallet, bWallet }); RequestResult<string> sig = _rpcClient.SendTransaction(txBytes, commitment: Commitment.Finalized); Console.WriteLine(sig.Reason);
成功场景代码
仅执行A→B转账
AddInstruction(TokenProgram.Transfer( aTokenAccount, bTokenAccount, 1000, aWallet)). Build(new List<Account> { _adminWallet.Account, aWallet });
仅执行B→C转账
AddInstruction(TokenProgram.Transfer( bTokenAccount, cTokenAccount, 5000, bWallet)). Build(new List<Account> { _adminWallet.Account, bWallet });
原因分析及解决方案
Solana完全支持单交易内多笔Token转账,不存在平台限制,失败核心原因集中在账户声明、签名顺序或交易预检查环节:
可能原因
- 账户列表未正确合并:TransactionBuilder自动收集账户时,可能遗漏重复账户的可写属性标记(如bTokenAccount在两次转账中都需要写入权限)。
- 签名顺序不匹配:交易签名者顺序必须与账户列表中的签名者顺序一致,若顺序错误会导致签名验证失败。
- 预检查余额误解:若B的Token账户初始余额不足5000,即使A→B会转入资金,Solana预检查会基于交易执行前的初始余额验证,导致指令不满足条件(但你单独执行B→C成功,此情况可排除)。
正确实现方式
1. 手动显式声明所有账户
避免依赖自动收集,手动添加所有涉及账户并标记属性,确保权限正确:
var txBytes = new TransactionBuilder() .SetRecentBlockHash(blockHash.Result.Value.Blockhash) .SetFeePayer(_adminWallet.Account) // 显式添加所有涉及账户,标记签名者/可写属性 .AddAccount(_adminWallet.Account, isSigner: true, isWritable: true) .AddAccount(aWallet, isSigner: true, isWritable: false) .AddAccount(bWallet, isSigner: true, isWritable: false) .AddAccount(aTokenAccount, isSigner: false, isWritable: true) .AddAccount(bTokenAccount, isSigner: false, isWritable: true) .AddAccount(cTokenAccount, isSigner: false, isWritable: true) .AddAccount(TokenProgram.ProgramId, isSigner: false, isWritable: false) // 添加转账指令 .AddInstruction(TokenProgram.Transfer( aTokenAccount, bTokenAccount, 1000, aWallet)) .AddInstruction(TokenProgram.Transfer( bTokenAccount, cTokenAccount, 5000, bWallet)) .Build(new List<Account> { _adminWallet.Account, aWallet, bWallet });
2. 手动签名排查问题
若自动签名仍失败,可手动生成交易消息并签名,排查自动签名流程的问题:
// 构建未签名的交易消息 var message = new TransactionBuilder() .SetRecentBlockHash(blockHash.Result.Value.Blockhash) .SetFeePayer(_adminWallet.Account) .AddInstruction(TokenProgram.Transfer( aTokenAccount, bTokenAccount, 1000, aWallet)) .AddInstruction(TokenProgram.Transfer( bTokenAccount, cTokenAccount, 5000, bWallet)) .BuildMessage(); // 手动按顺序签名 var sigAdmin = _adminWallet.Account.Sign(message); var sigA = aWallet.Sign(message); var sigB = bWallet.Sign(message); // 组装交易并序列化 var transaction = new Transaction(message, new List<Signature> { sigAdmin, sigA, sigB }); var txBytes = transaction.Serialize(); // 发送交易 RequestResult<string> sig = _rpcClient.SendTransaction(txBytes, commitment: Commitment.Finalized);
3. 验证核心条件
- 确认bWallet是bTokenAccount的所有者(可通过
_rpcClient.GetTokenAccountInfo(bTokenAccount)查询)。 - 确认bTokenAccount初始余额≥5000(通过
_rpcClient.GetTokenAccountBalance(bTokenAccount)查询)。
内容的提问来源于stack exchange,提问作者Javin Yang
相关产品推荐
相关产品推荐

