今天来看一个很重要的问题
就是创建账户,初始化Mint,创建Token账户
我们先来看客户端中的tx
const mint_tx = new anchor.web3.Transaction().add(
anchor.web3.SystemProgram.createAccount({
fromPubkey: provider.wallet.publicKey,
newAccountPubkey: mintKey.publicKey,
space: MINT_SIZE,
programId: TOKEN_PROGRAM_ID,
lamports,
}),
createInitializeMintInstruction(
mintKey.publicKey,
0,
provider.wallet.publicKey,
provider.wallet.publicKey,
),
createAssociatedTokenAccountInstruction(
provider.wallet.publicKey,
nftTokenAccount,
provider.wallet.publicKey,
mintKey.publicKey
)
);
const res = await program.provider.sendAndConfirm(mint_tx, [mintKey]);
那么我们需要把
createAccount
createInitializeMintInstruction
createAssociatedTokenAccountInstruction
这三个指令放到合约中去调用
试试看吧
试了很久很久
试了很多很多很多很多次
算是成功了一半
invoke的方式或者是anchor cpi的方式
分开调用的情况下都是成功的
但是合在一起就是不成功
真的很头疼
先看看invoke的方式
use anchor_lang::prelude::*;
use anchor_lang::solana_program;
use anchor_spl::token::spl_token;
use crate::solana_program::program::invoke;
declare_id!("HzMAyAPXaDKvtApQVqz1CSL8vHKRxF3FiM86WraCHgSs");
#[program]
pub mod game01_create_mint {
use super::*;
pub fn create(
ctx: Context<Create>,
lamports: u64,
space: u64,
) -> Result<()> {
let account_infos = vec![
ctx.accounts.system_program.to_account_info(),
ctx.accounts.token_program.to_account_info(),
ctx.accounts.from.to_account_info(),
ctx.accounts.to.to_account_info(),
];
invoke(
&solana_program::system_instruction::create_account(
&ctx.accounts.from.key(),
&ctx.accounts.to.key(),
lamports,
space,
&ctx.accounts.token_program.key(),
),
account_infos.as_slice(),
)?;
Ok(())
}
pub fn init_mint(
ctx: Context<InitMint>,
) -> Result<()> {
let account_infos = vec![
ctx.accounts.system_program.to_account_info(),
ctx.accounts.token_program.to_account_info(),
ctx.accounts.mint.to_account_info(),
ctx.accounts.rent.to_account_info(),
ctx.accounts.authority.to_account_info(),
ctx.accounts.freeze_authority.to_account_info(),
];
invoke(
&spl_token::instruction::initialize_mint(
ctx.accounts.token_program.key,
ctx.accounts.mint.key,
ctx.accounts.authority.key,
Some(ctx.accounts.freeze_authority.key),
9,
)?,
account_infos.as_slice(),
)?;
Ok(())
}
pub fn create_init_01(
ctx: Context<CreateInit01>,
lamports: u64,
space: u64,
) -> Result<()> {
msg!("Create Account");
let account_infos = vec![
ctx.accounts.system_program.to_account_info(),
ctx.accounts.token_program.to_account_info(),
ctx.accounts.from.to_account_info(),
ctx.accounts.to.to_account_info(),
];
invoke(
&solana_program::system_instruction::create_account(
&ctx.accounts.from.key(),
&ctx.accounts.to.key(),
lamports,
space,
&ctx.accounts.token_program.key(),
),
account_infos.as_slice(),
)?;
msg!("Initialize Mint");
let account_infos = vec![
ctx.accounts.system_program.to_account_info(),
ctx.accounts.token_program.to_account_info(),
ctx.accounts.mint.to_account_info(),
ctx.accounts.rent.to_account_info(),
ctx.accounts.authority.to_account_info(),
ctx.accounts.freeze_authority.to_account_info(),
];
invoke(
&spl_token::instruction::initialize_mint(
ctx.accounts.token_program.key,
ctx.accounts.mint.key,
ctx.accounts.authority.key,
Some(ctx.accounts.freeze_authority.key),
9,
)?,
account_infos.as_slice(),
)?;
Ok(())
}
}
#[derive(Accounts)]
pub struct Create<'info> {
pub system_program: Program<'info, System>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub token_program: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub from: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub to: AccountInfo<'info>,
pub signer: Signer<'info>,
}
#[derive(Accounts)]
pub struct InitMint<'info> {
pub system_program: Program<'info, System>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub token_program: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub rent: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub mint: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub authority: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub freeze_authority: AccountInfo<'info>,
pub signer: Signer<'info>,
}
#[derive(Accounts)]
pub struct CreateInit01<'info> {
pub system_program: Program<'info, System>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub token_program: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub rent: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub mint: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub authority: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub freeze_authority: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub from: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub to: AccountInfo<'info>,
pub signer: Signer<'info>,
}
然后是anchro cpi的方式
use anchor_lang::prelude::*;
use anchor_lang::system_program::{create_account, CreateAccount};
use anchor_spl::token::{initialize_mint, InitializeMint};
declare_id!("HzMAyAPXaDKvtApQVqz1CSL8vHKRxF3FiM86WraCHgSs");
#[program]
pub mod game01_create_mint {
use super::*;
pub fn create(
ctx: Context<Create>,
lamports: u64,
space: u64,
) -> Result<()> {
let cpi_accounts = CreateAccount {
from: ctx.accounts.from.to_account_info(),
to: ctx.accounts.to.to_account_info(),
};
let cpi_program = ctx.accounts.system_program.to_account_info();
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
create_account(cpi_ctx, lamports, space, ctx.accounts.token_program.key)?;
Ok(())
}
pub fn init_mint(
ctx: Context<InitMint>,
) -> Result<()> {
let cpi_accounts = InitializeMint {
mint: ctx.accounts.mint.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
};
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
initialize_mint(cpi_ctx, 9, ctx.accounts.authority.key, None)?;
Ok(())
}
pub fn create_init_01(
ctx: Context<CreateInit01>,
lamports: u64,
space: u64,
) -> Result<()> {
msg!("Create Account");
let cpi_accounts = CreateAccount {
from: ctx.accounts.authority.to_account_info(),
to: ctx.accounts.mint.to_account_info(),
};
let cpi_program = ctx.accounts.system_program.to_account_info();
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
create_account(cpi_ctx, lamports, space, ctx.accounts.token_program.key)?;
msg!("Initialize Mint");
let cpi_accounts = InitializeMint {
mint: ctx.accounts.mint.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
};
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
initialize_mint(cpi_ctx, 9, ctx.accounts.authority.key, None)?;
Ok(())
}
}
#[derive(Accounts)]
pub struct Create<'info> {
pub system_program: Program<'info, System>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub token_program: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub from: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub to: AccountInfo<'info>,
#[account(mut)]
pub signer: Signer<'info>,
}
#[derive(Accounts)]
pub struct InitMint<'info> {
pub system_program: Program<'info, System>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub token_program: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub rent: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub mint: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub authority: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub freeze_authority: AccountInfo<'info>,
#[account(mut)]
pub signer: Signer<'info>,
}
#[derive(Accounts)]
pub struct CreateInit01<'info> {
pub system_program: Program<'info, System>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub token_program: AccountInfo<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub rent: AccountInfo<'info>,
#[account(mut)]
pub mint: Signer<'info>,
#[account(mut)]
pub authority: Signer<'info>,
}
但是我用纯原生rust合约试了一下
是成功的
pub fn process_init(
program_id: &Pubkey,
accounts: &[AccountInfo],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let authority_info = next_account_info(account_info_iter)?;
let signer_info = next_account_info(account_info_iter)?;
let mint_info = next_account_info(account_info_iter)?;
let token_program_info = next_account_info(account_info_iter)?;
let rent_info = next_account_info(account_info_iter)?;
let system_info = next_account_info(account_info_iter)?;
assert_signer(&signer_info)?;
let size = 82;
let rent = &Rent::from_account_info(&rent_info)?;
let required_lamports = rent.minimum_balance(size);
msg!("create_account create");
invoke(
&system_instruction::create_account(
signer_info.key,
mint_info.key,
required_lamports,
size as u64,
token_program_info.key,
),
&[signer_info.clone(), mint_info.clone()],
)?;
msg!("initialize_mint");
invoke(
&initialize_mint(
token_program_info.key,
mint_info.key,
authority_info.key,
Some(authority_info.key),
9,
)?,
&[authority_info.clone(), mint_info.clone(),rent_info.clone(),token_program_info.clone(),],
)?;
msg!("initialize_mint::{:?} complete",mint_info.key.clone());
Ok(())
}
相比较起来
原生的和anchor中调用invoke
已经几乎是一一对应了
但是原生成功,anchor失败
我真的很无语
哎