Skip to main content
本页内容由 AI 自动翻译,所有内容以英文版本为准。查看英文版 →
CPMM 的程序 ID 和 PDA 种子在 reference/program-addresses 中规范列出。本页重点介绍每个账户的用途和它维护的不变量,而不是硬编码的地址。

CPMM 池的六个账户

每个 CPMM 池由 CPMM 程序下的六个程序派生地址(PDA)完全描述,加上它引用的一个共享 AmmConfig 账户。一旦你有了两个 mint,你可以确定性地推导出所有内容,无需接触网络。 以及共享配置:

仅从两个 mint 推导池

推导池 PDA 前始终对 mint 进行排序。 种子按字节顺序对两个 mint 进行哈希,而不是按用户顺序。具有 (A, B)(B, A) 的两个池会在链上发生碰撞——排序是程序使映射规范化的方式。
池 ID 并不总是规范 PDA。 Initialize 除了上面的 PDA 外,还接受任意签名者密钥对作为 pool_state。如果传递的账户与规范 PDA 不匹配,程序要求它是签名者——即创建者传递一个他们用其签名的新密钥对。这是前置运行防御:任何竞速抢占规范 PDA 的第三方都可以被合法创建者使用随机密钥对绕过。下游 PDA(lpMintvault0vault1observation)仍然从 poolState.key() 派生,因此它们对使用的任何地址保持唯一。索引池时,始终从链上状态发现池 ID(例如,CPMM 程序下的 PoolState 账户),而不是通过推导规范 PDA——后者会遗漏随机密钥对池。

账户布局

完整的 Rust 定义位于 raydium-cp-swap 源代码中。下面的字段是你在集成中会读取的字段。

PoolState

实际要读取的内容:
  • lp_supply ——池对 LP mint 总供应量的内部镜像。用于 LP 份额数学;该值应与 mint 的链上供应量匹配,但从 PoolState 读取它可以避免额外的账户获取。
  • protocol_fees_token{0,1}fund_fees_token{0,1} ——累积的费用尚未扫除。这些不影响交换定价;它们位于金库中,直到调用 CollectProtocolFee / CollectFundFee
  • status ——一个位掩码,控制是否允许 SwapDepositWithdraw。由管理员通过 UpdatePoolStatus 更新。SDK 在构建交易前检查这个;如果你直接进行 CPI,自己检查。
  • token0_program / token1_program ——为每个金库进行 CPI 的代币程序。一个可以是经典 SPL Token,另一个是 Token-2022;它们是独立的。
  • open_time ——Unix 时间戳。此时间之前的交换失败。open_time 之前允许存款,以便可以对池进行种子处理。
  • creator_fee_on / enable_creator_fee ——共同控制此池是否激活可选创建者费用以及从交换的哪一侧收取。enable_creator_fee == false 完全清零创建者费用路径。启用时,creator_fee_on 选择:0 = 从交换输入的任何代币收取费用(BothToken);1 = 仅从 token_0 收取费用(跳过 token_1 → token_0 交换);2 = 仅从 token_1 收取费用。在池创建时通过 InitializeWithPermission 设置;之后无法更改。
  • creator_fees_token_{0,1} ——累积的创建者费用,由 CollectCreatorFeeCollectCreatorFeePermissionless 扫除。两条路径都清零完整计数器;无权限路径将收件人固定为 pool_creator 的规范 ATA。

AmmConfig

需要注意三件事:
  1. trade_fee_ratecreator_fee_rate 是交易量的分数,两者都以 1/1_000_000 单位表示。2500 表示交易量的 0.25%。protocol_fee_ratefund_fee_rate交易费用的分数(不是交易量),使用相同的 1/1_000_000 分母。创建者费用不是交易费用的分数——它是自己独立的费率。完整算术在 products/cpmm/fees 中。
  2. indexu16,所以种子哈希使用 2 字节大端序。字节顺序偏差一是常见的集成错误。
  3. AmmConfig 在池级别是不可变的。 池在创建时指向一个 AmmConfig,之后永不切换。费用变化会传播,因为池在每次交换时读取配置——但池无法在费用等级之间移动。
关于创建者费用的说明:费率本身creator_fee_rate)位于 AmmConfig 上,在费用等级中共享。特定池是否实际收取它(enable_creator_fee)以及它在交换的哪一侧(creator_fee_on)位于 PoolState 上。创建者费用独立于交易费用——它是自己的费率,累积到自己的计数器(creator_fees_token_{0,1}),永远不会减少 LP / 协议 / 基金对交易费用的份额。扫除通过 CollectCreatorFee 或目标受限的 CollectCreatorFeePermissionless。完整机制见 products/cpmm/fees

Permission

InitializeWithPermission 使用的小型访问控制账户。CPMM 程序支持一个有权限的池创建路径,以便其他程序(例如 LaunchLab 在将代币升级到 CPMM 时)可以证明他们有权针对给定的 AmmConfig 创建池。
Permission PDA 由 CPMM 管理员或专用权限 PDA 创建者权限通过 CreatePermissionPda 创建。自 2026-09 升级以来,ClosePermissionPda 接受相同的两个签名者;之前仅限管理员。最终用户不直接与此账户交互——它是跨程序流的管道。有关角色边界,见 security/admin-and-multisig;有关规范地址,见 reference/program-addresses

金库和 Token-2022

vault0vault1 由 CPMM authority PDA 拥有,其代币程序所有者(token_program)是 SPL Token 或 Token-2022,在池创建时由 mint 的程序确定。池透明地处理两种情况——你在 Swap / Deposit / Withdraw 指令账户中为每一侧传递正确的代币程序 ID。 CPMM 在池创建时强制执行严格的扩展允许列表utils/token.rs 中的 is_supported_mint)。Token-2022 mint 只有在它携带的每个扩展都在此列表中时,才能在 CPMM 池中使用:
  • TransferFeeConfig 由 mint 在每次转账时应用。对于 SwapBaseInput 存款,池在接收端;对于提取,在发送端。程序计算登陆金库的金额并相应设置曲线。见 algorithms/token-2022-transfer-fees
  • MetadataPointerTokenMetadata 标准链上 mint 元数据。对交换数学无影响。
  • InterestBearingConfig mint 的 UI 金额累积利息。金库存储原始金额;曲线仅对原始金额操作。显示 APR 的 UI 应调用 Token-2022 助手来呈现 UI 金额。
  • ScaledUiAmount UI 显示缩放扩展。与 InterestBearingConfig 相同的处理——曲线使用原始金额。
任何其他扩展——PermanentDelegateTransferHookDefaultAccountStateNonTransferableConfidentialTransferGroup/GroupMemberMintCloseAuthority 等——导致 InitializeNotSupportMint 拒绝。一个例外是每个 mint 注册表:如果在种子 [b"support_mint", mint] 处存在 SupportMintAssociated PDA,则无论其扩展集如何,都允许该 mint。该 PDA 由管理员(或专用支持 mint 权限)通过 CreateSupportMintAssociated / CloseSupportMintAssociated 创建和删除,因此载入特定 mint 不再需要程序升级。
在 2026-09 中更改。 CPMM 之前还携带一个硬编码的四地址 MINT_WHITELIST,它绕过了扩展检查。该数组已删除;注册表 PDA 现在是唯一的绕过。任何依赖硬编码列表的 mint 在创建新池之前需要 SupportMintAssociated PDA——现有池不受影响,因为检查仅在池创建时运行。
经过审查的扩展列表位于 CP-Swap 源代码中的 programs/cp-swap/src/utils/token.rs 下,可能会随着未来的程序升级而更改。跨程序矩阵见 reference/token-2022-support

观察

观察账户是 ObservationState 条目的环形缓冲区,每个条目存储一个 block_timestamp 和一个累积价格。在每次交换时,如果自上次以来已经过了足够的时间,程序会追加一个新观察。TWAP 通过读取两个观察并除以 Δcumulative / Δtime 来计算。
环形缓冲区的大小为100 个观察。每个观察 40 字节,所以数组本身 4,000 字节;完整的 ObservationState PDA 在周围字段和判别器后约 4,100 字节。 两个消费者规则:
  • 不要将单个观察用作价格。 它是累积,不是现货价格。使用其中两个来计算 TWAP。
  • 选择至少相隔一个区块的观察。 同一区块内的交换可能不会产生新观察;读取连续的可能返回相同记录。
更多数学见 products/clmm/accounts

账户生命周期

CPMM 池及其 PDA 永远不会关闭。即使在零流动性时,poolState 仍然存在。这是有意的:稍后重新种子相同的池会保留其历史观察缓冲区,其 PDA 推导保持稳定。

在哪里读取什么

来源: