Skip to main content
Banner de versão. Todas as demos em TypeScript têm como alvo @raydium-io/raydium-sdk-v2@0.2.64-alpha; elas foram executadas pela última vez com 0.2.42-alpha (2026-04), e as assinaturas de chamada foram verificadas novamente contra o código-fonte de 0.2.64-alpha em 2026-09-09, na mainnet-beta da Solana. O esqueleto de CPI em Rust no final tem como alvo raydium-clmm na branch master, com Anchor 1.0.2, a mesma versão fixada da página do CPMM, para que as duas possam coexistir no mesmo crate. Os IDs dos programas vêm de reference/program-addresses por meio do SDK.

Configuração

Cada demo desta página espelha um arquivo em raydium-sdk-V2-demo/src/clmm; o link do GitHub fica ao lado de cada seção. A inicialização segue o config.ts.template do repositório de demos (fonte). Para qualquer integração não trivial, recomenda-se disableFeatureCheck: true:

Criar um pool CLMM

Fonte: src/clmm/createPool.ts
O SDK:
  • Ordena mint1/mint2 pela ordem dos bytes antes da derivação.
  • Calcula sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64).
  • Cria as contas observation e tick_array_bitmap_extension.
  • Paga a taxa de criação do pool definida por ammConfig.

Abrir uma posição em um intervalo escolhido

Fonte: src/clmm/createPosition.ts
O SDK calcula quais tick arrays o intervalo atinge e os passa como contas. Não é necessário incluir nenhuma instrução de inicialização — não existe instrução de init-tick-array; OpenPosition* aloca sozinha um tick array que esteja faltando, às custas do pagador.

Aumentar a liquidez de uma posição existente

Fonte: src/clmm/increaseLiquidity.ts

Reduzir a liquidez (e coletar taxas ao mesmo tempo)

Fonte: src/clmm/decreaseLiquidity.ts e src/clmm/closePosition.ts
Para coletar somente taxas e recompensas, chame decreaseLiquidity com liquidity = new BN(0). O efeito colateral da instrução é liquidar token_fees_owed_{0,1} e reward_amount_owed e transferi-los para fora — esta é a única forma de coletar qualquer um dos dois. Para fechar a posição por completo depois de zerar a liquidez e as taxas, passe ownerInfo: { closePosition: true } na última chamada de decreaseLiquidity. O SDK adiciona ClosePosition e queima o NFT.
Posições de emissor restrito exigem um builder de fechamento compatível. Essas posições têm uma conta de token NFT congelada. ClosePosition deve anexar o ID do pool de posição como a primeira conta remanescente, para que a CLMM possa descongelar a conta antes de queimá-la. O branch do código-fonte do programa não inclui nenhuma alteração no SDK. Confirme que a sua versão do SDK oferece suporte explícito ao caminho de fechamento de conta congelada antes de habilitar a criação de posições de emissor restrito.
Para um cliente Anchor direto, mantenha as contas declaradas inalteradas e anexe o pool:
Você pode passar poolId em todo fechamento. A CLMM só o lê quando positionNftAccount estiver congelada, o que mantém um único caminho no cliente compatível com posições antigas e novas.

Coletar recompensa(s)

Fonte: src/clmm/harvestAllRewards.ts
harvestAllRewards percorre cada posição de cada pool recebido, agrupa as chamadas DecreaseLiquidity de liquidez zero que liquidam taxas e recompensas (além de eventuais UpdateRewardInfos) e as divide entre transações quando necessário.

Swap

Fonte: src/clmm/swap.ts Este exemplo espelha src/clmm/swap.ts, que simula a operação com swapInternal em vez de PoolUtils.computeAmountOutFormat.
A simulação percorre o mapa de ticks off-chain, com a mesma lógica do programa on-chain, e retorna o valor de saída (amountCalculated) junto com a lista exata de contas que a swap vai acessar (accounts). Sempre passe o remainingAccounts retornado pela simulação: se faltarem contas, a swap é revertida no meio do percurso com NotEnoughTickArrayAccount; se forem contas desatualizadas, você só desperdiça compute.
PoolUtils.computeAmountOutFormat ainda existe, mas exige um ComputeClmmPoolInfo (o computePoolInfo retornado por getPoolInfoFromRpc, e não um objeto de pool da API), além de dois argumentos obrigatórios a mais — tickarrayBitmapExtension e blockTimestamp. Além disso, não existe o método raydium.clmm.fetchTickArrays (fetchTickArrays é uma função independente; os auxiliares no nível do módulo são PoolUtils.fetchMultiplePoolTickArrays e o tickData / tickArrays retornados por getPoolInfoFromRpc).

Criar um pool CLMM personalizável

createCustomizablePool é o ponto de entrada que expõe as opções de taxa dinâmica e de taxa de lado único no momento da criação do pool. Ele recebe a mesma estrutura de createPool, com dois campos adicionais:
Não existe um parâmetro enableDynamicFee, nem dynamicFeeConfigId, nem startTime. Fornecer dynamicFeeConfig é o que habilita as taxas dinâmicas — se você omiti-lo, obtém um pool com taxa estática, sem nenhum erro. Observe também que os membros do enum no SDK são TokenOnlyA / TokenOnlyB, enquanto o enum Rust on-chain os escreve como Token0Only / Token1Only; os valores numéricos são os mesmos (FromInput = 0).
createPool continua funcionando para o caminho de taxa padrão, sem taxa dinâmica. Use createCustomizablePool sempre que precisar de qualquer uma dessas opções. Para a lista de contas on-chain, consulte /pt/products/clmm/instructions.

Ordens limitadas

Uma ordem limitada deposita o valor do usuário em um único tick e é preenchida em FIFO quando uma swap atravessa esse tick. Os valores de saída são enviados para o ATA do dono no momento da liquidação; o dono não precisa estar online para que a ordem seja preenchida.

Abrir uma ordem limitada

Não existe uma conta de configuração de ordens limitadas por pool, nem um auxiliar getClmmLimitOrderConfigs() — as ordens são identificadas pelo tick.
O SDK deriva a PDA de LimitOrderState a partir de (owner, nonce PDA, order nonce), incrementa o LimitOrderNonce da carteira e insere a ordem na coorte FIFO daquele tick.

Aumentar / reduzir uma ordem aberta

decreaseLimitOrder só pode remover a parte não preenchida da ordem; a parte preenchida fica bloqueada até a liquidação. Ambas as instruções são revertidas com InvalidOrderPhase se a ordem já tiver sido totalmente preenchida.

Liquidar uma ordem preenchida

settleLimitOrder lê o unfilled_ratio_x64 da ordem em relação ao rastreador da coorte, calcula a saída preenchida e a transfere para o ATA do dono. O próprio dono pode chamar essa função; o limit_order_admin (um keeper operacional off-chain) também pode chamá-la em nome do dono — a saída continua indo para o dono. Para fechar ordens totalmente liquidadas e recuperar o rent, use closeLimitOrder (uma por vez) ou closeAllLimitOrder (em lote). Para liquidar várias ordens de uma vez, settleAllLimitOrder agrupa quantas chamadas de SettleLimitOrder couberem em uma transação v0.

Listar as ordens ativas de uma carteira (off-chain)

O endpoint de ordens ativas retorna, em um único payload, ordens não preenchidas e parcialmente preenchidas (totalAmount / filledAmount / pendingSettle distinguem as fases). Para o histórico de ordens fechadas, use /limit-order/history/order/list-by-user?wallet=… (por carteira, paginado por nextPageId); para o log completo de eventos de uma ordem específica, use /limit-order/history/event/list-by-pda?pda=….

Esqueleto de CPI em Rust

Ordem das contas restantes (remaining accounts) para SwapV2:
Se a swap nunca precisar da extensão, omita-a; caso contrário, ela é a primeira conta restante.

Armadilhas comuns

  • Extremos de tick fora do espaçamento → TickAndSpacingNotMatch. Sempre ajuste os valores com TickUtil.getPriceAndTick (no singular, TickUtil).
  • Não fornecer tick arrays suficientes no SwapV2 → NotEnoughTickArrayAccount. Obtenha a lista a partir de swapInternal(...).accounts.
  • Posição de faixa total sem a extensão do bitmap → a PDA da extensão precisa ser gravável; o SDK faz isso automaticamente.
  • Confundir sqrt_price_x64 com price → um erro de fator 2 aqui é especialmente problemático. Na dúvida, deixe o SDK calcular o valor a partir de um preço legível.
  • Coletar recompensas com frequência excessiva → cada coleta é um DecreaseLiquidity com liquidez zero e custa uma transação. Agrupe as coletas com harvestAllRewards em várias posições e lembre-se de que o execute dela precisa de { sequentially: true }.
  • Fechar as contas de NFT manualmente → ClosePosition queima o NFT e fecha seu ATA. Ele também fecha um mint de NFT Token-2022; já um mint do SPL Token clássico permanece com supply zero, pois esse programa não consegue fechar mints. Não feche as contas suportadas separadamente, ou a instrução será revertida.
  • Abrir uma ordem limite em um tick fora do espaçamento → TickAndSpacingNotMatch. Sempre quantize o valor com o helper exportado getOrderTick.
  • Chamar decreaseLimitOrder em uma ordem totalmente preenchida → InvalidOrderPhase. Use settleLimitOrder e, em seguida, closeLimitOrder.
  • Esperar uma flag enableDynamicFee → ela não existe. Omitir dynamicFeeConfig simplesmente cria um pool de taxa estática, sem aviso e sem erro. Se você quiser taxas dinâmicas, passe o PublicKey da conta de configuração, escolhido em /pt/main/clmm-dynamic-config.

Próximos passos

Fontes: