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 →
Biểu diễn căn bậc hai của giá
CLMM lưu trữ giá dưới dạngsqrt_price_x64 — căn bậc hai của giá token1 trên token0, được biểu diễn dưới dạng số cố định Q64.64:
trong đó p = token1_amount / token0_amount. Việc làm việc với sqrt thay vì p tuyến tính hóa toán học swap (những thay đổi lượng token trở thành tuyến tính theo Δsqrt_price), và số cố định x64 duy trì độ chính xác qua nhiều lần swap qua các tick.
Chuyển đổi giữa Tick ↔ căn bậc hai của giá được tính toán trước thông qua xấp xỉ logarithm bit-by-bit:
được thực hiện dưới dạng phép tính mũ dựa trên bảng tra cứu trong tick_math::get_sqrt_price_at_tick.
Liquidity như một đơn vị chính
Bên trong một phạm vi[sqrt_a, sqrt_b] (với sqrt_a < sqrt_b), một vị trí có liquidity L ánh xạ tới các lượng token như sau. Gọi sqrt_c = sqrt_price_x64 là giá hiện tại của pool.
| Trường hợp | amount0 | amount1 |
|---|---|---|
sqrt_c <= sqrt_a (giá pool dưới phạm vi) | L · (sqrt_b - sqrt_a) / (sqrt_a · sqrt_b) | 0 |
sqrt_a < sqrt_c < sqrt_b (trong phạm vi) | L · (sqrt_b - sqrt_c) / (sqrt_c · sqrt_b) | L · (sqrt_c - sqrt_a) |
sqrt_c >= sqrt_b (giá pool trên phạm vi) | 0 | L · (sqrt_b - sqrt_a) |
x = L / sqrt_p, y = L · sqrt_p mà liquidity tập trung thỏa mãn trong một phạm vi.
Những người tích hợp thường muốn phép nghịch đảo: có một khoản gửi amount0 / amount1, hãy tính L tối đa phù hợp với phạm vi. SDK của LiquidityMath.getLiquidityFromTokenAmounts thực hiện điều này. Công thức cho trường hợp trong phạm vi:
Phía nào bị ràng buộc sẽ quyết định tỷ lệ thực tế được tiêu thụ; phía còn lại có thể có dư.
Bước swap theo tick đơn
Một swap tiến hành theo các bước. Mỗi bước hoặc (a) tiêu thụ tất cả các khoản nhập liệu khả dụng trong phạm vi tick hiện tại mà không vượt qua một tick, hoặc (b) di chuyển giá đến chính xác tick được khởi tạo tiếp theo. Cho trạng thái hiện tại(sqrt_c, L) và swap lên (token0 vào, token1 ra, sqrt_price tăng), khoảng cách đến tick được khởi tạo tiếp theo là sqrt_t. Bên trong khoảng nhỏ này, mối quan hệ giữa đầu vào và giá là:
và
Chương trình thực hiện một trong hai điều:
-
Toàn bộ đầu vào có phù hợp không? Nếu đầu vào còn lại (sau khi trừ phí) nhỏ hơn
Δamount0để đạtsqrt_t, hãy giải quyết chosqrt_c'mới chính xác: (cho một swaptoken0 → token1với đầu vào chính xác). Swap kết thúc trong bước này mà không vượt qua một tick. -
Đầu vào vượt quá
Δamount0? Đặtsqrt_c' = sqrt_t, vượt qua tick (áp dụngliquidity_net), giảm đầu vào còn lại bởiΔamount0, tăng đầu ra bởiΔamount1, và lặp lại.
token1 → token0, giá giảm), các công thức có sqrt_c và sqrt_t được hoán đổi và phép nghịch đảo ở vị trí khác.
Việc triển khai Rust đầy đủ nằm trong raydium-clmm/programs/amm/src/libraries/swap_math.rs. Logic ở đó khớp với SwapMath.computeSwapStep của Uniswap v3 một cách chính xác.
Phí trên mỗi bước
Phí giao dịch được lấy từ lượng đầu vào trong mỗi bước, cùng quy ước với CPMM:L_i vẫn trong phạm vi trong suốt swap này sẽ sau đó đọc lại L_i · Δfee_growth_global / 2^{64} token phải trả.
Các phần protocol và fund tích lũy vào PoolState.protocol_fees_token_{0,1} và PoolState.fund_fees_token_{0,1} tương ứng, giống hệt như CPMM. Chúng được quét bởi CollectProtocolFee / CollectFundFee.
Phí tích lũy bên ngoài và bên trong
Phần phức tạp của tính toán phí CLMM: một vị trí chỉ kiếm được phí khi giá của pool bên trong phạm vi của nó. Pool theo dõi các phí tích lũy toàn cầu; vị trí cần phải biết các phí tích lũy khi bên trong phạm vi cụ thể của nó. Giải pháp là một bộ tích lũy dựa trên tick. Mỗi tick lưu trữ:- Nếu giá của pool trên tick này (
tick_current >= this_tick),fee_growth_outside = fee_growth_global. (Tất cả những phí kiếm được cho đến nay là “bên ngoài” — hay nói cách khác, dưới — tick này, so với giá hiện tại.) - Nếu không thì
fee_growth_outside = 0.
fee_growth_outside của tick đó:
Bất biến mà điều này bảo toàn: đối với bất kỳ tick t nào, fee_growth_outside(t) bằng các phí tích lũy khi tick_current ở phía đối diện của t.
Phí tích lũy bên trong một phạm vi [tick_lower, tick_upper] được suy ra:
Một vị trí lưu trữ gì và nó đọc gì
PersonalPositionState lưu trữ fee_growth_inside_0_last_x64 và fee_growth_inside_1_last_x64: các giá trị fee_growth_inside vào lần cuối cùng vị trí được chạm đến.
Trong bất kỳ lần chạm tiếp theo nào (tăng, giảm, thu thập), chương trình:
- Tính toán
fee_growth_inside_{0,1}_x64hiện tại bằng công thức trên. - Tính toán
Δ = fee_growth_inside_now − fee_growth_inside_last(trừ môđun trên u128). - Thêm
Δ × position.liquidity / 2^{64}vàotokens_fees_owed_{0,1}. - Cập nhật
fee_growth_inside_lastthành giá trị mới.
CollectFees / DecreaseLiquidity, dựa trên tokens_fees_owed.
Phần thưởng
Mỗi luồng phần thưởng của pool (tối đa 3 luồng) sử dụng cơ chế tăng trưởng-bên-trong giống nhau, trong bộ tích lũyreward_growth_global_x64 của chính nó. Vào lúc phát hành:
— các phát hành tỷ lệ nghịch với liquidity hoạt động, vì vậy một pool dày đặc trả cho mỗi vị trí ít hơn mỗi giây, nhưng trên nhiều vị trí hơn. Phần thưởng mỗi vị trí phải trả là
và được yêu cầu thông qua CollectReward. Xem products/clmm/fees.
Ví dụ thực tế: swap với đầu vào chính xác
Giả sử:tick_spacing = 60sqrt_price_x64 = 1 × 2^{64}— giá = 1.0, vì vậytick_current = 0.- Liquidity hoạt động
L = 1_000_000 × 2^{64}. - Tick được khởi tạo tiếp theo phía trên:
t = 60(sqrt_price_b ≈1.003004 × 2^{64}). - Tỷ lệ phí giao dịch: 500 (0.05%).
SwapBaseInput với đầu vào chính xác 1,000 token0.
Bước 1 — phí:
999 < 2995.5, vì vậy toàn bộ đầu vào phù hợp mà không vượt qua tick.
Bước 3 — giá mới:
sqrt_c' hơi dưới sqrt_c. Lưu ý rằng công thức trên là cho một swap token1 → token0. Ví dụ ở đây là token0 → token1, điều này đẩy giá lên, không phải xuống — vì vậy chúng ta sử dụng dạng tương ứng cho token0 vào:
token0 → token1: sqrt_c tăng cùng với giá.)
Bước 4 — lượng ra:
trade_fee_rate × protocol_fee_rate / 1e6 (và tương tự cho fund); phần LP chảy vào fee_growth_global_0_x64.
Khớp lệnh giới hạn trong quá trình swap
Khi một bước swap vượt qua một tick mà có các lệnh giới hạn mở, những lệnh đó tiêu thụ đầu vào swap trước đường cong LP thực hiện, ở mức giá chính xác của tick. Khớp là FIFO trong tick theo bộ cohortorder_phase.
Trạng thái mỗi bộ cohort trên TickState
orders_amount và kế thừa order_phase tiếp theo; chúng không thể điền cho đến khi bộ cohort trước đó được tiêu thụ hoàn toàn.
Bước khớp
Mã giả cho khớp xảy ra ở mỗi lần vượt qua tick trong quá trình swap:SettleLimitOrder (hoặc DecreaseLimitOrder). Pool chỉ đơn giản theo dõi bao nhiêu phần của bộ cohort được điền đầy thông qua unfilled_ratio_x64. Mỗi LimitOrderState lưu trữ ảnh chụp (order_phase, unfilled_ratio_x64) của riêng nó vào thời điểm mở, vì vậy quyết toán rút gọn thành:
Tương tác với đường cong LP
Trong một bước swap, khớp lệnh giới hạn xảy ra tại tick (khôngΔsqrt_price); tiêu thụ đường cong LP xảy ra giữa các tick. Thứ tự do đó:
- Vượt qua tick
t_cross(áp dụng thay đổi LPliquidity_nettrước tiên, vì đây là cách Uniswap-V3 thực hiện). - Điền các lệnh giới hạn nằm ở
t_cross. - Tiếp tục dọc theo đường cong LP đến tick được khởi tạo tiếp theo hoặc đến việc
swap_inputbị cạn kiệt.
Suy dẫn phí động
PoolState.dynamic_fee_info mang lại trạng thái biến động. Mỗi bước swap tính toán tỷ lệ phí mỗi bước là:
trong đó:
- —
DYNAMIC_FEE_CONTROL_DENOMINATOR - —
VOLATILITY_ACCUMULATOR_SCALE vol_acclà bộ tích lũy mỗi swap sau khi quy tắc cập nhật dưới đâytick_spacingtừPoolState.tick_spacing
Cập nhật bộ tích lũy
Hai quy tắc được áp dụng mỗi swap, theo thứ tự: Phân rã. Mức sàn tham chiếu phân rã dựa trên thời gian kể từ lần cập nhật cuối: Tích lũy. Bộ tích lũy mới là tham chiếu cộng với khoảng cách tick được duyệt qua kể từ chỉ số tham chiếu trước đó:tick_spacing_index_reference () tính bằng đơn vị tick-spacing, không phải tick thô: .
Tại sao lại parabol về khoảng cách tick
Bình phương bộ tích lũy có nghĩa là phí tăng lên theo bình phương của khoảng cách giá đã đi từ điểm tham chiếu của nó. Thực nghiệm điều này khớp với tỷ lệ phương sai của giá dưới áp lực đi bộ ngẫu nhiên: một phöng đi 2 lần tick ngụ ý 4 lần biến động ngụ ý, vì vậy tính phí 4 lần phụ phí. Tham sốdynamic_fee_control hiệu chỉnh mức tuyệt đối.
Cửa sổ filter_period ngăn chặn các dao động cực nhỏ dưới một giây (ví dụ: bot MEV sandwich) khỏi làm tăng bộ tích lũy. Cửa sổ decay_period ngăn chặn một xung tăng đột ngột trong quá khứ khỏi việc tính phí vô hạn sau khi thị trường đã bình tĩnh.
Mạnh mẽ về mặt số học
- Tất cả các sản phẩm trung gian đi qua số học hình dạng
u128hoặcu256. CLMM sử dụng các trợ giúpU128Sqrtvà các mẫuFullMath::mulDivđược chuyển cổng trực tiếp từ Uniswap v3. - Làm tròn phép chia được chọn mỗi bước để thực thi bất biến
k' ≥ kcục bộ.SwapBaseInputlàm tròn đầu ra xuống;SwapBaseOutputlàm tròn đầu vào lên. - Những lần vượt qua tick làm giảm
PoolState.liquidityvề 0 được cho phép (giá có thể duyệt qua một “lỗ liquidity”) nhưng swap chỉ đơn giản nâng cao đến tick được khởi tạo tiếp theo mà không tiêu thụ đầu vào, không tính phí. - Bảo vệ tràn:
sqrt_price_x64được giữ trong phạm vi bao gồm[MIN_SQRT_PRICE_X64, MAX_SQRT_PRICE_X64]tương ứng với[MIN_TICK, MAX_TICK]. Một swap sẽ đẩy quá bất kỳ ranh giới nào hoàn tác vớiSqrtPriceLimitOverflow.
Tiếp theo đi đâu
products/clmm/ticks-and-positionscho cách bản đồ tick tham gia vào lần đi bộ.products/clmm/feescho phía phí/phần thưởng của toán học chi tiết.algorithms/clmm-mathcho các suy dẫn đằng sauL = sqrt(x · y)và các công thức phạm vi so với liquidity.
raydium-io/raydium-clmm—libraries/swap_math.rs,libraries/tick_math.rs- “Uniswap v3 Core” whitepaper, §6–7


