Solana Anchor程序获取Token余额报错:预期&AccountInfo<'_>,实际&Pubkey
Solana Anchor链上获取用户Token余额的正确方法
你的代码报错expected &AccountInfo<'_>, found &Pubkey,核心原因是Account::try_from需要传入链上账户的AccountInfo引用,但你传的是推导出来的Pubkey地址,类型不匹配导致错误。下面是两种链上获取用户Token余额的正确实现方式:
方法一:Anchor自动验证关联Token账户(推荐,适用于账户已存在场景)
直接在Accounts结构体中声明关联Token账户,Anchor会自动完成地址推导、有效性验证,无需手动处理:
use anchor_lang::prelude::*; use anchor_spl::token::{self, Mint, TokenAccount, AssociatedToken}; #[derive(Accounts)] pub struct FetchUserTokenBalance<'info> { #[account(mut)] pub user: Signer<'info>, pub token_mint: Account<'info, Mint>, // 自动关联用户的Token账户,Anchor会验证地址和归属 #[account( associated_token::mint = token_mint, associated_token::authority = user )] pub user_token_account: Account<'info, TokenAccount>, // 必须传入的依赖程序账户 pub token_program: Program<'info, token::Token>, pub associated_token_program: Program<'info, AssociatedToken>, pub system_program: Program<'info, System>, } pub fn fetch_user_token_balance(ctx: Context<FetchUserTokenBalance>) -> Result<()> { // 直接从上下文读取余额 let token_balance = ctx.accounts.user_token_account.amount; msg!("用户的Token余额: {:?}", token_balance); Ok(()) }
这种方式的优势是Anchor帮你完成了所有安全校验:确保关联账户属于该用户和铸币地址、账户已初始化等,代码简洁且不易出错。
方法二:处理账户可能不存在的场景
如果需要判断用户是否尚未创建该Token的关联账户(余额为0),可以手动推导地址后验证并解析:
use anchor_lang::prelude::*; use anchor_spl::token::{Mint, TokenAccount}; use spl_associated_token_account::get_associated_token_address; #[derive(Accounts)] pub struct FetchUserTokenBalance<'info> { #[account(mut)] pub user: Signer<'info>, pub token_mint: Account<'info, Mint>, // 传入关联Token账户的AccountInfo(不管是否存在) pub user_token_account: AccountInfo<'info>, } pub fn fetch_user_token_balance(ctx: Context<FetchUserTokenBalance>) -> Result<()> { let user_pubkey = ctx.accounts.user.key(); let token_mint = ctx.accounts.token_mint.key(); // 推导预期的关联Token账户地址 let expected_ata_address = get_associated_token_address(&user_pubkey, &token_mint); // 验证传入的账户地址是否匹配 require!(ctx.accounts.user_token_account.key() == expected_ata_address, CustomError::InvalidTokenAccount); // 检查账户是否未初始化(即用户未持有该Token) if ctx.accounts.user_token_account.data_is_empty() { msg!("用户未持有该Token,余额为0"); return Ok(()); } // 解析Token账户数据获取余额 let token_account = Account::<TokenAccount>::try_from(&ctx.accounts.user_token_account)?; msg!("用户的Token余额: {:?}", token_account.amount); Ok(()) } // 自定义错误类型示例 #[error_code] pub enum CustomError { #[msg("无效的Token账户")] InvalidTokenAccount, }
这种方式需要调用方传入关联Token账户的AccountInfo,程序先验证地址正确性,再判断账户是否存在,灵活处理未持有Token的情况。
内容的提问来源于stack exchange,提问作者Jack Moes
相关产品推荐
相关产品推荐

