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.
Halaman ini diterjemahkan secara otomatis oleh AI. Versi bahasa Inggris adalah acuan resmi.Lihat versi bahasa Inggris →
Representasi sqrt-price
CLMM menyimpan harga sebagaisqrt_price_x64 — akar kuadrat dari harga token1-per-token0, sebagai angka fixed-point Q64.64:
di mana p = token1_amount / token0_amount. Bekerja dalam sqrt daripada p melinierkan matematika swap (delta jumlah token menjadi linear dalam Δsqrt_price), dan fixed-point x64 mempertahankan presisi melalui swap multi-tick.
Konversi tick ↔ sqrt-price diperhitungkan sebelumnya melalui pendekatan log bit-by-bit:
diimplementasikan sebagai eksponensisasi berbasis lookup dalam tick_math::get_sqrt_price_at_tick.
Likuiditas sebagai satuan kanonik
Di dalam range[sqrt_a, sqrt_b] (dengan sqrt_a < sqrt_b) sebuah posisi dengan likuiditas L memetakan ke jumlah token sebagai berikut. Misalkan sqrt_c = sqrt_price_x64 adalah harga pool saat ini.
| Kasus | amount0 | amount1 |
|---|---|---|
sqrt_c <= sqrt_a (harga pool di bawah range) | L · (sqrt_b - sqrt_a) / (sqrt_a · sqrt_b) | 0 |
sqrt_a < sqrt_c < sqrt_b (dalam range) | L · (sqrt_b - sqrt_c) / (sqrt_c · sqrt_b) | L · (sqrt_c - sqrt_a) |
sqrt_c >= sqrt_b (harga pool di atas range) | 0 | L · (sqrt_b - sqrt_a) |
x = L / sqrt_p, y = L · sqrt_p yang dipenuhi likuiditas terkonsentrasi dalam sebuah range.
Umumnya integrator menginginkan sebaliknya: diberikan deposit amount0 / amount1, hitung L maksimum yang sesuai dalam range. LiquidityMath.getLiquidityFromTokenAmounts di SDK melakukan ini. Rumus untuk kasus dalam range:
Sisi mana yang mengikat menentukan rasio yang sebenarnya dikonsumsi; sisi lainnya mungkin memiliki sisa.
Langkah swap satu tick
Swap dilakukan dalam langkah-langkah. Setiap langkah baik (a) mengonsumsi semua input yang tersedia dalam range tick saat ini tanpa melintasi tick, atau (b) memindahkan harga tepat ke tick terinisialisasi berikutnya. Diberikan state saat ini(sqrt_c, L) dan swap naik (token0 masuk, token1 keluar, sqrt_price meningkat), jarak ke tick terinisialisasi berikutnya adalah sqrt_t. Di dalam micro-interval ini hubungan antara input dan harga adalah:
dan
Program melakukan satu dari dua hal:
-
Apakah seluruh input sesuai? Jika input yang tersisa (setelah fee) kurang dari
Δamount0untuk mencapaisqrt_t, selesaikansqrt_c'dengan tepat: (untuk swap exact-inputtoken0 → token1). Swap selesai dalam langkah ini tanpa melintasi tick. -
Input melebihi
Δamount0? Atursqrt_c' = sqrt_t, lintasi tick (terapkanliquidity_net), kurangi input yang tersisa sebesarΔamount0, tingkatkan output sebesarΔamount1, dan ulangi.
token1 → token0, harga turun), rumusnya memiliki sqrt_c dan sqrt_t ditukar dan inversi di slot lainnya.
Implementasi Rust lengkap terdapat dalam raydium-clmm/programs/amm/src/libraries/swap_math.rs. Logika di sana cocok persis dengan SwapMath.computeSwapStep Uniswap v3.
Biaya di setiap langkah
Biaya perdagangan diambil dari jumlah input di setiap langkah, konvensi yang sama dengan CPMM:L_i yang tetap dalam range di seluruh swap ini akan kemudian membaca kembali L_i · Δfee_growth_global / 2^{64} token yang dihutangkan.
Porsi protokol dan dana terakumulasi ke PoolState.protocol_fees_token_{0,1} dan PoolState.fund_fees_token_{0,1} masing-masing, identik dengan CPMM. Mereka dikumpulkan oleh CollectProtocolFee / CollectFundFee.
Fee growth di luar dan di dalam
Bagian rumit dari akuntansi fee CLMM: posisi mendapatkan biaya hanya saat harga pool berada dalam range-nya. Pool melacak biaya kumulatif secara global; posisi perlu tahu biaya kumulatif saat dalam range spesifiknya. Solusinya adalah akumulator berbasis tick. Setiap tick menyimpan:- Jika harga pool berada di atas tick ini (
tick_current >= this_tick),fee_growth_outside = fee_growth_global. (Semua yang diperoleh sejauh ini adalah “di luar” — yaitu, di bawah — tick ini, relatif terhadap harga saat ini.) - Sebaliknya
fee_growth_outside = 0.
fee_growth_outside tick itu:
Invarian yang ini pertahankan: untuk tick t apa pun, fee_growth_outside(t) sama dengan biaya yang terakumulasi saat tick_current berada di sisi berlawanan dari t.
Fee growth di dalam range [tick_lower, tick_upper] kemudian diturunkan:
Apa yang disimpan posisi dan apa yang dibacanya
PersonalPositionState menyimpan fee_growth_inside_0_last_x64 dan fee_growth_inside_1_last_x64: nilai fee_growth_inside pada waktu terakhir posisi disentuh.
Pada setiap sentuhan berikutnya (increase, decrease, collect), program:
- Menghitung
fee_growth_inside_{0,1}_x64saat ini menggunakan rumus di atas. - Menghitung
Δ = fee_growth_inside_now − fee_growth_inside_last(pengurangan modular pada u128). - Menambahkan
Δ × position.liquidity / 2^{64}ketokens_fees_owed_{0,1}. - Memperbarui
fee_growth_inside_lastke nilai baru.
CollectFees / DecreaseLiquidity, melawan tokens_fees_owed.
Reward
Setiap dari hingga 3 aliran reward pool menggunakan mekanik growth-inside yang sama, dalam akumulatorreward_growth_global_x64-nya sendiri. Pada waktu emisi:
— emisi skala terbalik dengan likuiditas aktif, sehingga pool yang lebih padat membayar setiap posisi secara proporsional lebih sedikit per detik, tetapi di atas lebih banyak posisi total. Reward per-posisi yang dihutangkan adalah
dan diklaim melalui CollectReward. Lihat products/clmm/fees.
Contoh kerja: swap exact-input
Anggaplah:tick_spacing = 60sqrt_price_x64 = 1 × 2^{64}— harga = 1.0, jaditick_current = 0.- Likuiditas aktif
L = 1_000_000 × 2^{64}. - Tick terinisialisasi berikutnya di atas:
t = 60(sqrt_price_b ≈1.003004 × 2^{64}). - Tingkat biaya perdagangan: 500 (0,05%).
SwapBaseInput exact-input 1.000 token0.
Langkah 1 — biaya:
999 < 2995.5, jadi seluruh input sesuai tanpa melintasi tick.
Langkah 3 — harga baru:
sqrt_c' sedikit di bawah sqrt_c. Perhatikan bahwa rumus di atas adalah untuk swap token1 → token0. Contoh di sini adalah token0 → token1, yang mendorong harga naik, bukan turun — jadi kami menggunakan bentuk yang sesuai untuk token0 in:
token0 → token1: sqrt_c naik seiring dengan harga.)
Langkah 4 — jumlah keluar:
trade_fee_rate × protocol_fee_rate / 1e6 (dan serupa untuk dana); porsi LP mengalir ke fee_growth_global_0_x64.
Pencocokan limit order selama swap
Ketika langkah swap melintasi tick yang memegang limit order terbuka, pesanan tersebut mengonsumsi input swap sebelum kurva LP, pada harga tepat tick. Pencocokan adalah FIFO dalam tick menurut cohortorder_phase.
State per-cohort pada TickState
orders_amount dan mewarisi order_phase berikutnya; mereka tidak dapat mengisi sampai cohort sebelumnya sepenuhnya dikonsumsi.
Langkah pencocokan
Pseudo-code untuk pencocokan yang terjadi pada setiap persilangan tick selama swap:SettleLimitOrder (atau DecreaseLimitOrder). Pool hanya melacak berapa banyak cohort yang sekarang terisi melalui unfilled_ratio_x64. Setiap LimitOrderState menyimpan snapshot (order_phase, unfilled_ratio_x64) sendiri pada waktu terbuka, jadi penyelesaian berkurang menjadi:
Interaksi dengan kurva LP
Dalam langkah swap, pencocokan limit order terjadi pada tick (zeroΔsqrt_price); konsumsi kurva LP terjadi antara ticks. Urutan-nya adalah:
- Lintasi tick
t_cross(terapkan perubahan LPliquidity_netterlebih dahulu, karena ini cara Uniswap-V3 melakukannya). - Isi limit order apa pun yang duduk di
t_cross. - Lanjutkan sepanjang kurva LP ke tick terinisialisasi berikutnya atau ke exhaustion
swap_input.
Derivasi dynamic fee
PoolState.dynamic_fee_info membawa state volatilitas. Setiap langkah swap menghitung tingkat biaya per-langkah sebagai:
di mana:
- —
DYNAMIC_FEE_CONTROL_DENOMINATOR - —
VOLATILITY_ACCUMULATOR_SCALE vol_accadalah akumulator per-swap setelah peraturan update di bawahtick_spacingadalah dariPoolState.tick_spacing
Pembaruan akumulator
Dua peraturan diterapkan setiap swap, berurutan: Decay. Lantai referensi meluruh berdasarkan waktu sejak update terakhir: Accumulate. Akumulator baru adalah referensi ditambah jarak tick yang ditempuh sejak indeks referensi sebelumnya:tick_spacing_index_reference () berada dalam unit tick-spacing, bukan raw ticks: .
Mengapa parabola dalam jarak tick
Mengkuadratkan akumulator berarti biaya naik sebagai kuadrat seberapa jauh harga telah berjalan dari titik referensinya. Secara empiris ini cocok dengan volatilitas scaling dari harga di bawah tekanan random-walk: excursion tick 2× menyiratkan 4× implied volatility, jadi mengenakan 4× surcharge. Parameterdynamic_fee_control kalibrasi level absolut.
Jendela filter_period mencegah osilasi sub-detik kecil (misalnya, bot MEV sandwiching) dari menginflasi akumulator. Jendela decay_period mencegah spike masa lalu tunggal dari mengenakan biaya tanpa batas setelah pasar tenang.
Robustness numerik
- Semua produk perantara melalui aritmetika bentuk
u128atauu256. CLMM menggunakan helperU128Sqrtdan polaFullMath::mulDivyang diporte langsung dari Uniswap v3. - Pembulatan divisi dipilih per-langkah untuk menegakkan invarian
k' ≥ ksecara lokal.SwapBaseInputmembulatkan output ke bawah;SwapBaseOutputmembulatkan input ke atas. - Persilangan tick yang menjatuhkan
PoolState.liquidityke nol diizinkan (harga dapat melintasi “liquidity hole”) tetapi swap hanya maju ke tick terinisialisasi berikutnya tanpa mengonsumsi input, tidak mengenakan biaya. - Overflow guard:
sqrt_price_x64disimpan dalam range inklusif[MIN_SQRT_PRICE_X64, MAX_SQRT_PRICE_X64]yang sesuai dengan[MIN_TICK, MAX_TICK]. Swap yang akan mendorong melampaui salah satu batas kembali denganSqrtPriceLimitOverflow.
Ke mana selanjutnya
products/clmm/ticks-and-positionsuntuk bagaimana peta tick berpartisipasi dalam jalan.products/clmm/feesuntuk sisi fee/reward matematika secara detail.algorithms/clmm-mathuntuk derivasi di balikL = sqrt(x · y)dan rumus range-vs-liquidity.
raydium-io/raydium-clmm—libraries/swap_math.rs,libraries/tick_math.rs- “Uniswap v3 Core” whitepaper, §6–7


