You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:48:28