Skip to main content
本页内容由 AI 自动翻译,所有内容以英文版本为准。查看英文版 →
版本说明。 所有 TypeScript 示例针对 @raydium-io/raydium-sdk-v2@0.2.64-alpha;最后在 0.2.42-alpha(2026-04)上执行,并在 2026-09-09 针对 Solana mainnet-beta 的 0.2.64-alpha 源代码重新检查了调用签名。末尾的 Rust CPI 框架针对 master 分支上的 raydium-clmm,其中固定 Anchor =0.32.1不是 CPMM 页面使用的 1.0.2;两者不能在一个 crate 中共存。程序 ID 来自 reference/program-addresses 通过 SDK。

设置

本页的每个示例都对应 raydium-sdk-V2-demo/src/clmm 中的一个文件;GitHub 链接位于每个部分旁边。引导程序遵循演示仓库的 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 数组并将其作为账户传递。它不需要捆绑任何初始化指令 — 没有初始化 tick 数组指令;OpenPosition* 会自行分配缺失的 tick 数组,费用由支付者承担。

增加现有头寸的流动性

源代码:src/clmm/increaseLiquidity.ts

减少流动性(同时收取费用)

源代码:src/clmm/decreaseLiquidity.tssrc/clmm/closePosition.ts
仅收取费用和奖励,使用 liquidity = new BN(0) 调用 decreaseLiquidity。指令的副作用是结算 token_fees_owed_{0,1}reward_amount_owed 并将其转出 — 这是收取任一者的唯一方式。 要在清零流动性和费用后完全关闭头寸,在最后的 decreaseLiquidity 调用上传递 ownerInfo: { closePosition: true }。SDK 会追加 ClosePosition 并销毁 NFT。
受限发行人头寸需要兼容的关闭构建器。 这些头寸有冻结的 NFT 代币账户。ClosePosition 必须将头寸的池 ID 作为第一个剩余账户追加,以便 CLMM 在销毁前解冻账户。程序源分支不包括 SDK 更改。在启用受限发行人头寸创建之前,确认你的 SDK 版本明确支持冻结关闭路径。
对于直接 Anchor 客户端,保持声明的账户不变并追加池:
你可以在每次关闭时传递 poolId。CLMM 仅在 positionNftAccount 冻结时读取它,这使一个客户端路径与旧头寸和新头寸兼容。

收取奖励

源代码:src/clmm/harvestAllRewards.ts
harvestAllRewards 遍历传入的每个池上的每个头寸,批处理零流动性 DecreaseLiquidity 调用以结算费用和奖励(加上任何 UpdateRewardInfos),并在需要时将其分散到多个交易中。

交换

源代码:src/clmm/swap.ts
模拟使用与链上程序相同的逻辑离线遍历 tick 映射,并返回输出量(amountCalculated)加上交换将触及的确切账户列表(accounts)。 始终传递模拟返回的 remainingAccounts:太少会导致交换在中途以 NotEnoughTickArrayAccount 回滚;过时的只是浪费计算。
PoolUtils.computeAmountOutFormat 仍然存在,但它需要 ComputeClmmPoolInfo(来自 getPoolInfoFromRpccomputePoolInfo,不是 API 池对象)加上两个更多必需的参数 — tickarrayBitmapExtensionblockTimestamp — 并且没有 raydium.clmm.fetchTickArrays 方法(fetchTickArrays 是自由函数;模块级助手是 PoolUtils.fetchMultiplePoolTickArraysgetPoolInfoFromRpc 返回的 tickData / tickArrays)。

创建可定制的 CLMM 池

createCustomizablePool 是入口点,在池创建时公开动态费用和单边费用切换。它采用 createPool 的形状加上两个补充:
没有 enableDynamicFee 和没有 dynamicFeeConfigId 参数,也没有 startTime提供 dynamicFeeConfig 是启用动态费用的方式 — 省略它,你会得到一个静态费用池,没有错误。还要注意 SDK 枚举成员是 TokenOnlyA / TokenOnlyB,而链上 Rust 枚举拼写为 Token0Only / Token1Only;数值匹配(FromInput = 0)。
createPool 继续用于默认费用、无动态费用路径。每当你需要任一旋钮时使用 createCustomizablePool。有关链上账户列表,见 products/clmm/instructions

限价单

限价单在单个 tick 处停泊用户输入,当交换穿过该 tick 时按 FIFO 填充。输出在结算时推送到所有者的 ATA;所有者不需要在线即可被填充。

开启限价单

SDK 从 (owner, nonce PDA, order nonce) 推导 LimitOrderState PDA,碰撞每个钱包的 LimitOrderNonce,并将订单插入该 tick 处的 FIFO 队列。

增加/减少开放订单

decreaseLimitOrder 只能从订单的未填充部分移除;填充部分被锁定直到结算。如果订单已完全填充,两个指令都会以 InvalidOrderPhase 回滚。

结算已填充的订单

settleLimitOrder 根据队列跟踪器读取订单的 unfilled_ratio_x64,计算填充输出,并将其转移到所有者的 ATA。所有者可以自己调用此方法;limit_order_admin(离线操作保管人)也可以代表所有者调用它 — 输出仍然进入所有者。 要关闭完全结算的订单以恢复租金,使用 closeLimitOrder(单个)或 closeAllLimitOrder(批处理)。要一次结算许多,settleAllLimitOrder 将尽可能多的 SettleLimitOrder 调用打包到 v0 tx 中。

列出钱包的停泊订单(离线)

活跃订单端点在一个有效负载中返回未填充和部分填充的订单(totalAmount / filledAmount / pendingSettle 区分阶段)。对于已关闭订单历史,使用 /limit-order/history/order/list-by-user?wallet=…(按钱包,按 nextPageId 分页);对于特定订单的完整事件日志,使用 /limit-order/history/event/list-by-pda?pda=…

Rust CPI 框架

SwapV2 的剩余账户顺序:
如果交换永远不需要扩展,省略它;否则它是第一个剩余账户。

常见陷阱

  • 非间距 tick 端点TickAndSpacingNotMatch。始终通过 TickUtil.getPriceAndTick(单数 TickUtil)对齐。
  • SwapV2 中提供的 tick 数组不足NotEnoughTickArrayAccount。从 swapInternal(...).accounts 获取列表。
  • 没有位图扩展的全范围头寸 → 扩展 PDA 必须可写;SDK 自动处理此问题。
  • sqrt_price_x64price 混淆 → 这里的因子 2 混淆特别痛苦。如有疑问,让 SDK 从人类可读的价格计算它。
  • 过于急切地收取奖励 → 每次收取都是零流动性 DecreaseLiquidity,成本一个交易。通过 harvestAllRewards 跨许多头寸批处理,并记住其 execute 需要 { sequentially: true }
  • 自己关闭 NFT 账户ClosePosition 销毁 NFT 并关闭其 ATA。它也关闭 Token-2022 NFT 铸币;经典 SPL Token 铸币保持供应零,因为该程序无法关闭铸币。不要单独关闭支持的账户,否则指令将回滚。
  • 在非间距 tick 处开启限价单TickAndSpacingNotMatch。始终通过导出的 getOrderTick 助手量化。
  • 在完全填充的订单上调用 decreaseLimitOrderInvalidOrderPhase。改用 settleLimitOrder 然后 closeLimitOrder
  • 期望 enableDynamicFee 标志 → 没有。省略 dynamicFeeConfig 只是创建一个静态费用池,无声且无错误。如果你想要动态费用,传递从 /main/clmm-dynamic-config 选择的配置账户的 PublicKey

接下来去哪里

来源: