Anchor 0.30.0使用TokenAccount报错:未实现Discriminator等问题求助
问题:Anchor 0.30.0开发中使用
Account<'a, TokenAccount>处理非Anchor账户报错 环境信息:
- Windows 10 64位 + Ubuntu WSL
- rustc 1.78.0
- anchor 0.30.0
- solana 1.18.13
参考官方文档「使用Account<'a, T>处理非Anchor程序账户」编写程序,运行anchor test时出现以下错误:
- error[E0599]: TokenAccount找不到
create_type关联项 - error[E0277]: TokenAccount未实现
Discriminatortrait - error[E0599]: TokenAccount找不到
insert_types关联项
示例代码
use anchor_lang::prelude::*; use anchor_spl::token::TokenAccount; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); #[program] mod hello_anchor { use super::*; pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> { if ctx.accounts.token_account.amount > 0 { ctx.accounts.my_account.data = data; } Ok(()) } } #[account] #[derive(Default)] pub struct MyAccount { data: u64, mint: Pubkey, } #[derive(Accounts)] pub struct SetData<'info> { #[account(mut)] pub my_account: Account<'info, MyAccount>, #[account( constraint = my_account.mint == token_account.mint, has_one = owner )] pub token_account: Account<'info, TokenAccount>, pub owner: Signer<'info>, }
错误信息
error[E0599]: no function or associated item named `create_type` found for struct `anchor_spl::token::TokenAccount` in the current scope --> programs/sol-test/src/lib.rs | | #[derive(Accounts)] | ^^^^^^^^ function or associated item not found in `TokenAccount` | = note: this error originates in the derive macro `Accounts` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `anchor_spl::token::TokenAccount: Discriminator` is not satisfied --> programs/sol-test/src/lib.rs | | pub token_account: Account<'info, TokenAccount>, | ^^^^^^^^^^^^ the trait `Discriminator` is not implemented for `anchor_spl::token::TokenAccount` | = help: the following other types implement trait `Discriminator`: MyAccount __idl::IdlAccount anchor_lang::ProgramData anchor_lang::idl::IdlAccount instruction::SetData error[E0599]: no function or associated item named `insert_types` found for struct `anchor_spl::token::TokenAccount` in the current scope --> programs/sol-test/src/lib.rs | | #[derive(Accounts)] | ^^^^^^^^ function or associated item not found in `TokenAccount` | = note: this error originates in the derive macro `Accounts` (in Nightly builds, run with -Z macro-backtrace for more info)
解决方案
这是Anchor版本迭代导致的文档滞后问题,Anchor 0.26+版本对非Anchor程序账户的处理方式做了调整:
Account<'a, T>类型要求泛型T必须实现Anchor的Discriminator trait以及相关的账户类型关联方法,而原生的anchor_spl::token::TokenAccount是对应Solana Token程序的账户结构,并没有实现这些Anchor专属的trait,因此报错。
有两种可行的修改方式:
方式一:使用Anchor SPL提供的接口化TokenAccount
Anchor SPL在interface模块下提供了适配Anchor账户校验的TokenAccount类型,替换原导入即可解决问题:
修改后的代码:
use anchor_lang::prelude::*; // 替换原TokenAccount导入为interface下的版本 use anchor_spl::token::interface::TokenAccount; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); #[program] mod hello_anchor { use super::*; pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> { if ctx.accounts.token_account.amount > 0 { ctx.accounts.my_account.data = data; } Ok(()) } } #[account] #[derive(Default)] pub struct MyAccount { data: u64, mint: Pubkey, } #[derive(Accounts)] pub struct SetData<'info> { #[account(mut)] pub my_account: Account<'info, MyAccount>, #[account( constraint = my_account.mint == token_account.mint, has_one = owner )] pub token_account: InterfaceAccount<'info, TokenAccount>, // 用InterfaceAccount替代Account pub owner: Signer<'info>, }
方式二:直接使用AccountInfo结合手动校验
如果不想依赖接口化类型,可以直接用AccountInfo,并手动添加Token账户的校验约束:
修改后的代码:
use anchor_lang::prelude::*; use anchor_spl::token::{self, TokenAccount}; use solana_program::program_pack::Pack; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); #[program] mod hello_anchor { use super::*; pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> { // 手动解析TokenAccount数据 let token_account = TokenAccount::unpack(&ctx.accounts.token_account.data.borrow())?; if token_account.amount > 0 { ctx.accounts.my_account.data = data; } Ok(()) } } #[account] #[derive(Default)] pub struct MyAccount { data: u64, mint: Pubkey, } #[derive(Accounts)] pub struct SetData<'info> { #[account(mut)] pub my_account: Account<'info, MyAccount>, /// CHECK: 手动校验Token账户 #[account( mut, constraint = token_account.owner == owner.key(), constraint = my_account.mint == TokenAccount::unpack(&token_account.data.borrow())?.mint, constraint = *token_account.owner == token::ID // 校验账户属于Token程序 )] pub token_account: AccountInfo<'info>, pub owner: Signer<'info>, }
关键说明
- 第一种方式更简洁,是Anchor官方推荐的适配非Anchor程序账户的新方式
- 第二种方式更底层,适合需要完全自定义校验逻辑的场景
内容的提问来源于stack exchange,提问作者puelo
相关产品推荐
相关产品推荐

