Esta página foi traduzida automaticamente por IA. A versão em inglês é a fonte oficial.Ver versão em inglês →
Quando CPI é a ferramenta certa
Um programa customizado faz sentido quando a troca precisa acontecer atomicamente com outras mudanças de estado on-chain que apenas seu programa pode fazer. Casos comuns:- Programas de escrow / ordem limitada — o usuário deposita um mint no seu escrow, seu programa monitora uma condição de preço, e quando dispara, seu programa atomicamente faz swap através do Raydium e credita a conta do usuário.
- Proxies agregadores — uma única instrução que roteia um swap através do Raydium + um ou mais outros DEXes, com todos os hops sob uma única verificação de slippage de propriedade do seu programa.
- Vaults com auto-compounding — deposite tokens LP ou stake de farm no seu vault, o vault colhe recompensas em um cronograma, re-fornece liquidez, emite tokens de participação.
- Vaults de estratégia — posições LP alavancadas que rebalanceiam fazendo swap através de CLMM; liquidadores que fecham posições e fazem swap de colateral em uma transação.
- Plataformas de lançamento de tokens com vesting customizado — seu programa mantém tokens em vesting e libera em um pool Raydium em um cronograma.
Padrões de composição
Padrão 1: Proxy fino
Seu programa expõe uma única instrução que valida alguma política (ex: pares de mint na whitelist, desconto de taxa para usuários verificados) e depois encaminha para o Raydium.Padrão 2: Escrow
Seu programa possui um PDA que mantém o mint de entrada do usuário. No disparo, o PDA assina um CPI para o Raydium fazer swap de seu próprio saldo.CpiContext::new_with_signer. Veja Sementes de signatário PDA.
Padrão 3: Multi-hop composto
Seu programa emite múltiplos CPIs em uma instrução, aplicando um único limite de slippage em todos eles. As instruções de swap do Raydium cada uma têm seu própriominimum_amount_out, mas você define aqueles para 0 (ou um piso muito solto) e aplica um mínimo final rigoroso você mesmo após o último hop.
Padrão 4: Vault / estratégia
Seu programa mantém tokens LP ou stake de farm em um PDA. Um keeper (ou o usuário) chamacompound(), que:
- Colhe recompensas do farm.
- Faz swap de recompensas por tokens de pool (CPI em CPMM ou CLMM).
- Deposita os rendimentos de volta no LP (outro CPI).
- Faz stake do novo LP (outro CPI).
Construção da lista de contas
A structAccounts do programa chamador espelha a ordem de contas do programa Raydium, mas a maioria das contas do lado Raydium são UncheckedAccount porque o Raydium as valida por si mesmo. Você apenas adiciona restrições em contas que você possui:
UncheckedAccount nas do Raydium — não é preguiça. O receptor valida as suas; validar duas vezes no chamador apenas queima CU e corre o risco de ficar fora de sincronização quando o Raydium envia um novo campo de layout de struct.
A chamada CPI em si
Sementes de signatário PDA
O CPI só tem sucesso se o PDA passado comoauthority corresponder à derivação que o chamador afirma. Os dois devem concordar em:
- A sequência de bytes de semente (aqui
[b"escrow", user.key().as_ref()]). - O bump.
- O ID do programa chamador (seu programa, não o do Raydium).
authority do CPMM é seu próprio PDA de vault — uma conta fixa de todo o programa que ele deriva e assina com ele mesmo, e que seu programa nem controla nem substitui. A conta com a qual suas sementes PDA têm que se alinhar é payer: a verificação acontece dentro do helper transfer_from_user_to_pool_vault do próprio CPMM, que requer que a conta passada como payer seja a proprietária de input_token_account.
Bug comum: passar user como payer enquanto escrow_input_ata é de propriedade do PDA de escrow. O programa SPL Token rejeita com owner mismatch. Sempre faça payer ser o proprietário da ATA — e assine por ela com new_with_signer quando esse proprietário é um PDA.
Contas restantes
Várias instruções do Raydium levam uma lista de comprimento variável de contas anexadas após as fixas — contas restantes.- CLMM
SwapV2: 1–8 contasTickArrayStatepara os arrays de tick que o swap pode atravessar, na direção do swap. - Farm v6
Deposit/Harvest/Withdraw: pares(reward_vault, user_reward_ata), um par por slot de recompensa ativo. - Mints de transfer-hook Token-2022: o programa de transfer-hook mais quaisquer contas que o hook precise.
Orçamento de compute para chamadas compostas
Um CPI custa ~1.500 CU para o frame de chamada em si; o uso de CU do chamado se acumula no topo. Os valores do chamado abaixo são medidos de transações mainnet ao vivo em pools de alto volume em 2026-09-09, lidos da linha de logProgram <id> consumed N of M compute units para a própria invocação do programa Raydium (então incluem seus CPIs internos de programa de token):
Adicione ~1.500 para cada frame CPI e a sobrecarga do seu próprio programa no topo. O custo de swap CLMM escala com travessias de tick, então trate seu valor como um piso. Mints Token-2022 adicionam o custo de manipulação de extensão da transferência em si; meça para seus próprios mints em vez de aplicar um multiplicador fixo.
Sempre defina um
ComputeBudgetProgram::set_compute_unit_limit explícito:
Propagação de erro
Os programas do Raydium retornam erros Anchor com códigos estáveis. Seu programa chamador os vê comoErr(ProgramError::Custom(code)). Propague por padrão:
ERROR_CODE_OFFSET: variantes #[error_code] são emitidas começando em 6000, então comparar contra o discriminante de enum nu nunca corresponde. (Não há helper is_err em anchor-lang ou em raydium_cp_swap — revisões anteriores desta página usavam um que não existe.)
O mapeamento de código de erro para significado é estável por política de IDL (sdk-api/anchor-idl); novos códigos se anexam ao final, códigos existentes nunca mudam de significado.
Exemplo completo trabalhado: escrow de ordem limitada
Fluxo:open_order— usuário depositaamount_indeinput_mintno PDA de escrow; registramin_amount_outalvo e expiração.execute_order— qualquer um (keeper) chama com as contas de pool atuais. Programa verifica a cotação atual ≥min_amount_out, depois CPI swap do Raydium e mantém a saída em escrow.claim— usuário retira o mint de saída do escrow.
order assina o CPI como payer, porque possui a ATA de entrada do escrow; ExecuteOrder portanto também precisa de um campo pool_authority: UncheckedAccount<'info> para o próprio PDA de vault do CPMM. Tanto a verificação de slippage do lado Raydium quanto a verificação de delta do próprio escrow aplicam o piso — segurança dupla.
Testes
Puxando programas Raydium para um validador local para testes de integração (deAnchor.toml):
anchor test as busca da mainnet na inicialização. Veja sdk-api/rust-cpi.
Armadilhas específicas de composição
Reentrância
Solana não tem verdadeira reentrância — um CPI não pode chamar de volta para o programa originador na mesma invocação. Mas você ainda pode se construir em uma reentrância lógica: um CPI que lê seu estado, depois seu código o lê novamente assumindo que o CPI não o mudou. Para Raydium, os CPIs não tocam seu estado, então isso é menos uma preocupação do que ex: contextos de flash-loan. Mas se você compor Raydium com um protocolo de empréstimo, esteja ciente.Deriva de mutabilidade de conta
Se seu programa passa uma conta comomut mas Raydium espera apenas leitura (ou vice versa), o runtime rejeita a invocação com InvalidAccountData. Sempre verifique a mutabilidade esperada da instrução do Raydium no IDL; raydium_cp_swap::cpi::accounts::Swap define a mutabilidade de cada conta para você, a partir dos marcadores #[account(mut)] na própria struct Swap do CPMM — os campos derivados são todos AccountInfo<'info> simples, então é a impl ToAccountMetas derivada, não os tipos de campo, que carrega as flags.
Campo de programa Token-2022
Mints de entrada e saída podem estar sob diferentes programas de token — um SPL Token, um Token-2022. O CPI tem camposinput_token_program e output_token_program separados por essa razão. Sempre verifique o campo owner de cada mint e roteia o programa correto em cada slot.
Transações versionadas
Uma tx composta que faz 2+ CPIs Raydium mais uma criação de ATA raramente cabe em uma transação legada (v0-sem-LUT). Use V0 com tabelas de lookup de endereço; puxe LUTs públicas do Raydium viaraydium.getRaydiumLutAddresses().
Ponteiros
sdk-api/rust-cpi— mecânica CPI de baixo nível.integration-guides/priority-fee-tuning— dimensionamento de orçamento de compute.products/cpmm/code-demos,products/clmm/code-demos,products/farm-staking/code-demos— snippets CPI por produto.

