0

I have been figuring this one out for a few days. Appreciate the help.

I want to be able to send the tokens from the PDA ATA to the user who is removing his vault.\

This is the error I am getting: Error: Signature verification failed

My function:

   pub fn remove_vault(
    ctx: Context<RemoveVault>,
    _vault_idx: u8,
    // _info_address: Pubkey,
) -> Result<()> {
    // Decreate total todo count
    let user_profile = &mut ctx.accounts.user_profile;
    user_profile.vault_count = user_profile.vault_count.checked_sub(1).unwrap();

    let vault_account = &mut ctx.accounts.vault_account;

    let time_diff = Clock::get().unwrap().unix_timestamp - vault_account.staked_at;

    let vault_info = &mut ctx.accounts.vault_info;

    msg!("Total staking time (seconds): {}", time_diff.to_string());
    // msg!("Token program: {}", vault_info.token);
    msg!("CMV2 ID: {}", vault_info.cmv2);

    // let seed = &[&[INFO_TAG]];

    // let sender = &mut ctx.accounts.vault_info.key();

    // let sender_key = sender.as_ref();

    let inner = vec![INFO_TAG.as_ref()];
    // &[&["INFO_STATE".as_ref(),ctx.accounts.authority.key().as_ref()]]
    let outer = vec![inner.as_slice()];

    // let cpi_ctx = CpiContext::new_with_signer(
    //     ctx.accounts.token_program.to_account_info(),
    //     token::Transfer {
    //         from: ctx.accounts.sender.to_account_info(),
    //         to: ctx.accounts.receiver.to_account_info(),
    //         authority: ctx.accounts.vault_info.to_account_info(),
    //     },
    //     // &[&[INFO_TAG]],
    // outer.as_slice(),
    // );

    let cpi_accounts = Transfer {
        from: ctx.accounts.from.to_account_info().clone(),
        to: ctx.accounts.to.to_account_info().clone(),
        authority: ctx.accounts.owner.to_account_info().clone(),
    };
    let cpi_program = ctx.accounts.token_program.clone();
    let cpi_ctx = CpiContext::new_with_signer(
        cpi_program,
        cpi_accounts,
        outer.as_slice(), // outer.as_slice()
    );

    token::transfer(cpi_ctx, 10 * 10 * 9)?;

    // token::transfer(cpi_ctx, 1)?;

    // No need to decrease last todo idx

    // Todo PDA already closed in context

    Ok(())

My Struct:

pub struct RemoveVault<'info> {
#[account(
    mut,
    seeds = [USER_TAG, authority.key().as_ref()],
    bump,
    has_one = authority,
)]
pub user_profile: Box<Account<'info, UserProfile>>,

#[account(
    mut,
    close = authority,
    seeds = [VAULT_TAG, authority.key().as_ref(), &[vault_idx].as_ref()],
    bump,
    has_one = authority,
)]
pub vault_account: Box<Account<'info, UserVault>>,

#[account(mut, signer,
    seeds = [INFO_TAG
    // , authority.key().as_ref()
    ],
    bump,
)]
pub vault_info: Box<Account<'info, VaultInfo>>,

#[account(mut)]
/// CHECK: PDA is handling this as signer
pub authority: Signer<'info>,

pub system_program: Program<'info, System>,

#[account(mut, has_one = owner)]
/// CHECK: PDA is handling this as signer
from: Account<'info, TokenAccount>,
// #[account(mut)]
#[account(mut, "from.mint == to.mint")]
/// CHECK: PDA is handling this as signer
to: Account<'info, TokenAccount>,
#[account(mut)]
/// CHECK: PDA is handling this as signer
owner: UncheckedAccount<'info>,
/// CHECK: PDA is handling this as signer
token_program: AccountInfo<'info>,

}

My testing script:

it("User Vault removed!", async () => {
// Add your test here.
// const tx = await program.methods.initializeUser().rpc();

console.log("user:", user.publicKey)
console.log("program:", program.programId)
console.log("token program:", TOKEN_PROGRAM_ID)

console.log("Mint:", mintPubkey.toBase58())


const [userProfilePDA] = await anchor.web3.PublicKey.findProgramAddress([
  utf8.encode("USER_STATE"),
  user.publicKey.toBuffer(),
],
  program.programId
);
console.log("userProfilePDA", userProfilePDA.toBase58());

const userProfile = await program.account.userProfile.fetch(userProfilePDA);
// console.log("UserProfile:", userProfile)
console.log("Last vault:", userProfile.lastVault)

const [vaultAccountPDA] = await anchor.web3.PublicKey.findProgramAddress([
  utf8.encode("VAULT_STATE"),
  user.publicKey.toBuffer(),
  new anchor.BN(0).toBuffer()
],
  program.programId
);
console.log("vaultAccountPDA:", vaultAccountPDA.toBase58());

const [vaultInfoPDA] = await anchor.web3.PublicKey.findProgramAddress([
  utf8.encode("INFO_STATE"),
  // user.publicKey.toBuffer(),
],
  program.programId
);
console.log("vaultInfoPDA:", vaultInfoPDA.toBase58());


let tokenAccountPubkeyUser = await getOrCreateAssociatedTokenAccount(program.provider.connection, user, mintPubkey, user.publicKey)


console.log("tokenProgram:", TOKEN_PROGRAM_ID.toBase58())
console.log("receiver ATA:", tokenAccountPubkeyUser.address.toBase58())

let tokenAuth = await program.provider.connection.getAccountInfo(tokenAccountPubkeyUser.address);

console.log("receiver (user) ATA owner:", tokenAuth.owner.toBase58())

let tokenAccountPubkeyVault = await getOrCreateAssociatedTokenAccount(program.provider.connection, user, mintPubkey, vaultInfoPDA, true)


console.log("sender (VaultInfo) ATA:", tokenAccountPubkeyVault.address.toBase58())


let txhash = await transferChecked(
  program.provider.connection, // connection
  user, // payer
  tokenAccountPubkeyUser.address, // from (should be a token account)
  mintPubkey, // mint
  tokenAccountPubkeyVault.address, // to (should be a token account)
  user, // from's owner
  10e9, // amount, if your deciamls is 9, send 10^9 for 1 token
  9 // decimals
);


let tokenAmount = await program.provider.connection.getTokenAccountBalance(tokenAccountPubkeyVault.address);

console.log("VaultInfo ATA supply:", tokenAmount.value.uiAmount)

tokenAuth = await program.provider.connection.getAccountInfo(tokenAccountPubkeyVault.address);

console.log("VaultATA owner:", tokenAuth.owner.toBase58())

tokenAuth = await program.provider.connection.getAccountInfo(program.programId);

console.log("Program owner:", tokenAuth.owner.toBase58())

tokenAuth = await program.provider.connection.getAccountInfo(vaultInfoPDA);

console.log("vaultInfoPDA owner:", tokenAuth.owner.toBase58())



const tx = await program.rpc.removeVault(0, {
  accounts: {
    authority: user.publicKey,
    userProfile: userProfilePDA,
    vaultAccount: vaultAccountPDA,
    vaultInfo: vaultInfoPDA,
    systemProgram: anchor.web3.SystemProgram.programId,
    tokenProgram: TOKEN_PROGRAM_ID,
    from: tokenAccountPubkeyVault.address,
    to: tokenAccountPubkeyUser.address,
    owner: vaultInfoPDA,
    // sender: vaultInfoPDA
  },
  signers: []
})

console.log("Your transaction signature", tx);

});

1 Answer 1

0

In your struct, authority is a signer:

#[account(mut)]
/// CHECK: PDA is handling this as signer
pub authority: Signer<'info>,

But you're not passing in user as a signer, so try to add user as a signer. Note the last parameter:

const tx = await program.rpc.removeVault(0, {
  accounts: {
    authority: user.publicKey,
    userProfile: userProfilePDA,
    vaultAccount: vaultAccountPDA,
    vaultInfo: vaultInfoPDA,
    systemProgram: anchor.web3.SystemProgram.programId,
    tokenProgram: TOKEN_PROGRAM_ID,
    from: tokenAccountPubkeyVault.address,
    to: tokenAccountPubkeyUser.address,
    owner: vaultInfoPDA,
    // sender: vaultInfoPDA
  },
  signers: [user]
})

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.