> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 常数乘积 AMM

> x·y=k 不变式、基于储备的定价、滑点推导以及 Raydium CPMM 和 AMM v4 使用的费用处理变体。这是 Raydium 中所有 x·y=k 产品的参考数学页面。

<Info>
  **本页内容由 AI 自动翻译，所有内容以英文版本为准。**

  [查看英文版 →](/algorithms/constant-product)
</Info>

## 不变式

常数乘积做市商（CPMM）持有两个储备 `x` 和 `y`，并强制以下条件：

```
x · y ≥ k       (每次交易后)
```

其中 `k` 是交易前的储备乘积。对于无费用市场，`x · y = k` 完全相等。有费用时，`k` 会严格增长（LP 费用份额保留在储备中）。

这个不变式是刻意设计的几何形式：它保证无论一个储备变多小，另一个都会无限增长来匹配——也就是说，池子在任何一侧都永远不会被完全耗尽。

## 定价

### 现货价格

在任何时刻，用 `x` 表示的 `y` 的边际价格是曲线的切线：

```
p = y / x
```

（推导：对 `x · y = k` 进行隐函数求导得到 `dy/dx = −y/x`；忽略符号，`|dy/dx| = y/x`）。

这是池子为无穷小交易报价的价格。对于任何有限交易，因为沿曲线的滑点，实现的价格会更差。

### 精确输入交换（给出 `Δx`，接收 `Δy`）

有费用的情况下，设 `f` 为费用率（例如 `f = 0.0025` 表示 25 个基点）。将费用应用于输入，然后使用不变式求解输出：

```
Δx_after_fee = Δx · (1 − f)
Δy           = y · Δx_after_fee / (x + Δx_after_fee)
```

交易后储备：

```
x' = x + Δx
y' = y − Δy
```

完整的 `Δx` 进入储备。费用的 LP 份额保留在 `x'` 中；协议份额通过单独的会计步骤从曲线中排除（见下方的[费用会计变体](#fee-accounting-variants)）。

### 精确输出交换（接收 `Δy`，支付最小的 `Δx`）

```
Δx_after_fee = x · Δy / (y − Δy)
Δx           = Δx_after_fee / (1 − f)
```

`Δx` 向上舍入，以确保池子不会低估费用。

## 滑点和价格影响

**价格影响**衡量交易导致池子现货价格变动的幅度：

```
p_before = y / x
p_after  = y' / x' = (y − Δy) / (x + Δx)
impact   = (p_before − p_after) / p_before
```

对于较小的 `Δx / x`，一阶泰勒展开给出：

```
impact ≈ 2 · Δx / x      (忽略费用)
```

直观理解：1% 的交换会导致约 2% 的价格影响。这个因子 2 是 CPMM 池子对中等规模交易的报价看起来"稀薄"的原因，与订单簿市场相比——你不仅是在当前最优报价处买入，还在走自己的边际价格曲线。

**有效价格**是交易者支付的：

```
effective = Δx / Δy
```

`p_before` 和 `effective` 之间的差价是**滑点**。链上 UI 通常将 `slippage` 表示为 `(effective − p_before) / p_before`；SDK 的 `computeAmountOut` 返回 `amountOut` 和 `priceImpact` 是为了这个原因。

## 代码中的不变式检查

交换后，协议重新验证：

```
k' = x' · y'  ≥  k  =  x · y
```

任何违反都是程序 bug 或算术溢出。Raydium 的交换指令将此检查显式地作为后置条件：

```rust theme={null}
let k_before = coin_reserve_before as u128 * pc_reserve_before as u128;
let k_after  = coin_reserve_after  as u128 * pc_reserve_after  as u128;
require!(k_after >= k_before, ErrorCode::InvariantViolation);
```

## 费用会计变体

不变式检查假设 LP 费用保留在储备中。不同的 Raydium 产品对协议/基金/创建者分量的处理方式不同：

### CPMM 约定

费用是基于 `1_000_000` 分母的 `u64` 基点类似费率。交易费用分为 `trade_fee_rate`（总计），然后通过 `protocol_fee_rate`、`fund_fee_rate`、`creator_fee_rate` 细分。每次交换时：

```
trade_fee     = ceil(Δx · trade_fee_rate / 1_000_000)
protocol_fee  = trade_fee · protocol_fee_rate / 1_000_000
fund_fee      = trade_fee · fund_fee_rate     / 1_000_000
creator_fee   = trade_fee · creator_fee_rate  / 1_000_000
lp_fee        = trade_fee − protocol_fee − fund_fee − creator_fee
```

三个非 LP 份额累积到单独的计数器（`protocol_fees_*`、`fund_fees_*`、`creator_fees_*`）中，这些计数器**被排除**在不变式中使用的储备之外。这就是如何在不移动曲线的情况下清扫费用的方式。参见[`products/cpmm/fees`](/zh/products/cpmm/fees)。

### AMM v4 约定

费用是基于 `10_000` 分母的 `numerator / denominator` 比率。分割在池子创建时固定，并存储在 `AmmInfo.fees` 上：

```
swap_fee  = ceil(Δx · swap_fee_numerator / swap_fee_denominator)    // 例如 0.25%
pnl_share = swap_fee · pnl_numerator / swap_fee_numerator            // 例如 0.03 / 0.25 = 12%
lp_share  = swap_fee − pnl_share                                     // 交易量的 0.22%
```

`pnl_share` 累积到 `state_data.need_take_pnl_*` 中并从储备中排除；`lp_share` 保留在保险库中。参见[`products/amm-v4/fees`](/zh/products/amm-v4/fees)。

两种约定以相同方式保留不变式——区别仅是表面（分母 + 子类别数量）。

## 舍入规则

* **费用计算向上舍入。** 确保池子永远不会低估费用。
* **输出金额向下舍入。** 确保不变式严格成立（即使在添加费用之前 `k' > k`）。
* **精确输出输入金额向上舍入。** 确保用户不会少付。

所有算术使用 `u128` 来计算中间的 `x · Δx` 乘积，以避免大型储备上的溢出。最终结果通过饱和检查转换回 `u64`。

## 边界情况

### 空池子

在首次 `Deposit` 之前，`x = y = 0`。交换指令拒绝预存款。

### 零输出

如果 `Δx` 足够小，使得舍入后的 `Δy` 为 0，指令将以 `ZeroTradingTokens` 错误回滚。这防止了无需支付而提取价值；也意味着高度不平衡池子上的尘埃交换失败。

### 尘埃 LP

首次 `Deposit` 有特殊处理：它将初始 LP 供应计算为 `sqrt(x · y)`，并销毁少量"初始销毁"金额（通常 100 LP 单位）以防止"首存款膨胀攻击"（攻击者向保险库捐赠并膨胀 LP 代币价值）。后续存款使用按比例计算。

## 与套利的关系

CPMM 池子的价格仅通过以下方式改变：

1. 通过池子本身的交易（用户沿曲线行走）。
2. 捐赠（不进行交换而向保险库发送代币）。

由于交易通过曲线以确定性方式移动价格，任何其价格与更广泛市场价格偏离的池子都会产生套利机会。套利者将池子价格拉回市场价格附近。这就是为什么说 CPMM 池子"在没有预言机的情况下报价"：市场通过套利而不是池子外部读取来找到价格。

反过来说：池子本身是套利者的对手方，所以任何套利利润都是 LP 的无常损失（减去 LP 捕获的费用）。

## 详细示例

### 示例 1——小额交易，可忽略的滑点

池子：`x = 1_000_000, y = 2_000_000, k = 2·10^12`。费用 `f = 0.0025`。

交易 `Δx = 1_000`：

```
Δx_after_fee = 1000 · 0.9975  = 997.5
Δy           = 2_000_000 · 997.5 / (1_000_000 + 997.5)
             = 1_995_000_000 / 1_000_997.5
             ≈ 1_993.01
```

有效价格：`1000 / 1993.01 ≈ 0.5018`。之前现货：`0.5`。影响：约 0.36%。

### 示例 2——中等交易，明显滑点

同一池子，`Δx = 100_000`（`x` 的 10%）：

```
Δx_after_fee = 100_000 · 0.9975 = 99_750
Δy           = 2_000_000 · 99_750 / (1_000_000 + 99_750)
             = 199_500_000_000 / 1_099_750
             ≈ 181_405
```

有效价格：`100_000 / 181_405 ≈ 0.5513`。影响：约 10.3%——大约是 `2 · 10% = 20%` 经验法则的一半（该法则是无费用常数乘积曲线的最坏情况上限；交易费用加上公式中的反演会降低它）。

## 相关页面

* [`products/cpmm/math`](/zh/products/cpmm/math) — CPMM 的特定舍入 + 费用分母选择。
* [`products/amm-v4/math`](/zh/products/amm-v4/math) — AMM v4 的 OpenBook 集成储备如何扩展此模型。
* [`algorithms/slippage-and-price-impact`](/zh/algorithms/slippage-and-price-impact) — 关于为 UI 调整滑点容差的专题页面。

来源：

* Uniswap v2 白皮书 — `x · y = k` 的规范陈述。
* Raydium CPMM 程序源代码。
* Raydium AMM v4 程序源代码。
