-1

I simply tried transferring token from account A (vault_account) to account B (receiver_account) using both traditional method and anchor method. In both of the methods i used receiver_account as signer. But the anchor method is throwing Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account. This error was solved if i use vault_account as signer. Can anyone explain why is this happening because As far as i know both of these method does the same thing under the hood.

Traditional method:

let (_account_address, bump) = Pubkey::find_program_address(
            &[&sender_account.key.to_bytes()], 
            program_id
        );

        let pda_signer_seeds: &[&[_]] = &[&sender_account.key.to_bytes(), &[bump]];
        
        //transfering token to receiver_associated_info
        invoke_signed(
            &spl_token::instruction::transfer(
                token_program_info.key,
                vault_associated_info.key,
                receiver_associated_info.key,
                vault.key,
                &[vault.key],
                amount,
            )?,
            &[
                token_program_info.clone(),
                vault_associated_info.clone(),
                receiver_associated_info.clone(),
                vault.clone(),
                system_program.clone()
            ],&[&pda_signer_seeds],
        )?;

Anchor method:

 let (_account_address, bump) = Pubkey::find_program_address(
            &[&ctx.accounts.sender_account.key.to_bytes()], 
            ctx.program_id
        );

        let pda_signer_seeds: &[&[&[_]]] = &[&[&ctx.accounts.vault.key.to_bytes(), &[bump]]];
        
        let transfer_ix = Token_Transfer{
            from: ctx.accounts.vault_associated_info.to_account_info(),
            to: ctx.accounts.receiver_associated_info.to_account_info(),
            authority: ctx.accounts.vault.to_account_info()
        };

        let cpi_ctx = CpiContext::new_with_signer(
            ctx.accounts.system_program.to_account_info(),
            transfer_ix,
            pda_signer_seeds,
        );
        
        token_transfer(cpi_ctx, amount)?;

1 Answers1

0

For the traditional method, you need to pass in the accounts in the correct order, and specify the arguments correctly:

        invoke_signed(
            &spl_token::instruction::transfer(
                token_program_info.key,
                vault_associated_info.key,
                receiver_associated_info.key,
                vault.key,
                &[],
                amount,
            )?,
            [
                vault_associated_info.clone(),
                receiver_associated_info.clone(),
                vault.clone(),
                token_program_info.clone()
            ],&[&pda_signer_seeds],
        )?;

This is assuming that vault.key == _account_address derived earlier, otherwise you may get an error.

For Anchor, you'll need to specify the correct program that you're invoking:

        let cpi_ctx = CpiContext::new_with_signer(
            ctx.accounts.token_program.to_account_info(),
            transfer_ix,
            pda_signer_seeds,
        );

Separate note: in the case of an SPL token transfer, you don't need the receiver to sign, only the authority of the sender account.

Jon C
  • 7,019
  • 10
  • 17