本页内容由 AI 自动翻译,所有内容以英文版本为准。查看英文版 →
CPMM 的程序 ID 和 PDA 种子列在
reference/program-addresses 中。本页重点介绍每个账户的用途和它维护的不变量,而不是硬编码的地址。CPMM 池的六个账户
每个 CPMM 池由 CPMM 程序下的六个程序派生地址(PDA)完全描述,加上它引用的一个共享AmmConfig 账户。一旦你有两个 mint,就可以不接触网络直接确定性地派生所有内容。
以及共享配置:
仅从两个 mint 派生池
池 ID 并不总是规范 PDA。
Initialize 除了上面的 PDA 外,还接受任意签署者密钥对作为 pool_state。如果传递的账户与规范 PDA 不匹配,程序要求它是签署者——即创建者传递一个他们用签名的新密钥对。这是前置攻击防御:任何第三方竞速抢占规范 PDA 都可以被合法创建者使用随机密钥对绕过。下游 PDA(lpMint、vault0、vault1、observation)仍从 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—— 控制是否允许Swap、Deposit、Withdraw的位掩码。由管理员通过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}—— 累计的创建者费用,由CollectCreatorFee清扫。
AmmConfig
trade_fee_rate和creator_fee_rate是交易量的分数,两者都用1/1_000_000的单位表示。2500表示交易量的 0.25%。protocol_fee_rate和fund_fee_rate是交易费的分数(不是交易量),使用相同的1/1_000_000分母。创建者费用不是交易费的分数——它是自己独立的费率。完整算术在products/cpmm/fees中。index是u16,所以种子哈希使用 2 字节大端序。字节顺序偏差一是常见的集成错误。- **
AmmConfig在池级别是不可变的。**池在创建时指向一个AmmConfig,不会切换。费用更改会传播,因为池在每次交换时读取配置——但池不能在费用等级之间移动。
creator_fee_rate)位于 AmmConfig 上,在费用等级之间共享。特定池是否真的收费(enable_creator_fee)以及它在交换的哪一侧(creator_fee_on)位于 PoolState 上。创建者费用独立于交易费——它是自己的费率,累计到自己的计数器(creator_fees_token_{0,1}),从不减少 LP / 协议 / 基金在交易费中的份额。清扫通过 CollectCreatorFee。有关完整机制,请参阅 products/cpmm/fees。
Permission
由 InitializeWithPermission 使用的小型访问控制账户。CPMM 程序支持一个许可池创建路径,以便其他程序(例如 LaunchLab 当将代币升级为 CPMM 时)可以证明他们有权针对给定 AmmConfig 创建池。
CreatePermissionPda 创建,通过 ClosePermissionPda 撤销。最终用户不直接与此账户交互——它是跨程序流的管道。
金库和 Token-2022
vault0 和 vault1 由 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。- **
MetadataPointer和TokenMetadata。**标准链上 mint 元数据。对交换数学无影响。 InterestBearingConfig。 Mint 的 UI 金额累计利息。金库存储原始金额;曲线仅在原始金额上操作。显示 APR 的 UI 应调用 Token-2022 辅助程序来呈现 UI 金额。ScaledUiAmount。 UI 显示缩放扩展。与InterestBearingConfig相同的处理——曲线使用原始金额。
PermanentDelegate、TransferHook、DefaultAccountState、NonTransferable、ConfidentialTransfer、Group/GroupMember、MintCloseAuthority 等——导致 Initialize 以 NotSupportMint 拒绝。例外是程序中的小型硬编码 mint 白名单(少数特定公钥),绕过扩展检查;它用于逐个批准特定 mint。
经过审查的扩展列表和 mint 白名单位于 CP-Swap 源的 programs/cp-swap/src/utils/token.rs 下,可能会通过未来的程序升级更改。
观测
观测账户是ObservationState 条目的环形缓冲区,每个条目存储 block_timestamp 和累积价格。在每次交换时,如果自上次以来足够的时间已过,程序会追加新的观测。TWAP 通过读取两个观测并除以 Δcumulative / Δtime 计算。
ObservationState PDA 在周围字段和鉴别器之后约 4100 字节。
两个消费者规则:
- **不要将单个观测用作价格。**它是累积,不是现货价格。使用其中两个来计算 TWAP。
- **选择相隔至少一个区块的观测。**同一区块内的交换可能不会产生新的观测;逐个读取可能会返回相同的记录。
products/clmm/accounts 中。
账户生命周期
CPMM 池及其 PDA 从不关闭。即使在零流动性时,
poolState 仍然存在。这是故意的:稍后重新投入相同的池保留其历史观测缓冲区,其 PDA 派生保持稳定。
在哪里读取什么
- 指令账户列表(上述每个指令的可写/签署者):
products/cpmm/instructions。 - 费用累计语义:
products/cpmm/fees。 - 交换数学 / 观测更新规则:
products/cpmm/math。 - 规范种子 / 程序 ID:
reference/program-addresses。

