Noções Básicas de CPI
10 exemplos para você começar com CPIs - 7 básicos e 3 intermediários.
Pré-requisitos
- Familiaridade com o entrypoint do programa nativo.
- Ordenação de metadados de conta de Trabalhando com Pubkeys.
Exemplos Básicos
1. Invoke Simples
Chame a transferência do System Program do seu programa.
use solana_program::program::invoke;
use solana_program::system_instruction;
invoke(
&system_instruction::transfer(from.key, to.key, lamports),
&[from.clone(), to.clone()],
)?;- O ID do programa callee está embutido na Instruction.
- As contas devem corresponder às expectativas do callee.
- Retorne
?para propagar erros de CPI.
2. Struct Instruction
Construa Instruction com ID do programa, contas e dados.
use solana_program::instruction::{AccountMeta, Instruction};
let ix = Instruction {
program_id: token_program.key(),
accounts: vec![/* AccountMeta */],
data: vec![/* opcode */],
};- O layout dos dados deve corresponder ao programa callee.
- Prefira crates auxiliares (
spl-token) para codificação. - ID do programa errado = IncorrectProgramId.
3. Clonar AccountInfo
Invoke precisa de referências owned de AccountInfo em um slice.
&[payer.clone(), vault.clone(), system_program.clone()]cloneem AccountInfo é uma clonagem de referência barata.- A ordem corresponde à ordem de AccountMeta.
- Inclua contas de programa como readonly, a menos que writable seja necessário.
4. Propagação de Erro de CPI
CPI falho falha sua instrução.
invoke(&ix, accounts).map_err(|e| {
solana_program::msg!("cpi failed");
e
})?;- Toda a transação é revertida em caso de erro de CPI.
- Mapeie erros se precisar de códigos personalizados.
- Logs podem incluir erros do programa callee.
5. Conta de Programa em CPI
Passe a conta do programa de token/sistema como readonly.
let system_program = next_account_info(iter)?;
if system_program.key != &system_program::ID {
return Err(ProgramError::IncorrectProgramId);
}- Valide os IDs dos programas antes do invoke.
- Contas executáveis são contas de programa.
- Nunca passe o ID do programa errado.
6. Requisitos de Signer
CPI não pode adicionar assinaturas que as carteiras não forneceram.
if !payer.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}- Exceção: PDAs via
invoke_signed. - Débito do usuário requer que o usuário seja signer.
- Débito de PDA requer seeds do programa.
7. CPI Read-only
Algumas CPIs apenas leem o estado do callee.
// e.g. reading oracle - still passes accounts- O flag Writable deve ser false se não estiver mutando.
- Metas sobrescritas são achados de auditoria.
- Siga a documentação da interface do callee.
Exemplos Intermediários
8. invoke_signed para PDA
O programa assina CPI em nome do PDA.
invoke_signed(&ix, accounts, &[&[b"vault", &[bump]]])?;- As seeds devem corresponder à derivação do PDA.
- Necessário para PDAs de autoridade de token.
- Veja a página invoke vs invoke_signed.
Relacionado: invoke vs invoke_signed
9. Transferência de Token SPL via CPI
Transfira tokens com o programa de token.
use spl_token::instruction as token_ix;
let ix = token_ix::transfer(
token_program.key,
source.key,
dest.key,
authority.key,
&[],
amount,
)?;
invoke(&ix, &[source.clone(), dest.clone(), authority.clone(), token_program.clone()])?;- A autoridade deve assinar ou ser um PDA com invoke_signed.
- Valide a correspondência de mint entre as contas.
- Use matemática de quantidade verificada antes da CPI.
Relacionado: CPI para SPL Token
10. Consciência de Profundidade de CPI
CPIs podem chamar programas que fazem CPI novamente - profundidade máxima de 4.
// Seu programa -> Token -> ... orçamento de profundidade- Cadeias profundas custam CUs.
- Projete grafos de CPI planos sempre que possível.
- Veja Profundidade e Limites de CPI.
Relacionado: Profundidade e Limites de CPI
Versões da Stack: 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.