Skip to main content
本页内容由 AI 自动翻译,所有内容以英文版本为准。查看英文版 →
版本说明。 所有示例均基于 @raydium-io/raydium-sdk-v2@0.2.42-alpha,针对 Solana mainnet-beta 环境,验证时间为 2026 年 4 月。Program ID 通过 SDK 从 reference/program-addresses 获取。

初始化配置

本页所有示例均对应 raydium-sdk-V2-demo/src/clmm 目录下的文件,每个章节旁附有对应的 GitHub 链接。初始化方式参照 demo 仓库的 config.ts.template源码)—— disableFeatureCheck: true 是非简单集成场景的推荐配置:

创建 CLMM 流动池

源码:src/clmm/createPool.ts
SDK 内部执行以下操作:
  • 按字节顺序对 mint1/mint2 排序后再进行地址推导。
  • 计算 sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64)
  • 创建 observationtick_array_bitmap_extension 账户。
  • 支付由 ammConfig 定义的建池手续费。

在指定价格区间开仓

源码:src/clmm/createPosition.ts
SDK 会自动计算该区间涉及的 tick array,并在存在未初始化的情况下附加 InitTickArray 指令。

向已有仓位增加流动性

源码:src/clmm/increaseLiquidity.ts

减少流动性(同时领取手续费)

源码:src/clmm/decreaseLiquidity.tssrc/clmm/closePosition.ts
若只想领取手续费,以 liquidity = new BN(0) 调用 decreaseLiquidity 即可。该指令的副作用是结算 tokens_fees_owed_{0,1} 并将其转出。 若要在清零流动性和手续费后彻底关闭仓位,在最后一次 decreaseLiquidity 调用时传入 closePosition: true。SDK 会追加 ClosePosition 指令并销毁 NFT。

领取奖励

源码:src/clmm/harvestAllRewards.ts
harvestAllRewards 会遍历传入的所有流动池中的每个仓位,批量打包 CollectReward(以及 UpdateRewardInfos)指令,必要时拆分为多笔交易提交。

Swap

源码:src/clmm/swap.ts
computeAmountOutFormat 在链下按照与链上程序相同的逻辑遍历 tick map,返回:
  • 预期输出数量,
  • 考虑滑点后的最小输出数量,
  • 实际 swap 将访问的 tick array 账户列表(remainingAccounts)。
务必传入由模拟计算返回的 remainingAccounts:传入过少会在遍历中途触发 TickArrayNotFound 导致回滚;传入过时的账户则会白白消耗计算资源。

创建可定制化 CLMM 流动池

createCustomizablePool 是新的入口方法,支持在建池时启用动态手续费和单侧手续费等参数。其用法与 createPool 基本一致,额外增加三个字段:
对于默认手续费、无限价单、无动态手续费的场景,createPool 仍然适用。只要需要上述三个新参数中的任意一个,请改用 createCustomizablePool。链上账户列表详见 products/clmm/instructions

限价单

限价单将用户的输入锁定在单个 tick,当 swap 穿越该 tick 时按 FIFO 顺序成交。成交后的输出会在结算时推送至持有人的 ATA,持有人无需在线即可被成交。

挂出限价单

SDK 会根据 (pool, owner, tick, nonce) 推导 LimitOrderState PDA,递增对应 (pool, owner)LimitOrderNonce,并将订单插入该 tick 的 FIFO 队列。

增加 / 减少已挂订单的数量

decreaseLimitOrder 只能减少订单的未成交部分;已成交部分在结算前处于锁定状态。若订单已全部成交,两个指令均会以 InvalidOrderPhase 回滚。

结算已成交订单

settleLimitOrder 读取订单的 unfilled_ratio_x64 与队列追踪器进行比较,计算已成交输出并转入持有人的 ATA。持有人可自行调用此指令;链下运营守护进程 limit_order_admin 也可代为调用——输出仍归属于持有人。 如需关闭已完全结算的订单以回收租金,可使用 closeLimitOrder(单笔)或 closeAllLimitOrder(批量)。如需批量结算,settleAllLimitOrder 会将尽可能多的 SettleLimitOrder 调用打包进一笔 v0 交易。

查询钱包的挂单列表(链下)

活跃订单接口在同一响应中返回未成交和部分成交的订单(通过 totalAmount / filledAmount / pendingSettle 区分各阶段)。历史已关闭订单可使用 /limit-order/history/order/list-by-user?wallet=…(按钱包查询,通过 nextPageId 分页);特定订单的完整事件日志可使用 /limit-order/history/event/list-by-pda?pda=…

Rust CPI 骨架代码

SwapV2 的 remaining account 顺序:
如果 swap 不需要 extension,可省略;否则它必须作为第一个 remaining account 传入。

常见问题

  • tick 端点未对齐到 spacingInvalidTickIndex。请始终通过 TickUtils.getPriceAndTick 进行对齐。
  • SwapV2 提供的 tick array 不足TickArrayNotFound。请使用 computeAmountOutFormat 获取完整列表。
  • 全区间仓位未提供 bitmap extension → extension PDA 必须设为可写;SDK 会自动处理此情况。
  • sqrt_price_x64 误用为 price → 此处的 2 倍误差尤为棘手。如有疑虑,请让 SDK 从可读价格自动计算。
  • 过于频繁地领取奖励 → 每次领取需消耗一笔交易。建议通过 harvestAllRewards 跨多个仓位批量领取。
  • 在仍欠 mint 租金时销毁 NFTClosePosition 会同时关闭 NFT mint 和 ATA;请勿单独关闭它们,否则程序会回滚。
  • 在非对齐 tick 处挂限价单InvalidTickIndex。请始终通过 TickUtils.getPriceAndTick 进行量化。
  • 对已全部成交的订单调用 decreaseLimitOrderInvalidOrderPhase。请改用 settleLimitOrder 后再调用 closeLimitOrder
  • 传入 enableDynamicFee: true 时忘记提供 dynamicFeeConfigIdCreateCustomizablePool 会以 InvalidDynamicFeeConfigParams 回滚。请关闭动态手续费,或从 /main/clmm-dynamic-config 中选择一个配置。

后续阅读

参考资料: