1

How can multiple accounts can sign transaction along with PDA ?

In PDA based CPI in which PDA signs transactions, how can we use multiple accounts as a signers ?

I have to create an account in callee program using CPI, here I have to pass new account address or public key by signing transaction to callee program.

Callee Program

#[program]
mod callee {
    use super::*;

    // I want to call this method using cpi in which pda should be signer.
    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
        ctx.accounts.new_account.data = data;
        msg!("Changed data to: {}!", data);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 8 + 8)]
    pub new_account: Account<'info, NewAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct NewAccount {
    data: u64
}

Caller Program

#[constant]
const USER_ACCOUNT_SEEDS: &[u8] = b"USER_ACCOUNT_SEEDS";

#[program]
pub mod caller {
    use super::*;

    pub fn create_user_account(ctx: Context<CreateUserAccount>) -> Result<()> {
        ctx.accounts.user_account.bump = *ctx.bumps.get("user_account").unwrap();
        Ok(())
    }

    pub fn invoke_transaction<'info>(
        ctx: Context<'_, '_, '_, 'info, InvokeTransaction<'info>>,
        data: Vec<u8>,
    ) -> Result<()> {
        // Am i doing any mistake here
        let ix = solana_program::instruction::Instruction {
            program_id: ctx.accounts.program_to_be_called.key(),
            accounts: vec![
                AccountMeta::new(ctx.accounts.new_account.key(), true),
                AccountMeta::new(ctx.accounts.user_account.key(), true),
                AccountMeta::new_readonly(ctx.accounts.system_program.key(), false),
            ],
            data,
        };

        solana_program::program::invoke_signed(
            &ix,
            &[
                ctx.accounts.new_account.to_account_info(),
                ctx.accounts.user_account.to_account_info(),
                ctx.accounts.system_program.to_account_info(),
            ],
            &[&[
                USER_ACCOUNT_SEEDS,
                ctx.accounts.signer.key().as_ref(),
                &[ctx.accounts.user_account.bump],
            ]],
        )?;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct CreateUserAccount<'info> {
    #[account(
        init,
        payer=signer,
        space= 8 + std::mem::size_of::<UserAccount>(),
        seeds=[USER_ACCOUNT_SEEDS,signer.key().as_ref()],
    bump)]
    pub user_account: Account<'info, UserAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct UserAccount {
    pub owner: Pubkey,
    pub bump: u8,
}

#[derive(Accounts)]
pub struct InvokeTransaction<'info> {
    #[account(mut)]
    pub user_account: Account<'info, UserAccount>,

    /// CHECK: provide dummy program ID here
    pub program_to_be_called: UncheckedAccount<'info>,

    /// CHECK: provide dummy program ID here
    #[account(mut, signer)]
    pub new_account: AccountInfo<'info>,

    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}
  • Error i am getting Invalid program argument.

  • Note:- When i use signer of invoke_transaction as a signer in cpi this code works fine, but when i use user_account (pda) as a signer i gets above given error.

1 Answer 1

1

You can use multiple addresses to sign a CPI. Here's how you will do it:

invoke_signed(
        &instruction,
        accounts,
        &[&["First addresses seed"],
          &["Second addresses first seed", "Second addresses second seed"]],
    )?;

Source: https://docs.solana.com/developing/programming-model/calling-between-programs#program-signed-accounts


If the CPI instruction requires a non-PDA signer, add the signature for such signer in your original transaction. No adjustments needed at the program level.

6
  • This is useful when all signers are PDA address, what to do when other signers are not PDA addresses. Apr 29, 2023 at 16:26
  • In such case, just sign your original transaction with the new account. No adjustment is needed at the program level. The answer is edited to reflect the fact.
    – 0xShuk
    Apr 29, 2023 at 17:48
  • I had also tried this, can you please share any example Or demo code with me ? Apr 29, 2023 at 18:00
  • Can you share your callee program? I will explain the caller program's instruction and the client side code on the basis of that.
    – 0xShuk
    Apr 29, 2023 at 18:46
  • I have edited question and added my callee and caller program code. Apr 29, 2023 at 19:27

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.