1

I have a program which should be allowed to be called by whitelisted programs only. Currently I solved the issue as such, but I wonder whether there are other more elegant solutions (maybe, by using Instructions sysvar, just like Metaplex does).

#[derive(Accounts)]
#[instruction(caller_id: Pubkey, caller_bump: u8)]
pub struct Whitelisted<'info> {
    #[account(
        seeds = [crate::SIGNATURE],
        bump = caller_bump,
        seeds::program = caller_id,
    )]
    pub caller_signature: Signer<'info>,

    #[account(
        constraint = state.can_be_called_by(caller_id),
    )]
    pub state: Account<'info, State>,
}

---snip---

pub fn whitelisted(
    ctx: Context<Whitelisted>, 
    _caller_id: Pubkey,
    _called_bump: u8,
) -> anchor_lang::Result<()> {
    ---snip---
}

And I have a caller sign caller_signature pda account with invoke_signed and also pass its address with a bump, which were stored beforehand.

1 Answer 1

5

FWIW, this is how Metaplex candy-machine-v2 does it:

use solana_program::sysvar::instructions::get_instruction_relative;

const ALLOWED_PROGRAM_ID: Pubkey = solana_program::pubkey!("...");

// in your instruction:

let current_ix = get_instruction_relative(
  0, 
  &ctx.accounts.instruction_sysvar_account.to_account_info()
).unwrap();

if !cmp_pubkeys(&current_ix.program_id, &ALLOWED_PROGRAM_ID) {
  // not my program - throw error!
}

You can get the instruction, which this CPI call is an inner instruction of, and check that it matches the program ID you expect.

This is the relevant part in candy-machine-v2 source code.

1
  • 2
    Note that if you have Program A => CPI into Program B => CPI into Program C. Program C will see caller as Program A and not Program B
    – AnonBird
    Commented Aug 4, 2022 at 15:10

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.