Solana PDA提现SOL报错:交易模拟失败 账户数据无效
Solana PDA 提现交易报
invalid account data for instruction根因与修复 核心报错原因
- 指令与转账资产类型不匹配:当前要转原生SOL,却调用了仅适用于SPL代币的
spl_token::instruction::transfer指令。SPL代币程序会将传入的原生SOL账户按SPL代币账户结构解析,数据格式完全不匹配,直接触发账户数据无效错误。 - 账户传输顺序、权限配置错误:
- TS端传入的第4个账户是
TOKEN_PROGRAM_ID,Rust端却将其读取为system_program,程序ID获取错误。 - PDA作为交易签名方,TS端配置为
isWritable: false,不满足签名账户可写的要求。 invoke_signed传入的账户列表顺序与指令要求的账户顺序完全错位,没有按指令定义的顺序排列源账户、目标账户、权限账户、程序账户。
- TS端传入的第4个账户是
- PDA签名参数错误:调用转账指令时传入的签名种子仅包含PDA公钥,没有传入派生PDA时使用的完整业务种子+对应bump值,无法通过PDA签名校验。
修复方案
场景1:转账标的为原生SOL
Rust端代码修正
use solana_program::{ account_info::next_account_info, program::invoke_signed, system_instruction, }; let accounts_iter = &mut accounts.iter(); // 账户读取顺序必须和TS端传入顺序严格一一对应 let coinflip_account = next_account_info(accounts_iter)?; // SOL持有方(转出方) let wallet_account = next_account_info(accounts_iter)?; // 用户钱包(转入方) let pda_account = next_account_info(accounts_iter)?; // PDA签名权限账户 let system_program = next_account_info(accounts_iter)?; // 系统程序 // 构造原生SOL转账指令,替换掉原spl_token的transfer调用 let withdraw_instruction = system_instruction::transfer( coinflip_account.key, wallet_account.key, lamports, ); // 替换为你业务中派生PDA时实际使用的种子前缀,以及链上查到的对应bump值 let pda_sign_seeds = &[b"your-business-pda-seed", &[pda_bump]]; invoke_signed( &withdraw_instruction, &[ coinflip_account.clone(), wallet_account.clone(), system_program.clone(), ], &[pda_sign_seeds], )?;
TypeScript端keys配置修正
keys: [ { pubkey: coinflipPubKey, isSigner: false, isWritable: true }, { pubkey: wallet.publicKey, isSigner: true, isWritable: true }, { pubkey: pda, isSigner: false, isWritable: true }, // PDA必须设为可写 { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, // 原生SOL用系统程序,不要传TOKEN_PROGRAM_ID ],
场景2:转账标的为SPL代币
需补充缺失的3个必填账户:SPL代币铸币账户、转出方关联代币账户(ATA)、转入方关联代币账户(ATA),严格按照SPL代币transfer指令要求的账户顺序传参,PDA作为转出方代币账户的所有者传入完整签名种子,程序ID传入TOKEN_PROGRAM_ID即可。
内容的提问来源于stack exchange,提问作者srb
相关产品推荐
相关产品推荐

