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 →

Hai khoản phí độc lập, bốn địa chỉ đích

CPMM tính hai khoản phí riêng biệt có tỷ lệ khác nhau trên mọi swap:
  1. Phí giao dịch — được tính theo AmmConfig.trade_fee_rate và chia thành ba địa chỉ đích:
    • Phần LP — nằm trong vault và tăng k. Được yêu cầu ngầm bằng cách đốt token LP.
    • Phần giao thức — được tích lũy vào PoolState.protocol_fees_token*; được rút bởi protocol_owner thông qua CollectProtocolFee.
    • Phần quỹ — được tích lũy vào PoolState.fund_fees_token*; được rút bởi fund_owner thông qua CollectFundFee.
  2. Phí nhà tạo (tùy chọn, cho mỗi pool) — được tính theo AmmConfig.creator_fee_rate độc lập với phí giao dịch, tích lũy vào PoolState.creator_fees_token*, được rút bởi pool_state.pool_creator thông qua CollectCreatorFee. Chỉ hoạt động khi pool được tạo với enable_creator_fee = true.
Phí nhà tạo không phải là một phần của phí giao dịch. Hai tỷ lệ được cộng lại khi phí được tính trên đầu vào swap, nhưng mỗi tỷ lệ vẫn là một hạng mục riêng — các phần của giao thức và quỹ luôn được tính từ trade_fee mà thôi, không bao giờ từ creator_fee. Một pool với creator_fee_rate = 1000 (0.10%) và trade_fee_rate = 2500 (0.25%) sẽ tính một khoản phí kết hợp 0.35% của đầu vào trong swap có creator-fee-on-input, trong đó nhà tạo giữ 0.10% và hạng mục trade-fee nhận 0.25%. Các tỷ lệ phí giao dịch (trade_fee_rate, protocol_fee_rate, fund_fee_rate) và creator_fee_rate đều nằm trên AmmConfig. Cờ enable_creator_fee cho mỗi pool và chế độ creator_fee_on (phía nào của giao dịch được tính phí nhà tạo) nằm trên PoolState. Xem products/cpmm/accounts.

Tỷ lệ và đơn vị

Tất cả tỷ lệ là u64s được biểu diễn bằng đơn vị 1 / FEE_RATE_DENOMINATOR trong đó FEE_RATE_DENOMINATOR = 1_000_000.
  • trade_fee_rate là một phân số của khối lượng swap. 2500 ⇒ 0.25% của phía liên quan (đầu vào hoặc đầu ra, tùy thuộc vào creator_fee_on — xem “Phía nào của giao dịch được tính phí” dưới đây).
  • creator_fee_rate là một phân số của khối lượng swap, được tính riêng biệt từ phí giao dịch. 1000 ⇒ 0.10% của phía liên quan.
  • protocol_fee_ratefund_fee_rate là các phân số của phí giao dịch, không phải của khối lượng. 120_000 ⇒ 12% của phí giao dịch.
Các tham số mặc định cho AmmConfig[index=0] (pool 0.25% “tiêu chuẩn”) trên mainnet, để tham khảo:
TrườngGiá trịTỷ lệ phần trăm hiệu dụng
trade_fee_rate25000.25% của khối lượng (hạng mục phí giao dịch)
protocol_fee_rate12000012% của phí giao dịch ≈ 0.030% của khối lượng
fund_fee_rate400004% của phí giao dịch ≈ 0.010% của khối lượng
creator_fee_rate0 (mặc định)0% (hạng mục riêng biệt)
→ Phần LP hiệu dụng0.210% của khối lượng
Vì vậy trên swap $1,000 với AmmConfig[0]enable_creator_fee = false: $2.50 tổng phí giao dịch, trong đó $2.10 ở lại với LP, $0.30 đi đến giao thức, $0.10 đến quỹ. Hạng mục nhà tạo là 0 vì phí nhà tạo bị vô hiệu hóa. Nếu cùng pool đó có enable_creator_fee = truecreator_fee_rate = 1000 (0.10%), người dùng thanh toán thêm $1.00 cho hạng mục nhà tạo — được tính trên phía giống như được cấu hình bởi creator_fee_on — để có $3.50 phí tổng cộng. Hạng mục phí giao dịch và các phần chia của nó cho giao thức/quỹ vẫn không thay đổi. Xác nhận các giá trị mainnet hiện tại với GET https://api-v3.raydium.io/main/cpmm-config — các tỷ lệ có thể thay đổi được bởi admin và nên được đọc tươi mới hơn là hardcoded.

Cách chia, dưới dạng code

// Paraphrased from raydium-cp-swap/programs/cp-swap/src/curve/{calculator,fees}.rs.
// The actual code branches on `is_creator_fee_on_input`; both branches preserve the
// invariant that creator_fee is its own rate, never a slice of trade_fee.

const FEE_RATE_DENOMINATOR_VALUE: u64 = 1_000_000;

pub struct FeeBreakdown {
    pub amount_in_after_fees: u64,    // input minus all fees taken on the input side
    pub amount_out_after_fees: u64,   // output minus any creator fee taken on the output side
    pub trade_fee:    u64,            // → split into LP / protocol / fund buckets below
    pub protocol_fee: u64,            // share of trade_fee
    pub fund_fee:     u64,            // share of trade_fee
    pub creator_fee:  u64,            // independent bucket (input or output side)
}

fn take_fees_on_input(
    amount_in: u64,
    trade_rate: u64,
    creator_rate: u64,
    protocol_rate: u64,
    fund_rate: u64,
) -> (u64 /* trade_fee */, u64 /* creator_fee */, u64 /* amount_in_after_fees */) {
    // The two rates are added so we round once on the combined fee, then split
    // proportionally — this is purely a rounding/efficiency trick. The split
    // honours the rates exactly: creator_fee/trade_fee == creator_rate/trade_rate.
    let total_fee = ((amount_in as u128) * ((trade_rate + creator_rate) as u128))
        .div_ceil(FEE_RATE_DENOMINATOR_VALUE as u128) as u64;

    let creator_fee = ((total_fee as u128) * (creator_rate as u128)
                       / ((trade_rate + creator_rate) as u128)) as u64;
    let trade_fee   = total_fee - creator_fee;

    (trade_fee, creator_fee, amount_in - total_fee)
}

fn take_creator_fee_on_output(amount_out_swapped: u64, creator_rate: u64) -> (u64, u64) {
    // When creator_fee_on routes the creator fee to the output side,
    // trade_fee is taken on input as a single rate, and creator_fee
    // is computed against the curve output.
    let creator_fee = ((amount_out_swapped as u128) * (creator_rate as u128))
        .div_ceil(FEE_RATE_DENOMINATOR_VALUE as u128) as u64;
    (amount_out_swapped - creator_fee, creator_fee)
}

fn split_trade_fee(
    trade_fee: u64,
    protocol_rate: u64,
    fund_rate: u64,
) -> (u64 /* protocol_fee */, u64 /* fund_fee */) {
    let protocol_fee = (trade_fee as u128 * protocol_rate as u128
                        / FEE_RATE_DENOMINATOR_VALUE as u128) as u64;
    let fund_fee     = (trade_fee as u128 * fund_rate as u128
                        / FEE_RATE_DENOMINATOR_VALUE as u128) as u64;
    (protocol_fee, fund_fee)
}
Ghi chú:
  • Tổng phí trên đầu vào làm tròn lên để pool không bao giờ tính phí thấp hơn.
  • Các phân chia phụ của trade_fee (giao thức, quỹ) làm tròn xuống để tổng của chúng không bao giờ vượt quá trade_fee; phần còn lại là phần LP.
  • lp_share = trade_fee − protocol_fee − fund_fee (creator_fee không bị trừ ở đây vì nó là hạng mục riêng).
  • Phí nhà tạo được tính từ đầu vào hoặc đầu ra tùy thuộc vào PoolState.creator_fee_on (xem phần tiếp theo). Tỷ lệ không thay đổi dù là trường hợp nào.

Phía nào của giao dịch được tính phí

CPMM có cài đặt creator_fee_on cho mỗi pool (BothToken / OnlyToken0 / OnlyToken1) xác định liệu phí nhà tạo được tính từ phía đầu vào hay đầu ra của một swap nhất định. Hàm trợ giúp runtime is_creator_fee_on_input(direction) rút gọn điều đó thành một boolean cho mỗi swap:
creator_fee_onSwap 0 → 1Swap 1 → 0
BothToken (0)phía đầu vàophía đầu vào
OnlyToken0 (1)phía đầu vàophía đầu ra
OnlyToken1 (2)phía đầu raphía đầu vào
Khi phí nhà tạo ở phía đầu vào, cả phí giao dịch và phí nhà tạo đều được trừ từ amount_in trước khi đường cong chạy. Toán học trích dẫn: lấy trade_rate + creator_rate kết hợp từ đầu vào. Khi phí nhà tạo ở phía đầu ra, chỉ có phí giao dịch được trừ từ amount_in; đường cong tạo ra một đầu ra chưa tính phí, sau đó phí nhà tạo được trừ từ đầu ra đó. Toán học trích dẫn: lấy trade_rate từ đầu vào; lấy creator_rate từ đầu ra. Phí giao dịch tự nó luôn được tính từ phía đầu vào (mô hình tiêu chuẩn Uniswap-V2). Chỉ phí nhà tạo mới có thể ở phía đầu ra.

Cách các phí “tích lũy” tương tác với đường cong

Một chi tiết quan trọng: phí giao thức, quỹ và nhà tạo vẫn nằm vật lý trong vault cho đến khi lệnh Collect* tương ứng được gọi. Nhưng chúng bị loại khỏi khung nhìn của đường cong đối với số dư vault. Một hình ảnh cụ thể sau một swap:
raw_vault_0_balance = getTokenAccountBalance(vault_0).amount
                    = lp_entitled + protocol_fees_token0
                      + fund_fees_token0 + creator_fees_token0

curve_x = raw_vault_0_balance − (protocol_fees_token0
                                  + fund_fees_token0
                                  + creator_fees_token0)
Chương trình sử dụng curve_x (và curve_y tương tự) khi thực thi k' ≥ k. Đây là cách các phí không phải LP đạt đến các địa chỉ đích mà không làm tăng phần LP của pool. Hậu quả bạn nên thiết kế xung quanh:
  • Trích dẫn từ số dư thô là sai. Nếu bạn xây dựng một quoter từ getTokenAccountBalance, bạn sẽ liên tục nêu quá cao giá mà pool sẽ chấp nhận. Luôn trừ các phí tích lũy, hoặc mô phỏng qua SwapBaseInput / API.
  • CollectProtocolFee không di chuyển giá. Nó di chuyển token ra khỏi vault làm không các bộ đếm protocol_fees_token*, nên curve_xcurve_y không thay đổi.
  • Phí LP không tích lũy vào một bộ đếm. Chúng ngầm trong số dư vault. Quyền của LP đối với phí LP tích lũy được thực hiện bằng cách đốt token LP (tức là qua Withdraw) — không có CollectLpFee.

Tương tác với phí chuyển Token-2022

Phí chuyển Token-2022 được áp dụng bởi mint, không phải bởi CPMM. Chúng tác dụng trên mọi chuyển token — swap, gửi, rút và các lần rút Collect*. Toán học phí giao dịch của CPMM được tính dựa trên số tiền thực sự hạ cánh trong vault, tức là ròng theo phí chuyển của mint đầu vào (nếu có). Vì vậy trong trường hợp tồi tệ nhất, người dùng trả ba khoản thuế riêng biệt trên swap input-exact:
  1. Phí chuyển của mint đầu vào trên amount_in (cho nhà cung cấp phí của mint).
  2. trade_fee của pool trên phần còn lại (chia như trên).
  3. Phí chuyển của mint đầu ra trên amount_out (cho nhà cung cấp phí của mint).
Quoter của SDK tính tất cả ba cái nên minimum_amount_out được biểu diễn bằng những gì người dùng thực sự nhận được. Nếu bạn đang viết quoter của riêng bạn, hãy phản chiếu hành vi đó, nếu không các kiểm tra slippage của bạn sẽ thường xuyên quá hào phóng. Xem algorithms/token-2022-transfer-fees để biết tính đạo hàm chi tiết.

Phí nhà tạo

Phí nhà tạo là tùy chọn và cho mỗi pool. Tỷ lệ nằm trên AmmConfig.creator_fee_rate; cờ bậtphía (creator_fee_on) nằm trên PoolState:
  • Bật tại tạo pool. Initialize đặt enable_creator_fee = false theo mặc định; các pool được tạo qua InitializeWithPermission (được sử dụng bởi các tốt nghiệp LaunchLab và các đường dẫn được cấu hình khác) có thể chuyển enable_creator_fee = true và chọn creator_fee_on.
  • Tỷ lệ được chia sẻ với tiers phí. Tỷ lệ tự nó là AmmConfig.creator_fee_rate, giá trị giống nhau trên mọi pool gắn với config đó. Mỗi pool sau đó quyết định có tính nó (enable_creator_fee) và phía nào của swap để tính nó (creator_fee_on). Khi enable_creator_fee = false, tỷ lệ phí nhà tạo hiệu dụng của pool là không có gì bất kể giá trị config (xem PoolState::adjust_creator_fee_rate trong source).
  • Độc lập với phí giao dịch. Phí nhà tạo không bao giờ giảm các phần LP / giao thức / quỹ — nó là tỷ lệ riêng, được áp dụng riêng, tích lũy trong các bộ đếm riêng.
  • Được rút qua CollectCreatorFee, ký bởi PoolState.pool_creator.
  • Không thể được bật lại hoặc định tuyến lại sau tạo. Một pool được khởi tạo với enable_creator_fee = false sẽ không bao giờ tính phí nhà tạo; một pool được khởi tạo với creator_fee_on cụ thể không thể chuyển đổi phía.
Phí nhà tạo là cơ chế đằng sau mô hình “Burn & Earn” của Raydium: token LP được khóa dưới chương trình LP Lock vì vậy nhà tạo không thể rút thanh khoản, nhưng vẫn có thể yêu cầu CollectCreatorFee vô thời hạn.

Luồng hoạt động bộ sưu tập

Người kýLệnhCác bộ đếm nguồn được làm khôngTần suất điển hình
amm_config.protocol_ownerCollectProtocolFeeprotocol_fees_token{0,1}Hàng tuần hoặc lập trình
amm_config.fund_ownerCollectFundFeefund_fees_token{0,1}Hàng tuần hoặc lập trình
pool_state.pool_creatorCollectCreatorFeecreator_fees_token{0,1}Bất cứ lúc nào
Chủ sở hữu giao thức và quỹ là multisig Raydium trên mainnet; xem security/admin-and-multisig. Người ký nhà tạo là tài khoản đã chạy Initialize.

Thay đổi một tiers phí

Các tỷ lệ phí có thể được thay đổi bởi admin thông qua UpdateAmmConfig (xem products/cpmm/instructions). Các thay đổi có hiệu lực trên swap tiếp theo cho mọi pool gắn với AmmConfig đó — không có di chuyển, vì các pool tải config trên mỗi swap. Những gì admin không thể làm:
  • Di chuyển một pool từ AmmConfig này sang AmmConfig khác.
  • Tính giá lại các phí đã tích lũy.
  • Sưu tập phí mà không có protocol_owner / fund_owner signer.

Đọc phí từ một pool đang chạy

// Off-chain: current accrued fees in each bucket
const pool = await connection.getAccountInfo(poolStatePda);
const decoded = PoolState.decode(pool.data);
console.log(
  "Protocol accrued:",
  decoded.protocolFeesToken0.toString(),
  decoded.protocolFeesToken1.toString(),
);
console.log(
  "Fund accrued:",
  decoded.fundFeesToken0.toString(),
  decoded.fundFeesToken1.toString(),
);
console.log(
  "Creator accrued:",
  decoded.creatorFeesToken0.toString(),
  decoded.creatorFeesToken1.toString(),
);

// Off-chain: effective rates today.
// trade_fee_rate, creator_fee_rate are fractions of volume (denominator 1e6).
// protocol_fee_rate, fund_fee_rate are fractions of the *trade fee* (same denominator).
const config = await fetch("https://api-v3.raydium.io/main/cpmm-config")
  .then((r) => r.json());
const tier = config.data.find((t) => t.index === decoded.ammConfigIndex);

const tradeFeeOfVolume   = tier.tradeFeeRate / 1_000_000;
const protocolOfTradeFee = tier.protocolFeeRate / 1_000_000;
const fundOfTradeFee     = tier.fundFeeRate / 1_000_000;
const lpOfTradeFee       = 1 - protocolOfTradeFee - fundOfTradeFee;

console.log("LP fee effective:",       (tradeFeeOfVolume * lpOfTradeFee * 100).toFixed(4), "%");
console.log("Protocol fee effective:", (tradeFeeOfVolume * protocolOfTradeFee * 100).toFixed(4), "%");
console.log("Fund fee effective:",     (tradeFeeOfVolume * fundOfTradeFee * 100).toFixed(4), "%");
console.log(
  "Creator fee effective:",
  decoded.enableCreatorFee
    ? ((tier.creatorFeeRate / 1_000_000) * 100).toFixed(4) + " %"
    : "0 % (disabled on this pool)",
);

So sánh với CLMM và AMM v4

Xem reference/fee-comparison để xem ma trận so sánh cạnh-nhau. Tóm tắt:
  • AMM v4 sử dụng phí giao dịch cố định 0.25% với một phân chia LP/giao thức khác và không có phí quỹ.
  • CLMM phí là cho mỗi tiers khoảng cách tick, tích lũy cho mỗi vị trí (không phải cho mỗi pool), và được yêu cầu qua DecreaseLiquidity hoặc CollectFees.

Đi đến đâu tiếp theo

Nguồn: