本页内容由 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
- 在推导前按字节顺序排序
mint1/mint2。 - 计算
sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64)。 - 创建
observation和tick_array_bitmap_extension账户。 - 支付由
ammConfig定义的池创建费用。
在选定范围内开仓
源代码:src/clmm/createPosition.ts
OpenPosition* 会自行分配缺失的 tick 数组,费用由支付者承担。
增加现有头寸的流动性
源代码:src/clmm/increaseLiquidity.ts
减少流动性(同时收取费用)
源代码:src/clmm/decreaseLiquidity.ts 和 src/clmm/closePosition.ts
liquidity = new BN(0) 调用 decreaseLiquidity。指令的副作用是结算 token_fees_owed_{0,1} 和 reward_amount_owed 并将其转出 — 这是收取任一者的唯一方式。
要在清零流动性和费用后完全关闭头寸,在最后的 decreaseLiquidity 调用上传递 ownerInfo: { closePosition: true }。SDK 会追加 ClosePosition 并销毁 NFT。
对于直接 Anchor 客户端,保持声明的账户不变并追加池:
poolId。CLMM 仅在 positionNftAccount 冻结时读取它,这使一个客户端路径与旧头寸和新头寸兼容。
收取奖励
源代码:src/clmm/harvestAllRewards.ts
harvestAllRewards 遍历传入的每个池上的每个头寸,批处理零流动性 DecreaseLiquidity 调用以结算费用和奖励(加上任何 UpdateRewardInfos),并在需要时将其分散到多个交易中。
交换
源代码:src/clmm/swap.ts
amountCalculated)加上交换将触及的确切账户列表(accounts)。
始终传递模拟返回的 remainingAccounts:太少会导致交换在中途以 NotEnoughTickArrayAccount 回滚;过时的只是浪费计算。
PoolUtils.computeAmountOutFormat 仍然存在,但它需要 ComputeClmmPoolInfo(来自 getPoolInfoFromRpc 的 computePoolInfo,不是 API 池对象)加上两个更多必需的参数 — tickarrayBitmapExtension 和 blockTimestamp — 并且没有 raydium.clmm.fetchTickArrays 方法(fetchTickArrays 是自由函数;模块级助手是 PoolUtils.fetchMultiplePoolTickArrays 和 getPoolInfoFromRpc 返回的 tickData / tickArrays)。创建可定制的 CLMM 池
createCustomizablePool 是入口点,在池创建时公开动态费用和单边费用切换。它采用 createPool 的形状加上两个补充:
createPool 继续用于默认费用、无动态费用路径。每当你需要任一旋钮时使用 createCustomizablePool。有关链上账户列表,见 products/clmm/instructions。
限价单
限价单在单个 tick 处停泊用户输入,当交换穿过该 tick 时按 FIFO 填充。输出在结算时推送到所有者的 ATA;所有者不需要在线即可被填充。开启限价单
(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_x64与price混淆 → 这里的因子 2 混淆特别痛苦。如有疑问,让 SDK 从人类可读的价格计算它。 - 过于急切地收取奖励 → 每次收取都是零流动性
DecreaseLiquidity,成本一个交易。通过harvestAllRewards跨许多头寸批处理,并记住其execute需要{ sequentially: true }。 - 自己关闭 NFT 账户 →
ClosePosition销毁 NFT 并关闭其 ATA。它也关闭 Token-2022 NFT 铸币;经典 SPL Token 铸币保持供应零,因为该程序无法关闭铸币。不要单独关闭支持的账户,否则指令将回滚。 - 在非间距 tick 处开启限价单 →
TickAndSpacingNotMatch。始终通过导出的getOrderTick助手量化。 - 在完全填充的订单上调用
decreaseLimitOrder→InvalidOrderPhase。改用settleLimitOrder然后closeLimitOrder。 - 期望
enableDynamicFee标志 → 没有。省略dynamicFeeConfig只是创建一个静态费用池,无声且无错误。如果你想要动态费用,传递从/main/clmm-dynamic-config选择的配置账户的PublicKey。
接下来去哪里
sdk-api/typescript-sdk— 完整 SDK 表面。sdk-api/rest-api— 报价和池元数据端点。user-flows/create-clmm-pool— 非代码演练。integration-guides/aggregator— 将 CLMM 作为路径的一部分进行路由。

