2

I am writing an anchor program where I want to sign a CPI as both a PDA from my program and the signer of the tx. I expect it would look something like this:

CpiContext::new_with_signer(
   program,
   accounts,
   [ctx.accounts.signer, pda_signer_seeds]
)```

How would one do this? 

3 Answers 3

4

You do not need to explicitly pass the non-PDA signer into the signer_seeds array. It will be passed through from the caller automatically as long as is_signer is true in the corresponding AccountInfo in your accounts array.

See https://solanacookbook.com/core-concepts/cpi.html#cpi-with-invoke

1

Here is a simple example using the CpiContext::new_with_signer to transfer some tokens from a token vault owned by this program. Inside the seeds I put in the values needed to create the PDA of the vault as described in the Withdraw vault_account seeds.

#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(
        mut,
        seeds = [b"vault", to.mint.as_ref()],
        bump,
    )]
    pub vault_account: Account<'info, TokenAccount>,
    #[account(
        mut,
        seeds = [b"vault-access", to.mint.as_ref(), authority.key().as_ref()],
        bump, 
        constraint = vault_access.authority == authority.key()
    )]
    pub vault_access: Account<'info, VaultAccess>,
    #[account(mut, constraint = to.owner == authority.key())]
    pub to: Account<'info, TokenAccount>,
    pub authority: Signer<'info>,
    pub token_program: Program<'info, Token>,
}
pub fn withdraw(ctx: Context<Withdraw>, amount: u64, bump: u8) -> Result<()> {
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_accounts = Transfer {
            from: ctx.accounts.vault_account.to_account_info(),
            to: ctx.accounts.to.to_account_info(),
            authority: ctx.accounts.vault_account.to_account_info(),
        };

        if amount > ctx.accounts.vault_access.amount {
            return Err(ErrorCode::InsufficientFundsInVault.into())
        }

        ctx.accounts.vault_access.amount -= amount;

        token::transfer(
            CpiContext::new_with_signer(
                cpi_program, 
                cpi_accounts,
                &[&[b"vault", ctx.accounts.to.mint.as_ref(), &[bump]]]), 
            amount)?;
        Ok(())
    }

Note - with the latest version of anchor you don't need to pass the bump in as a parameter if you don't want to. There are new ways to deal with the bump that can make things a bit easier.

0

token::transfer( CpiContext::new_with_signer( cpi_program, cpi_accounts, &[&[b"vault", ctx.accounts.to.mint.as_ref(), &[bump]]]), amount)?; Ok(())

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.