跳转到主要内容

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.

本页内容由 AI 自动翻译,所有内容以英文版本为准。查看英文版 →

不变式

池子维持 coin_reserve × pc_reserve = k,其中:
coin_reserve = coin_vault_balance
             + orders_posted_on_openbook.base
             + pending_coin_fill_not_yet_settled
pc_reserve   = pc_vault_balance
             + orders_posted_on_openbook.quote
             + pending_pc_fill_not_yet_settled
             - accrued_pnl_pc
需要注意两点:
  1. 储备金包括在 OpenBook 上提交的金额。AMM 的限价单仍然是其流动性的一部分——它们并未”丢失”到订单簿中,只是被托管在那里。仅根据链上金库余额计算 k 会低估储备金。
  2. PnL 累计值(need_take_pnl_*)被减去,以便在管理员扫除费用时保持曲线不变。这与 CPMM 的 protocol_fees_* 排除原则相同。
每次 Swap* 操作都会强制执行 k' ≥ k,在把流动性提供者的费用份额加回到储备金后。

费用约定

AMM v4 使用比例费用(分子/分母对),而不是 CPMM / CLMM 的 1/1_000_000 约定。链上 Fees 结构体(见程序源中的 Fees::initialize)默认为:
Fees {
  min_separate_numerator:    5,
  min_separate_denominator:  10_000,   //  5/10_000 = 0.05%

  trade_fee_numerator:      25,
  trade_fee_denominator:    10_000,    // 25/10_000 = 0.25% — 用于 OpenBook 限价单定价

  pnl_numerator:            12,
  pnl_denominator:          100,       // 12/100   = 12%   — 协议在交换费中的份额

  swap_fee_numerator:       25,
  swap_fee_denominator:     10_000,    // 25/10_000 = 0.25% — AMM 路径交换的总费用
}
解释(发布的主网默认值):
  • 总交换费: swap_fee = amount_in × 25 / 10_000 = 0.25% 的总输入。
  • 协议份额: pnl_numerator / pnl_denominator = 12 / 100 = 12% 占交换费的,相当于交易量的 0.25% × 12% = 0.03%。这部分累计到 PnL 计数器中,由 WithdrawPnl 扫除。
  • 流动性提供者份额: 交换费的剩余 88%,相当于交易量的 0.25% × 88% = 0.22%。留在池子中并增加 k
  • 无基金份额。 AMM v4 没有 CPMM/CLMM 的基金费用拆分。
注意 pnl_numerator / pnl_denominator 是费用的一个分数**,而不是**交易量的分数——这是这些字段名称常见的误读。 trade_fee_numerator / trade_fee_denominator(也是 25 / 10_000)是一个独立的字段,由 OpenBook 集成使用,用于计算 AMM 限价单网格的费用包含价格;默认情况下它等于 swap_fee,但从不同的代码路径读取。 偏离这些默认值的情况很少见,但在少数几个遗留池子中确实存在;在引用之前,请始终从 AmmInfo.fees 读取费用。

直接交换数学(AMM 路径)

最简单的情况:用户针对池子的金库进行交换,而不与 OpenBook 互动。池子的内部储备金(包括在簿上的分配)是分母。 SwapBaseIn(精确输入):
amount_after_fee = amount_in − ceil(amount_in × swap_fee_numerator / swap_fee_denominator)
amount_out = amount_after_fee × out_reserve
           / (in_reserve + amount_after_fee)
require(amount_out >= minimum_amount_out)
这里使用的储备金是有效储备金。从历史上讲,这是 coin_vault_balance + coin_posted_on_openbook + ...(AMM 的金库加上它锁定在 OpenBook 订单中的代币)。自 OpenBook 停用后,在簿上的余额为零,因此有效储备金等于原始金库余额。曾经用于刷新 OpenBook 端的 MonitorStep / 隐式结算路径在实践中不再需要。 SwapBaseOut(精确输出):
amount_in_after_fee = ceil(in_reserve × amount_out / (out_reserve − amount_out))
amount_in_gross     = ceil(amount_in_after_fee × swap_fee_denominator
                            / (swap_fee_denominator − swap_fee_numerator))
require(amount_in_gross <= maximum_amount_in)

订单簿交互(历史)

不再活跃。 本节中描述的网格构造反映了 AMM v4 最初如何将曲线镜像到 OpenBook 市场的方式。OpenBook 集成已被停用;池子不再在 OpenBook 上发布或维护订单。以下数学保留用于参考——它解释了链上 target_orders / amm_open_orders 账户的大小以及为什么程序即使 keeper 不再执行它们也仍然验证 MonitorStep 相关参数。
与用户交换分开,AMM v4 历史上在 OpenBook 市场上放置了一个限价单网格。该网格从 AmmInfo 参数计算:
  • depth — 每一侧的价格水平数量。
  • amount_wave — 每个水平的基本大小单位。
  • min_sizecoin_lot_sizepc_lot_size — OpenBook 市场约束。
  • state_data.swap_acc_coin_feeswap_acc_pc_fee — 自上次 TakePnl 以来的累计费用计数器。
程序通过从当前曲线价格开始,以恒定比率步长走出来推导每个水平的价格:
price_level(k) = curve_price × (1.0001 ^ k)       # 概念上
size_level(k)  = amount_wave × f(depth, k)        # 按深度锥化
精确的价格和大小由 build_orders 计算的 target_orders 确定,并与每个 MonitorStep 中的 amm_open_orders 进行比较。任何偏差都会导致取消 + 新发布。OpenBook 上新填充的订单在刷新 OpenBook 端的下一次操作时结算到池子金库中。 集成者很少需要计算网格——Raydium keeper 维护它——但了解以下情况很有用:
  • 具有大量在簿上流动性的池子将该流动性贡献给 k,而不是闲置。
  • 陈旧的 OpenBook 市场(事件队列已满,crank 被阻止)会阻止网格更新;AMM 随后可以引用与可见订单簿不同的价格,直到下一次 crank。

结算步骤(PnL)

0.03% 的协议份额累计到 state_data.need_take_pnl_coinstate_data.need_take_pnl_pcTakePnl 将这些金额从金库移出到管理员指定的目标地址,然后清零计数器。 关键属性:不变式中的储备金始终计算时减去累计 PnL,所以 TakePnl 不会移动曲线。这与 CPMM 约定相匹配。

计算示例

池子状态:
  • coin_reserve = 1_000_000_000_000(100 万币方;6 位小数)
  • pc_reserve = 2_000_000_000_000(200 万 pc 方;6 位小数)
  • 费用:默认 swap = 25/10_000pnl = 3/10_000
用户:SwapBaseIn 精确输入 1_000_000_000 个币(1,000 个币)。
swap_fee        = ceil(1_000_000_000 * 25 / 10_000)    = 2_500_000
amount_after_fee =                                      997_500_000

amount_out = amount_after_fee * pc_reserve
           / (coin_reserve + amount_after_fee)
           = 997_500_000 * 2_000_000_000_000
           / (1_000_000_000_000 + 997_500_000)
           ≈ 1_995_015_009  (1,995.015 pc)

// 在 2_500_000 交换费中:
pnl_share = 2_500_000 * 3 / 25  = 300_000    (通过 need_take_pnl_coin 进入协议)
lp_share  = 2_500_000 * 22 / 25 = 2_200_000  (留在 coin_reserve 中)

new coin_reserve = 1_000_000_000_000 + 1_000_000_000                 = 1_001_000_000_000
                   (其中 300_000 是累计 PnL)
  curve coin_reserve = 1_001_000_000_000 − 300_000 = 1_000_999_700_000
new pc_reserve   = 2_000_000_000_000 − 1_995_015_009                 ≈ 1_998_004_984_991

k' = curve_coin_reserve * new_pc_reserve
   ≈ 2.000_002_701E24
k  = 1_000_000_000_000 * 2_000_000_000_000
   = 2.0E24
k' > k   ✓
LP 份额(2_200_000)不会在任何地方被单独显示——它只是将 k' 提高的剩余部分。

精度规则

  • 储备金乘法使用 u128;最终除法向零舍入。
  • swap_fee 向上舍入(使池子不会低收费)。
  • SwapBaseOutamount_in 向上舍入(使用户不会少付)。
  • 具有极端储备金比率的池子在非常小的输入上可能会触发 ZeroTradingTokens;与 CPMM 的约定相同。

相比 CPMM 的限制

  • AMM v4 的储备金包括 OpenBook 托管部分,所以集成者不能仅从 getTokenAccountBalance 中正确报价。始终获取完整状态(金库 + open_orders.free + open_orders.locked),或使用 SDK / API 报价。
  • AMM v4 不公开结构化的链上 TWAP。想要 AMM v4 支持价格的外部消费者必须自己从交易日志计算。
  • 不支持 Token-2022。

后续内容

来源: