Noções Básicas de CPI em Anchor
8 exemplos para você começar com CPIs em Anchor - 5 básicos e 3 intermediários.
Pré-requisitos
- anchor-lang 0.32.1 e anchor-spl 0.32.1 no
Cargo.tomldo programa - Compreensão de Manipuladores de Instruções
- Contas de programa para System, Token ou alvos personalizados na struct de contas
Exemplos Básicos
1. CpiContext::new para transferência de SOL
O programa System CPI move lamports entre contas.
use anchor_lang::system_program::{self, Transfer};
system_program::transfer(
CpiContext::new(
ctx.accounts.system_program.to_account_info(),
Transfer {
from: ctx.accounts.payer.to_account_info(),
to: ctx.accounts.recipient.to_account_info(),
},
),
lamports,
)?;- A conta do programa é o primeiro argumento para CpiContext::new
- A struct interna lista as metadados da conta para a CPI
- Use
?para propagar ProgramError
2. CPI de transferência de token SPL
anchor-spl envolve a invocação do programa de token.
use anchor_spl::token::{self, Transfer};
token::transfer(
CpiContext::new(
ctx.accounts.token_program.to_account_info(),
Transfer {
from: ctx.accounts.from_ata.to_account_info(),
to: ctx.accounts.to_ata.to_account_info(),
authority: ctx.accounts.authority.to_account_info(),
},
),
amount,
)?;- A autoridade deve assinar ou ser PDA com with_signer
- As contas de token devem ser mut
- Inclua Program<Token> nas contas
3. with_signer para autoridade PDA
PDAs assinam CPIs através de fatias de sementes.
let seeds = &[b"vault".as_ref(), &[ctx.bumps.vault]];
let signer = &[&seeds[..]];
token::transfer(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
accounts,
signer,
),
amount,
)?;- As sementes devem corresponder às restrições do PDA
- Use ctx.bumps quando disponível
- A conta de autoridade é o PDA
4. CpiContext com signer
Adicione sementes a um contexto existente com .with_signer.
let cpi_ctx = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
transfer_accounts,
);
token::transfer(cpi_ctx.with_signer(signer), amount)?;- Útil quando as sementes do signatário são computadas condicionalmente
- Mesmas semânticas de new_with_signer
- Prefira um estilo por base de código
5. Incluir contas de programa
Fixe os IDs de programa CPI na struct de contas.
pub token_program: Program<'info, Token>,
pub system_program: Program<'info, System>,- Previne ataques de substituição de programa
- Necessário para os helpers CPI do Anchor
- Use Interface para Token-2022
Exemplos Intermediários
6. declare_program! Módulo CPI
Anchor 0.32 gera clientes CPI a partir de IDL externa.
// lib.rs
declare_program!(other_program);
pub fn call_other(ctx: Context<CallOther>) -> Result<()> {
other_program::cpi::do_something(
CpiContext::new(
ctx.accounts.other_program.to_account_info(),
other_program::cpi::accounts::DoSomething { /* ... */ },
),
)?;
Ok(())
}- Coloque o JSON da IDL no workspace para declare_program!
- Módulo gerado em cpi::
- Structs de contas type-safe para CPI
Relacionado: CPI para Programas Personalizados
7. CpiContext contas restantes
Encaminha contas extras para o alvo da CPI.
let mut cpi_ctx = CpiContext::new(program, accounts);
cpi_ctx = cpi_ctx.with_remaining_accounts(ctx.remaining_accounts.to_vec());
other_program::cpi::advanced(cpi_ctx)?;- O programa alvo deve esperar extras
- Valide antes de encaminhar
- A ordem deve corresponder ao chamado
Relacionado: Passando Contas Restantes
8. Propagação de Erros
Falhas de CPI retornam como ProgramError no chamador.
token::transfer(cpi_ctx, amount)
.map_err(|_| MyError::TransferFailed)?;- Mapeie erros opacos para #[error_code] personalizado
- Registre antes de retornar para depuração
- Simule transações para ver erros internos
Versões da Pilha: Esta página foi escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, e LiteSVM 0.6.x.