本頁內容由 AI 自動翻譯,所有內容以英文版本為準。查看英文版 →
不變量
CPMM 在其兩個金庫上維持經典的常數乘積不變量: 其中x 是金庫 0 的餘額(在收到時扣除任何 Token-2022 轉帳費用之後),y 亦然。每次交換必須在計入分配給 LP 的交易費用後保持 k' ≥ k(協議、基金和創作者的費用桶不計入 k — 它們位於金庫中但被曲線視圖排除,見下方的曲線上的費用)。因此,隨著 LP 累積費用,k 會隨著時間單調增長。
LP 份額由池的儲備金定價,而不是由 k 定價:
燒毀 ΔLP 個 LP 代幣會返回恰好 ΔLP × x / lpSupply 的 token0 和 ΔLP × y / lpSupply 的 token1。曲線和 k 在存入或提取時都不會移動 — 只有交換會改變價格。
交換路徑上的費用模型
CPMM 在每次交換上應用兩個獨立計費的費用:- 交易費用在輸入端收取,按
AmmConfig.trade_fee_rate計費。然後將其分為 LP、協議和基金份額(LP 份額保留在金庫中並增長k;協議和基金份額從金庫會計中提取)。 - 創作者費用(僅當
enable_creator_fee == true時有效)按AmmConfig.creator_fee_rate計費。它在輸入端或輸出端收取,取決於PoolState.creator_fee_on和交換方向(見products/cpmm/fees)。它是自己的費用桶 — 永遠不是交易費用的一部分。
協議對創作者費用的份額不會出現在本頁的任何地方,這是有意的。 它在
CollectCreatorFee 在曲線已經排除的兩個計數器之間移動累積費用時應用 — 而不是在交換期間。交換數學、報價和 k 無論有無它都是相同的。見products/cpmm/fees。FEE_RATE_DENOMINATOR = 1_000_000trade_fee_rate— 來自AmmConfig,例如2500= 相關交易量端的 0.25%creator_fee_rate— 來自AmmConfig,例如1000= 相關交易量端的 0.10%protocol_fee_rate、fund_fee_rate— 以1/FEE_RATE_DENOMINATOR交易費用的單位計,而不是交易量
protocol_fee + fund_fee + creator_fee 的金額保留在金庫中,但在池狀態上單獨追蹤(protocol_fees_token*、fund_fees_token*、creator_fees_token*)。當常數乘積不變量檢查 k' ≥ k 時,它使用金庫餘額減去所有三個累積但未清掃的費用 — 因此 LP 只捕獲 lp_fee。
見products/cpmm/fees了解收集指令和詳細的數值示例。
SwapBaseInput(輸入精確)
「用戶給我們恰好amount_in 的輸入代幣,並接收至少 minimum_amount_out 的輸出代幣。」
暫時忽略 Token-2022:
Δx_net = amount_in_after_trade_fee。
程序隨後更新金庫會計,使得 trade_fee 中欠協議/基金/創作者的部分位於「累積」費用桶中(不包括在曲線的下一個 x 中),而 LP 份額確實加入 x 用於下一次交換。
Token-2022 在輸入端
如果輸入代幣有轉帳費用擴展,代幣在從用戶轉帳到金庫時扣除其費用。因此金庫實際接收amount_in − transfer_fee_in(amount_in)。CPMM 程序因此計算:
amount_in_after_trade_fee 運行曲線。這很重要,因為曲線價格是根據實際進入金庫的淨金額計算的,而不是根據用戶的標題金額。
Token-2022 在輸出端
如果輸出代幣有轉帳費用,池從其金庫向用戶發送amount_out。代幣隨後會在途中扣除其費用,因此用戶接收 amount_out − transfer_fee_out(amount_out)。程序照常從曲線計算 amount_out,但當顯示報價時,集成商有責任將池的「金庫發送」數字轉換為「用戶接收」數字。
滑點檢查
計算amount_out 後:
minimum_amount_out 之前應用轉帳費用,因此滑點常數以用戶實際接收的金額計,而不是金庫發送的金額。
SwapBaseOutput(輸出精確)
「用戶將恰好接收amount_out 的輸出代幣,並願意支付最多 maximum_amount_in 的輸入代幣。」
反轉曲線以求 Δx_net:
向上取整很重要 — 它保證在整數截斷後 k' ≥ k。然後:
gross_needed。
滑點檢查
詳細示例
池狀態,忽略 Token-2022:x = 1_000_000_000_000(1,000,000.000000 的 token0,6 位小數)y = 2_000_000_000_000(2,000,000.000000 的 token1,6 位小數)AmmConfig:trade_fee_rate = 2500、protocol_fee_rate = 120_000、fund_fee_rate = 40_000、creator_fee_rate = 0
SwapBaseInput,amount_in = 1_000_000_000(1,000.000000 的 token0)。創作者費用已禁用(enable_creator_fee = false)。
enable_creator_fee = true,creator_fee_rate = 1000(0.10%)在輸入端,程序會收取 total_input_fee = ceil(1_000_000_000 * 3500 / 1_000_000) = 3_500_000,然後將其分為 creator_fee = 1_000_000 和 trade_fee = 2_500_000。trade_fee 上的協議/基金/LP 算術與上面的示例相同 — 創作者費用是自己的費用桶,累積到 creator_fees_token0 並與協議和基金費用桶一起從 curve_x 中排除。
如果輸入代幣有 1% 的 Token-2022 轉帳費用,金庫接收 990_000_000 個代幣而不是 1_000_000_000,所有後續計算都使用該淨金額。
觀察更新規則
在每次交換時,程序評估是否應將新觀察推送到環形緩衝區:- 累積價格,而不是現貨價格。 單個觀察不是價格。要從時間
t0到t1獲得 TWAP,讀取最接近每一端的觀察,並計算(cumulative(t1) − cumulative(t0)) / (t1 − t0)。 - 樣本受速率限制。 同一個槽中的連續交換可能共享一個觀察。在交換後立即讀取觀察可能看起來陳舊一個槽 — 這是正常的。
products/clmm/accounts。
曲線上的費用
這是微妙的部分,值得特別說明。曲線算術針對淨金庫餘額工作 — 即原始 SPL 餘額減去累積的協議、基金和創作者費用(所有三個都是獨立的費用桶 — 見products/cpmm/fees)。一個具體的圖景:
- 不要從原始餘額報價。 先減去累積費用欄位,或調用
SwapBaseInput作為模擬並取其返回值。 CollectProtocolFee將代幣移出金庫。 收集後,raw_vault_balance下降,但curve_balance保持不變;池的價格不會移動。這是有意的。
精度和溢出
- 所有曲線算術使用
u128中間值以防止x * y上的溢出。 - 除法向零舍入,除了
SwapBaseOutput的Δx_net(向上舍入)和費用計算(在trade_fee上向上舍入,在子分割上向下舍入)。這些舍入方向被選擇以確保不變量由於整數截斷而永遠不會減少。 - 具有極端金庫比率(數十億:1)的池可能在小交易上達到精度下限;程序在這種情況下返回
ZeroTradingTokens。見reference/error-codes。
接下來去哪裡
products/cpmm/fees— 完整的費用層級和收集語義。products/cpmm/instructions— 調用此數學的指令。algorithms/constant-product—x · y = k的推導和邊界情況,在 AMM v4 和 CPMM 中共享。

