Skip to main content
Halaman ini diterjemahkan secara otomatis oleh AI. Versi bahasa Inggris adalah acuan resmi.Lihat versi bahasa Inggris →

Mengapa ticks ada

Likuiditas CLMM terkonsentrasi dalam rentang harga. Untuk membuat rentang dapat ditangani on-chain, harga dikuantisasi menjadi integer ticks, di mana setiap tick adalah kelipatan konstan dari yang sebelumnya: price(i)=1.0001i\text{price}(i) = 1.0001^{\,i} Satu tick sesuai dengan pergerakan harga 0,01%, atau ~1 basis poin. Pemetaannya adalah: MIN_TICK dan MAX_TICK dipilih sehingga sqrt_price_x64 sesuai dalam u128 di kedua ujung. Setiap pool memberlakukan bahwa tick_lower >= MIN_TICK dan tick_upper <= MAX_TICK. Dalam praktiknya, UI web membatasi rentang ke sesuatu yang jauh lebih sempit untuk mencegah pengguna mengunci likuiditas ke ticks yang tidak dapat dijangkau.

Tick spacing

AmmConfig pool menetapkan tick spacing — satu-satunya ticks yang diizinkan posisi gunakan sebagai endpoint. Jika tick_spacing = 60, hanya ticks …, −120, −60, 0, 60, 120, … yang valid. Upaya membuka posisi dengan endpoint 31 akan kembali dengan InvalidTickIndex. Spacing yang dipublikasikan secara umum: Semakin kasar spacing-nya, semakin sedikit tick arrays yang perlu diinisialisasi, semakin murah untuk membuka posisi yang lebar, dan semakin kabur batas harganya. Pasangan yang volatil biasanya berada di tier spacing 120; stablecoin berada di tier spacing 1.

Tick arrays

Pool tidak menyimpan status per-tick dalam akun terpisah. Sebaliknya, TICK_ARRAY_SIZE ticks yang berdekatan (60 dalam CLMM Raydium saat ini) dikemas ke dalam satu TickArrayState. Array pertama tick adalah start_tick_index-nya, dan mencakup tepat TICK_ARRAY_SIZE * tick_spacing unit integer-tick. Untuk tick_spacing = 60 dan TICK_ARRAY_SIZE = 60:
  • Setiap tick array mencakup 60 × 60 = 3600 integer ticks.
  • start_tick_index adalah kelipatan 3600: …, -7200, -3600, 0, 3600, 7200, ….
Endpoint posisi t = 2040 pada tick_spacing = 60 berada di tick array dengan start_tick_index = 0. Endpoint posisi t = 4200 berada di array dengan start_tick_index = 3600.

Ketika array diinisialisasi

Tick array adalah lazy: posisi pertama yang mereferensikan tick apa pun di dalamnya menginisialisasi array, membayar sewa. Swap tidak menginisialisasi tick arrays — mereka melewati array yang tidak diinisialisasi menggunakan bitmap. Alur open-position SDK memeriksa rentang yang dipilih, menghitung daftar tick arrays yang disentuhnya, dan menambahkan instruksi init_tick_array dalam transaksi yang sama dengan OpenPosition jika ada yang hilang.

Tick arrays tidak ditutup

Setelah tick array diinisialisasi, array tersebut bertahan selama masa hidup pool. Program tidak mengekspos jalur untuk menutup tick array, bahkan setelah initialized_tick_count kembali ke nol. Tidak ada pemulihan sewa untuk tick arrays; sewa yang dibayar oleh posisi pertama yang menyentuh array dikunci ke akun itu secara permanen. Ini adalah trade-off yang disengaja: menggunakan kembali tick array yang ada gratis untuk setiap posisi berikutnya, jadi pool yang banyak diperdagangkan hanya membayar biaya sewa sekali per slot (pool, start_tick_index) terlepas dari churn.

Bitmap

Menemukan “tick yang diinisialisasi berikutnya ke kiri/kanan dari tick saat ini” harus cepat — swap dapat melintasi banyak ticks. Pool menyimpan bitmap 1-bit-per-tick-array inline di PoolState untuk rentang ±1.024 arrays di sekitar tick 0. Di luar rentang itu (posisi full-range, setup eksotis), TickArrayBitmapExtension menyediakan overflow. Swap berjalan melalui bitmap: lowest_set_bit_above(tick_current_array_index) memberikan array berikutnya dengan tick yang diinisialisasi di sisi yang dilintasi swap. Dalam array itu, bit-scan serupa menemukan tick yang diinisialisasi berikutnya.

liquidity_gross dan liquidity_net

Setiap tick yang diinisialisasi menyimpan dua nilai likuiditas:
  • liquidity_gross — jumlah L di atas semua posisi yang mereferensikan tick ini sebagai endpoint. Ketika liquidity_gross mencapai nol, tick menjadi tidak diinisialisasi dan dapat dihapus dari bitmap.
  • liquidity_net — perubahan bertanda ke liquidity level-pool ketika harga melintasi tick ini bergerak ke atas (kiri-ke-kanan dalam ruang tick). Jika tick ini adalah batas bawah posisi dengan ukuran L, ia berkontribusi +L; jika ini adalah batas atas posisi itu, ia berkontribusi −L.
Contoh kerja: dua posisi di pool yang sama.
  • Posisi A: tick_lower = -120, tick_upper = 0, likuiditas L_A = 100.
  • Posisi B: tick_lower = -60, tick_upper = 60, likuiditas L_B = 50.
Status tick-by-tick: liquidity level-pool untuk nilai tick_current yang berbeda:
  • tick_current = -180: liquidity = 0 (sebelum posisi apa pun)
  • tick_current = -90: liquidity = 100 (hanya di dalam A)
  • tick_current = -30: liquidity = 150 (di dalam A dan B)
  • tick_current = 30: liquidity = 50 (hanya di dalam B)
  • tick_current = 90: liquidity = 0 (melewati keduanya)
Pada setiap tick cross selama swap, program menambahkan liquidity_net (mungkin negatif) ke PoolState.liquidity. Ini adalah mekanisme Uniswap-v3 yang tepat.

Posisi sebagai NFT

Posisi CLMM Raydium adalah NFT. Membuka posisi mencetak mint baru dengan supply 1 ke dompet pemanggil, dan otoritas mint adalah program CLMM. Program mengikat kepemilikan posisi ke siapa pun yang memegang saldo di ATA mint itu pada waktu CPI. Konsekuensi:
  • Posisi biasanya dapat ditransfer. Dompet dapat menjual atau airdrop posisi dengan mentransfer NFT. Pemegang baru kemudian dapat memanggil CollectRewards, IncreaseLiquidity, dll. Pengecualian adalah posisi yang dibekukan di bawah jalur restricted-issuer di bawah.
  • Posisi dapat dialamatkan di luar CLMM. Marketplace dan dompet menampilkan posisi seperti NFT lainnya. SDK menetapkan name/symbol yang masuk akal pada metadata mint.
  • PDA posisi diturunkan dari NFT mint. Anda dapat menemukan PersonalPositionState tanpa mengetahui siapa yang saat ini menahannya.

Posisi restricted-issuer

Setiap mint NFT posisi yang dibuat setelah upgrade 2026-08 mencatat pool_state CLMM-nya sebagai freeze authority. Ini tidak berarti setiap posisi baru dibekukan. Untuk pool biasa dan setiap posisi non-matching, akun token NFT tetap tidak dibekukan dan dapat ditransfer. Pool PDA tidak dapat menandatangani di luar program CLMM, dan CLMM tidak mengekspos instruksi freeze tujuan umum. Pembekuan memerlukan kedua kondisi ini:
  1. Posisi dibuka melalui OpenPositionV2 atau OpenPositionWithToken22Nft.
  2. Setidaknya satu vault mint pool membawa freeze authority dari daftar restricted-issuer yang dikodekan keras program.
Hanya ketika kedua kondisi terpenuhi CLMM membekukan akun NFT posisi yang baru dibuat segera setelah minting. OpenPosition V1 tidak menerapkan filter ini. Lihat reference/program-addresses untuk daftar saat ini. Posisi yang dibekukan:
  • Tidak dapat mentransfer NFT-nya ke akun token lain.
  • Tidak dapat mengubah pemilik akun token NFT.
  • Masih dapat meningkatkan atau mengurangi likuiditas dan mengumpulkan biaya atau reward ketika pemilik yang tercatat menandatangani.
  • Masih dapat ditutup. ClosePosition menggunakan pool PDA untuk mencairkan akun NFT, kemudian membakar NFT dan menutup akun posisi dalam instruksi yang sama.
Posisi yang ada tidak dimigrasikan atau dibekukan secara retroaktif. Mint NFT posisi yang dibuat sebelum upgrade mempertahankan pengaturan freeze-authority sebelumnya.
Klien yang menutup posisi yang dibekukan harus menambahkan pool_state posisi sebagai akun sisa pertama ke ClosePosition. Daftar akun IDL yang dideklarasikan tidak berubah, jadi klien yang lebih lama dapat membuka posisi yang dibekukan dengan sukses tetapi kemudian gagal menutupnya dengan AccountLack. Perbarui builder close sebelum mendukung pool ini.

Posisi Token-2022

CLMM dapat mencetak NFT posisi di bawah Token SPL klasik melalui OpenPositionV2, atau di bawah Token-2022 melalui OpenPositionWithToken22Nft. Kedua jalur V2 memeriksa vault mints pool dan menerapkan aturan freeze restricted-issuer yang sama. OpenPosition V1 adalah jalur token klasik legacy dan tidak dapat melayani pool dengan vault mints Token-2022. Kompatibilitas dompet dan marketplace berbeda; UI Raydium melacak kedua program NFT.

Aturan rentang yang diizinkan

Pada waktu OpenPosition program memberlakukan:
  1. tick_lower < tick_upper.
  2. tick_lower % tick_spacing == 0 dan tick_upper % tick_spacing == 0.
  3. MIN_TICK <= tick_lower dan tick_upper <= MAX_TICK.
  4. Pemanggil telah menyediakan tick arrays yang berisi tick_lower dan tick_upper — baik sudah diinisialisasi atau melalui init_tick_array dalam transaksi yang sama.
  5. Akun bitmap extension, jika posisi ini meluas ke dalam rentang extension.
Jika pemeriksaan apa pun gagal, instruksi akan kembali dengan InvalidTickIndex, NotApproved, atau InsufficientLiquidity tergantung pada batasan mana. Lihat reference/error-codes.

”In-range” vs “out-of-range”

Posisi adalah in range ketika tick_lower <= tick_current < tick_upper. Hanya posisi in-range yang berkontribusi pada PoolState.liquidity dan oleh karena itu hanya mereka yang mendapatkan biaya swap. Posisi out-of-range:
  • Memegang 100% dari satu token (yang rentangnya telah melewati). Secara spesifik, jika tick_current < tick_lower, posisi hanya memegang token1 (sudah “dijual” oleh harga yang bergerak menjauh); jika tick_current >= tick_upper, hanya memegang token0.
  • Tidak mendapatkan biaya swap.
  • Terus mengumpulkan reward jika aliran reward pool memancarkan ke likuiditas out-of-range — tetapi perilaku default Raydium adalah “emit hanya ke in-range”, sesuai dengan konvensi Uniswap v3. Lihat products/clmm/fees.
LP yang mengelola posisi CLMM menghabiskan sebagian besar perhatian mereka untuk menjaga posisi tetap in-range saat harga bergerak.

Jebakan integrasi umum

  • Endpoint off-spacing. Kode yang menghitung tick dari harga target harus snap ke kelipatan tick_spacing sebelum meneruskannya ke OpenPosition. Helper SDK (TickUtils.getTickWithPriceAndTickspacing) melakukan ini; math buatan sendiri sering tidak.
  • Tick arrays yang hilang. Membuka posisi yang lebar mungkin memerlukan inisialisasi beberapa tick arrays; lupa meneruskannya sebagai akun writable akan kembali. SDK openPositionFromBase mengembalikan daftar untuk Anda.
  • Tick stale setelah swap. tick_current dapat melintasi banyak ticks dalam satu swap. Jika UX Anda menampilkan “current tick” dari satu panggilan RPC dan kemudian membuka posisi di panggilan yang lebih baru, posisi relatif vs harga live dapat mati puluhan ticks. Ambil ulang tepat sebelum menandatangani.
  • NFT posisi dengan metadata tambahan. Jika Anda membangun dompet yang mengenali posisi Raydium, gunakan posisi PDA / data program dan bukan field metadata yang dikodekan keras. Mint posisi baru menggunakan pool PDA sebagai mint dan freeze authority saat pembuatan; mint authority dihapus setelah NFT tunggal dicetak.
  • Mengasumsikan setiap posisi dapat ditransfer. Baca status isFrozen akun token NFT sebelum menampilkan transfer, marketplace, escrow, atau Burn & Earn actions.

Ke mana selanjutnya

  • Math — langkah swap dan derivasi fee-growth yang batas tick ikuti serta.
  • Accounts — layout TickArrayState dan PositionState.
  • Biaya dan reward — bagaimana in-range-ness gating fee accrual.
  • algorithms/clmm-math — derivasi bersama formula concentrated-liquidity.
Sumber: