PDA imzalayıcılarla CPI'lar

Özet

Çağıran programın sahip olduğu bir PDA adına imzalaması gerektiğinde invoke_signed kullanın. Çalışma zamanı, sağlanan imzalayıcı seed'lerinden PDA pubkey'lerini türetir ve yetki kontrolünden önce bunları geçerli imzalayıcılar kümesine ekler.

PDA imzalayıcılarla CPI'lar

Bir CPI, PDA imzalayıcısı gerektirdiğinde, PDA'yı türetmek için kullanılan imzalayıcı seed'leri ile birlikte invoke_signed kullanın. Çalışma zamanının PDA imzalarını nasıl doğruladığına ilişkin ayrıntılar için PDA imzalama bölümüne bakın.

Invoke signed
pub fn invoke_signed(
instruction: &Instruction,
account_infos: &[AccountInfo],
signers_seeds: &[&[&[u8]]],
) -> ProgramResult {
// --snip--
invoke_signed_unchecked(instruction, account_infos, signers_seeds)
}

Aşağıdaki örnekler, Anchor ve Native Rust kullanarak PDA imzalayıcılarla bir CPI yapar. Her örnek, PDA tarafından imzalanan bir CPI kullanarak bir PDA'dan alıcı hesaba SOL transfer etmek için tek bir talimat içerir.

Anchor

Aşağıdaki örnekler, bir Anchor programında CPI'ları uygulamak için iki yaklaşım gösterir. Örnekler işlevsel olarak eşdeğerdir, ancak farklı soyutlama seviyelerini gösterir.

  • Örnek 1: Anchor'ın CpiContext ve yardımcı fonksiyonunu kullanır.
  • Örnek 2: solana_program crate'inden system_instruction::transfer fonksiyonunu kullanır. (Örnek 1, bu uygulamanın bir soyutlamasıdır.)
  • Örnek 3: CPI talimatını manuel olarak oluşturur. Bu yaklaşım, çağırmak istediğiniz talimatı oluşturmaya yardımcı olacak bir crate bulunmadığında kullanışlıdır.
use anchor_lang::prelude::*;
use anchor_lang::system_program::{transfer, Transfer};
declare_id!("BrcdB9sV7z9DvF9rDHG263HUxXgJM3iCQdF36TcxbFEn");
#[program]
pub mod cpi {
use super::*;
pub fn sol_transfer(ctx: Context<SolTransfer>, amount: u64) -> Result<()> {
let from_pubkey = ctx.accounts.pda_account.to_account_info();
let to_pubkey = ctx.accounts.recipient.to_account_info();
let program_id = ctx.accounts.system_program.to_account_info();
let seed = to_pubkey.key();
let bump_seed = ctx.bumps.pda_account;
let signer_seeds: &[&[&[u8]]] = &[&[b"pda", seed.as_ref(), &[bump_seed]]];
let cpi_context = CpiContext::new(
program_id,
Transfer {
from: from_pubkey,
to: to_pubkey,
},
)
.with_signer(signer_seeds);
transfer(cpi_context, amount)?;
Ok(())
}
}
#[derive(Accounts)]
pub struct SolTransfer<'info> {
#[account(
mut,
seeds = [b"pda", recipient.key().as_ref()],
bump,
)]
pda_account: SystemAccount<'info>,
#[account(mut)]
recipient: SystemAccount<'info>,
system_program: Program<'info, System>,
}

Rust

Aşağıdaki örnek, Native Rust ile yazılmış bir programdan PDA imzalayıcılarla bir CPI gerçekleştirir. SOL'u bir PDA hesabından başka bir hesaba aktaran tek bir talimat içerir. CPI, PDA hesabı tarafından imzalanır. (Test dosyası, programı test etmek için LiteSVM kullanır.)

use borsh::BorshDeserialize;
use solana_program::{
account_info::AccountInfo,
entrypoint,
entrypoint::ProgramResult,
program::invoke_signed,
program_error::ProgramError,
pubkey::Pubkey,
system_instruction,
};
// Declare program entrypoint
entrypoint!(process_instruction);
// Define program instructions
#[derive(BorshDeserialize)]
enum ProgramInstruction {
SolTransfer { amount: u64 },
}
impl ProgramInstruction {
fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
Self::try_from_slice(input).map_err(|_| ProgramError::InvalidInstructionData)
}
}
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
// Deserialize instruction data
let instruction = ProgramInstruction::unpack(instruction_data)?;
// Process instruction
match instruction {
ProgramInstruction::SolTransfer { amount } => {
// Parse accounts
let [pda_account_info, recipient_info, system_program_info] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
// Derive PDA and verify it matches the account provided by client
let recipient_pubkey = recipient_info.key;
let seeds = &[b"pda", recipient_pubkey.as_ref()];
let (expected_pda, bump_seed) = Pubkey::find_program_address(seeds, program_id);
if expected_pda != *pda_account_info.key {
return Err(ProgramError::InvalidArgument);
}
// Create the transfer instruction
let transfer_ix = system_instruction::transfer(
pda_account_info.key,
recipient_info.key,
amount,
);
// Create signer seeds for PDA
let signer_seeds: &[&[&[u8]]] = &[&[b"pda", recipient_pubkey.as_ref(), &[bump_seed]]];
// Invoke the transfer instruction with PDA as signer
invoke_signed(
&transfer_ix,
&[
pda_account_info.clone(),
recipient_info.clone(),
system_program_info.clone(),
],
signer_seeds,
)?;
Ok(())
}
}
}

Is this page helpful?

İçindekiler

Sayfayı Düzenle

Yönetici

© 2026 Solana Vakfı.
Tüm hakları saklıdır.
Bağlanın