Chuyển đến nội dung chính

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.

Trang này được dịch tự động bằng AI. Phiên bản tiếng Anh là bản chính thức.Xem bản tiếng Anh →

Bất biến

CPMM duy trì bất biến sản phẩm hằng số cổ điển trên hai kho lưu trữ của nó: xy=kx \cdot y = k trong đó x là số dư kho0 sau bất kỳ phí chuyển Token-2022 nào khi nhận, tương tự cho y. Mỗi swap phải để lại k' ≥ k sau khi tính đến phí giao dịch được ghi có cho LP (các khoá protocol, quỹ và người sáng tạo không được tính vào k — chúng nằm trong kho nhưng bị loại khỏi dạng xem đường cong, xem Phí trên đường cong dưới đây). k do đó tăng đơn điệu theo thời gian khi LP tích lũy phí. Cổ phiếu LP được định giá theo dự trữ của pool, không phải theo k: Giaˊ LP theo token0=xlpSupply,Giaˊ LP theo token1=ylpSupply\text{Giá LP theo token0} = \frac{x}{\text{lpSupply}}, \qquad \text{Giá LP theo token1} = \frac{y}{\text{lpSupply}} Đốt ΔLP token LP sẽ trả lại chính xác ΔLP × x / lpSupply của token0 và ΔLP × y / lpSupply của token1. Cả đường cong và k không di chuyển khi gửi hoặc rút tiền — chỉ swap thay đổi giá.

Mô hình phí trên đường dẫn swap

CPMM áp dụng hai phí được định giá độc lập trên mỗi swap:
  • Phí giao dịch được lấy ở phía đầu vào, được tính với AmmConfig.trade_fee_rate. Sau đó nó được chia thành phần chia sẻ LP, protocol và quỹ (phần chia sẻ LP vẫn ở trong kho và tăng k; phần chia sẻ protocol và quỹ được trích xuất khỏi hạch toán kho).
  • Phí người sáng tạo (chỉ hoạt động khi enable_creator_fee == true) được tính với AmmConfig.creator_fee_rate. Nó được lấy ở phía đầu vào hoặc đầu ra tùy thuộc vào PoolState.creator_fee_on và hướng swap (xem products/cpmm/fees). Nó là một khoá riêng — không bao giờ là một phần của phí giao dịch.
Để:
  • FEE_RATE_DENOMINATOR = 1_000_000
  • trade_fee_rate — từ AmmConfig, ví dụ: 2500 = 0,25% của phía thể tích liên quan
  • creator_fee_rate — từ AmmConfig, ví dụ: 1000 = 0,10% của phía thể tích liên quan
  • protocol_fee_rate, fund_fee_rate — tính theo đơn vị 1/FEE_RATE_DENOMINATOR của phí giao dịch, không phải của thể tích
Khi phí người sáng tạo ở phía đầu vào:
total_input_fee = ceil(amount_in * (trade_fee_rate + creator_fee_rate) / FEE_RATE_DENOMINATOR)
creator_fee     = floor(total_input_fee * creator_fee_rate / (trade_fee_rate + creator_fee_rate))
trade_fee       = total_input_fee - creator_fee
amount_in_after_fees = amount_in - total_input_fee
Khi phí người sáng tạo ở phía đầu ra:
trade_fee            = ceil(amount_in * trade_fee_rate / FEE_RATE_DENOMINATOR)
amount_in_after_fees = amount_in - trade_fee
amount_out_curve     = curve_output(amount_in_after_fees, ...)
creator_fee          = ceil(amount_out_curve * creator_fee_rate / FEE_RATE_DENOMINATOR)
amount_out           = amount_out_curve - creator_fee
Trong cả hai trường hợp, phí giao dịch được chia theo cách tương tự:
protocol_fee   = floor(trade_fee * protocol_fee_rate / FEE_RATE_DENOMINATOR)
fund_fee       = floor(trade_fee * fund_fee_rate     / FEE_RATE_DENOMINATOR)
lp_fee         = trade_fee - protocol_fee - fund_fee     // creator_fee được KHÔNG trừ ở đây
Số tiền protocol_fee + fund_fee + creator_fee được giữ trong các kho nhưng được theo dõi riêng trên trạng thái pool (protocol_fees_token*, fund_fees_token*, creator_fees_token*). Khi kiểm tra bất biến sản phẩm hằng số là k' ≥ k, nó sử dụng số dư kho trừ cả ba phí tích lũy nhưng chưa được thu thập — vì vậy LP chỉ nhận được lp_fee. Xem products/cpmm/fees để biết các hướng dẫn thu thập và các ví dụ toán học đã hoàn thành.

SwapBaseInput (input-exact)

“Người dùng cung cấp cho chúng tôi chính xác amount_in của mint đầu vào và nhận ít nhất minimum_amount_out của mint đầu ra.” Bỏ qua Token-2022 một lúc:
amount_in_after_trade_fee = amount_in - trade_fee
amount_out                = y − (x * y) / (x + amount_in_after_trade_fee)
Theo đại số: amount_out=yΔxnetx+Δxnet\text{amount\_out} = \frac{y \cdot \Delta x_{\text{net}}}{x + \Delta x_{\text{net}}} trong đó Δx_net = amount_in_after_trade_fee. Chương trình sau đó cập nhật hạch toán kho sao cho phần trade_fee được nợ cho protocol/quỹ/người sáng tạo nằm trong các khoá “tích lũy” (không được bao gồm trong x tiếp theo của đường cong), trong khi phần chia sẻ LP sẽ tham gia x cho swap tiếp theo.

Token-2022 ở phía đầu vào

Nếu mint đầu vào có tiện ích phí chuyển, mint sẽ trừ phí của nó khi chuyển từ người dùng → kho. Vì vậy, kho thực tế nhận được amount_in − transfer_fee_in(amount_in). Do đó, chương trình CPMM tính toán:
amount_actually_received = amount_in − transfer_fee_in(amount_in)
trade_fee                = ceil(amount_actually_received * trade_fee_rate / FEE_RATE_DENOMINATOR)
amount_in_after_trade_fee = amount_actually_received − trade_fee
và chạy đường cong chống lại amount_in_after_trade_fee. Điều này quan trọng vì giá đường cong được tính từ số tiền ròng đã hạ cánh trong kho, không phải từ số tiền hàng loạt của người dùng.

Token-2022 ở phía đầu ra

Nếu mint đầu ra có phí chuyển, pool sẽ gửi amount_out từ kho của nó đến người dùng. Mint sau đó sẽ lấy phí của nó trên đường đi, vì vậy người dùng nhận được amount_out − transfer_fee_out(amount_out). Chương trình tính toán amount_out từ đường cong như thường lệ, nhưng trách nhiệm của tích hợp là chuyển đổi số “gửi từ kho” của pool thành số “nhận được của người dùng” khi hiển thị báo giá.

Kiểm tra slippage

Sau khi tính toán amount_out:
require(amount_out >= minimum_amount_out, "AmountSpecifiedLessThanMinimum")
Nếu mint đầu ra tính phí chuyển, SDK áp dụng phí chuyển trước khi đặt minimum_amount_out vì vậy hằng số slippage được tính bằng những gì người dùng sẽ thực sự nhận được, không phải những gì kho gửi đi.

SwapBaseOutput (output-exact)

“Người dùng sẽ nhận được chính xác amount_out của mint đầu ra và sẵn sàng trả tối đa maximum_amount_in của mint đầu vào.” Đảo ngược đường cong cho Δx_net: Δxnet=xamount_outyamount_out\Delta x_{\text{net}} = \left\lceil \frac{x \cdot \text{amount\_out}}{y - \text{amount\_out}} \right\rceil Giới hạn trên rất quan trọng — nó đảm bảo k' ≥ k sau khi cắt ngắn số nguyên. Sau đó:
// Làm việc ngược từ net in đến gross in.
// phí được áp dụng trên gross, vì vậy:
//   net = gross − ceil(gross * rate / D)
//       ≈ gross * (D − rate) / D
// đảo ngược với giới hạn trên ở những nơi thích hợp:
gross_needed = ceil(Δx_net * D / (D − trade_fee_rate))
Trên Token-2022 input, bao bọc với:
gross_needed_before_mint_fee
  = inflate_for_transfer_fee(gross_needed, input_mint)
vì vậy người dùng trả đủ để sau khi mint trừ phí chuyển, pool vẫn nhận được gross_needed.

Kiểm tra slippage

require(gross_needed_before_mint_fee <= maximum_amount_in, "AmountSpecifiedExceedsMaximum")

Ví dụ hoàn thành

Trạng thái pool, bỏ qua Token-2022:
  • x = 1_000_000_000_000 (1.000.000,000000 của token0, 6 chữ số thập phân)
  • y = 2_000_000_000_000 (2.000.000,000000 của token1, 6 chữ số thập phân)
  • AmmConfig: trade_fee_rate = 2500, protocol_fee_rate = 120_000, fund_fee_rate = 40_000, creator_fee_rate = 0
Người dùng: SwapBaseInput với amount_in = 1_000_000_000 (1.000,000000 của token0). Phí người sáng tạo bị vô hiệu hóa (enable_creator_fee = false).
trade_fee                = ceil(1_000_000_000 * 2500 / 1_000_000)       = 2_500_000
  protocol_fee           = floor(2_500_000 * 120_000 / 1_000_000)       = 300_000
  fund_fee               = floor(2_500_000 *  40_000 / 1_000_000)       = 100_000
  lp_fee                 = 2_500_000 − 300_000 − 100_000                 = 2_100_000
creator_fee              = 0                                              // disabled

amount_in_after_trade_fee = 1_000_000_000 − 2_500_000                    = 997_500_000

amount_out = y − (x * y) / (x + Δx_net)
           = 2_000_000_000_000
             − (1_000_000_000_000 * 2_000_000_000_000)
               / (1_000_000_000_000 + 997_500_000)
           ≈ 1_995_015_009

new_vault0_raw   = x + amount_in                                        = 1_001_000_000_000
new_vault1       = y − amount_out                                       ≈ 1_998_004_984_991

// Trong số 1_000_000_000 nhận được trong vault0, 400_000 là "phí tích lũy"
// (protocol + quỹ) mà đường cong nên loại trừ:
curve_x          = new_vault0_raw − (protocol_fees_token0 + fund_fees_token0)
                 = 1_001_000_000_000 − 400_000
                 = 1_000_999_600_000

k' = curve_x * new_vault1 ≈ 2.000_002_501_E24  ≥  k = 2.0E24   ✓
Nếu pool tương tự có enable_creator_fee = true với creator_fee_rate = 1000 (0,10%) ở phía đầu vào, chương trình sẽ tính total_input_fee = ceil(1_000_000_000 * 3500 / 1_000_000) = 3_500_000, sau đó chia thành creator_fee = 1_000_000trade_fee = 2_500_000. Số học protocol/quỹ/LP trên trade_fee không thay đổi từ ví dụ trên — phí người sáng tạo là khoá của riêng nó, được tích lũy thành creator_fees_token0 và loại trừ khỏi curve_x cùng với các khoá protocol và quỹ. Nếu mint đầu vào có phí chuyển Token-2022 là 1%, kho nhận được 990_000_000 token thay vì 1_000_000_000, và mỗi tính toán tiếp theo sử dụng số tiền ròng đó.

Quy tắc cập nhật quan sát

Trên mỗi swap, chương trình đánh giá xem có nên đẩy một quan sát mới vào vòng lặp đệm hay không:
let since_last = now − observations[head].block_timestamp;
if since_last >= MIN_OBSERVATION_INTERVAL {
    let price0 = (vault1 << 32) / vault0;            // Q32.32-ish
    let price1 = (vault0 << 32) / vault1;
    let head' = (head + 1) % OBSERVATION_NUM;
    observations[head'] = Observation {
        block_timestamp: now,
        cumulative_token0_price_x32:
            observations[head].cumulative_token0_price_x32 + price0 * since_last,
        cumulative_token1_price_x32:
            observations[head].cumulative_token1_price_x32 + price1 * since_last,
    };
    head = head';
}
Hai tính chất:
  • Giá tích lũy, không phải giá tại chỗ. Một quan sát duy nhất không phải là giá. Để lấy TWAP từ thời gian t0 đến t1, đọc các quan sát gần nhất với mỗi đầu và tính (cumulative(t1) − cumulative(t0)) / (t1 − t0).
  • Các mẫu bị giới hạn tốc độ. Các swap liên tiếp trong cùng một slot có thể chia sẻ một quan sát. Đọc một quan sát ngay sau một swap do đó có thể trông cũ bởi một slot — điều này là bình thường.
Thêm trong products/clmm/accounts.

Phí trên đường cong

Đây là phần tinh tế và đáng được nhấn mạnh. Số học đường cong hoạt động chống lại các số dư kho ròng — tức là, số dư SPL thô trừ đi phí tích lũy protocol, quỹ và người sáng tạo (cả ba là các khoá độc lập — xem products/cpmm/fees). Một bức tranh cụ thể:
raw_vault_balance   = những gì trả về RPC getTokenAccountBalance
accrued_fees        = protocol_fees_token{0,1} + fund_fees_token{0,1} + creator_fees_token{0,1}
curve_balance       = raw_vault_balance − accrued_fees
invariant           = curve_balance0 * curve_balance1
Hệ quả cho các tích hợp:
  • Không báo giá từ số dư thô. Trừ đi các trường phí tích lũy trước, hoặc gọi SwapBaseInput như một mô phỏng và lấy kết quả trả về của nó.
  • CollectProtocolFee di chuyển token ra khỏi kho. Sau khi thu thập, raw_vault_balance giảm nhưng curve_balance không thay đổi; giá của pool không di chuyển. Điều này là cố ý.

Độ chính xác và tràn

  • Tất cả số học đường cong sử dụng trung gian u128 để ngăn chặn tràn trên x * y.
  • Phép chia làm tròn về phía không, ngoại trừ Δx_net của SwapBaseOutput, làm tròn lên, và tính toán phí, làm tròn lên trên trade_fee và xuống trên các phân chia con. Các hướng làm tròn này được chọn sao cho bất biến không bao giờ giảm do cắt ngắn số nguyên.
  • Các pool có tỷ lệ kho cực kỳ (hàng tỷ : 1) có thể hit precision floors trên các giao dịch nhỏ; chương trình trả về ZeroTradingTokens trong trường hợp đó. Xem reference/error-codes.

Tiếp theo là gì

Nguồn: