I just want to invoke initialize method of callee program from caller program in which pda account should be signer.
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.
How i have solved this issue
As 0xShuk have mentioned that we can fix this issue by creating system program owned pda, i have initially tried to create system owned pda account by transferring sol from phantom wallet to my pda address but when i was trying this phantom was not allowing me to do this and it was throwing error as "Invalid address".
After this i have tried to create system owned pda account by using
solana_program::system_instruction::create_account
method but it was still not working, but by this way i was able to create system program owned account.Solution:- Then i have created system program owned pda by just transferring sol using solana program, you can do this by using
solana_sdk
orweb3js Solana
.
pub fn create_system_program_owned_pda(ctx: Context<CreatePDA>) -> Result<()> {
let lamports = 1000000;
let (_pubkey, bump) = Pubkey::find_program_address(
&[USER_TEMP_ACCOUNT, ctx.accounts.signer.key().as_ref()],
&ID,
);
anchor_lang::solana_program::program::invoke_signed(
&anchor_lang::solana_program::system_instruction::transfer(
&ctx.accounts.signer.key(),
&ctx.accounts.temp_account.key(),
lamports,
),
&[
ctx.accounts.temp_account.to_account_info(),
ctx.accounts.signer.to_account_info(),
],
&[&[
USER_TEMP_ACCOUNT,
ctx.accounts.signer.key().as_ref(),
&[bump],
]],
)?;
Ok(())
}
#[derive(Accounts)]
pub struct CreatePDA<'info> {
/// CHECK: provide dummy program ID here
#[account(mut)]
pub temp_account: AccountInfo<'info>,
#[account(mut)]
pub signer: Signer<'info>,
pub system_program: Program<'info, System>,
}
Hope this will help you and eventually thank you so much 0xShuk.