I've been working on Solana program that should hold two different tokens for me in a Vault in an ATA. The first token should be deposited during Vault initialisation, the second will be deposited by exchanging for the first, will some fixed ratio. Both ATAs for the PDA of the Vault i wanted to be created during Vault initialisation. The problem is i keep getting error:
bundle.js:85 Error initializing vault: Error: Signature verification failed
at Je.serialize (<anonymous>:3:173798)
at AnchorProvider.sendAndConfirm (provider.ts:157:1)
at async MethodsBuilder.rpc [as _rpcFn] (rpc.ts:29:1)
at async initializeVault
The PDA initialisation looks fine, i was comparing it with lots of similar programs, tried debugging it, looks like the error is not related to fn initialize_vault
but it's related to account creation. Here is an Anchor code:
#[program]
pub mod heim_token {
use super::*;
pub fn initialize_vault(ctx: Context<InitializeVault>, initial_heim_amount: u64) -> Result<()> {
if ctx.accounts.authority_heim_ata.mint != mints::HEIM_ADDRESS {
return Err(ProgramError::InvalidAccountData.into());
}
let vault = &mut ctx.accounts.vault;
vault.authority = *ctx.accounts.authority.key;
vault.heim_amount = initial_heim_amount;
vault.usdc_amount = 0;
let cpi_accounts = SplTransfer {
from: ctx.accounts.authority_heim_ata.to_account_info().clone(),
to: ctx.accounts.vault_heim_ata.to_account_info().clone(),
authority: ctx.accounts.authority.to_account_info().clone()
};
let cpi_program = ctx.accounts.token_program.to_account_info();
token::transfer(CpiContext::new(cpi_program, cpi_accounts), initial_heim_amount)?;
Ok(())
}
}
#[account]
pub struct Vault {
pub authority: Pubkey,
pub heim_amount: u64,
pub usdc_amount: u64,
pub bump: u8,
}
#[derive(Accounts)]
pub struct InitializeVault<'info> {
#[account(mut)]
pub authority: Signer<'info>,
#[account(
init,
payer = authority,
space = 8 + 64 + 32 + 1,
seeds=[b"heim_vault".as_ref(), authority.key().as_ref()],
bump
)]
pub vault: Account<'info, Vault>,
#[account(
init,
payer = authority,
associated_token::mint = heim_mint,
associated_token::authority = authority,
)]
pub vault_heim_ata: Account<'info, TokenAccount>,
pub heim_mint: Account<'info, Mint>,
#[account(
init,
payer = authority,
associated_token::mint = usdc_mint,
associated_token::authority = authority,
)]
pub vault_usdc_ata: Account<'info, TokenAccount>,
pub usdc_mint: Account<'info, Mint>,
#[account(mut)]
pub authority_heim_ata: Account<'info, TokenAccount>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, Token>,
pub rent: Sysvar<'info, Rent>, // do i really need it here? google it
pub associated_token_program: Program<'info, AssociatedToken>,
}
And this is the client-side:
const getProvider = () => {
const connection = new Connection(network, opts.preflightCommitment)
return new AnchorProvider(connection, window.solana, opts.preflightCommitment)
}
const initializeVault = async() => {
try {
const provider = getProvider()
const program = new Program(idl, programID, provider)
const heimMint = new PublicKey(
"BVqRM5tbqerXFnGBSDZMvGEvdUx3aVNUadBiQBbjAjxB"
);
const usdcMint = new PublicKey(
"NkHsgx5xBCPp6Gi33KTPgD2weVJJY884NiuVjz76APn"
);
const mintInfo = await provider.connection.getAccountInfo(heimMint)
const data = MintLayout.decode(mintInfo.data);
// eslint-disable-next-line no-unused-vars
const [vault, _] = PublicKey.findProgramAddressSync(
[
utils.bytes.utf8.encode("heim_vault"),
provider.wallet.publicKey.toBuffer()
],
program.programId
);
const authorityHeimATA = await getAssociatedTokenAddress(heimMint, provider.wallet.publicKey);
const vaultHeimATA = await getAssociatedTokenAddress(heimMint, vault, true);
const vaultUsdcATA = await getAssociatedTokenAddress(usdcMint, vault, true);
const heim_amount = new BN(1000).mul(new BN(10).pow(new BN(data.decimals)))
const result = await program.methods.initializeVault(heim_amount).accounts(
{
authority: provider.wallet.publicKey,
vault: vault,
heimMint: heimMint,
usdcMint: usdcMint,
systemProgram: SystemProgram.programId,
authorityHeimAta: authorityHeimATA,
vaultHeimAta: vaultHeimATA,
vaultUsdcAta: vaultUsdcATA,
tokenProgram: TOKEN_PROGRAM_ID,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
rent: web3.SYSVAR_RENT_PUBKEY,
}
).rpc()
console.log("result", result)
getVault();
} catch (error) {
console.error('Error initializing vault:', error)
}
}
If you guys could take a look at it that would be great. This is devnet code so usdc is a fake usdc.
bump,
on theTokenAccount
init decorators.