Skip to main content
Halaman ini diterjemahkan secara otomatis oleh AI. Versi bahasa Inggris adalah acuan resmi.Lihat versi bahasa Inggris →
Halaman ini menjelaskan tata letak dan peran setiap akun. Seed yang kanonik tercantum di reference/program-addresses. Pool CLMM memiliki lebih banyak akun dibanding pool CPMM karena likuiditas disimpan secara jarang (sparse) di sepanjang rentang tick; memahami kejarangan tersebut adalah inti dari halaman ini.

Inventaris akun

Sebuah pool CLMM yang aktif terdiri dari keluarga akun berikut. Semuanya dimiliki oleh program CLMM, kecuali dua mint dan vault-nya.

PoolState

State live pool, dibaca pada setiap swap dan setiap perubahan posisi.
Field yang akan sering Anda gunakan:
  • sqrt_price_x64 dan tick_current adalah state harga pool. Keduanya diperbarui bersama pada setiap swap. tick_current adalah floor dari log_{1.0001}(price).
  • liquidity adalah likuiditas aktif — jumlah nilai L dari semua posisi yang rentangnya mencakup tick_current. Nilainya berubah setiap kali swap melintasi sebuah tick dan setiap kali posisi dibuka/ditutup/diubah ukurannya.
  • fee_growth_global_{0,1}_x64 adalah biaya kumulatif yang diperoleh per unit likuiditas sepanjang seluruh riwayat pool. Posisi membaca nilai ini untuk menghitung jumlah yang terutang kepada mereka.
  • tick_spacing dikunci ke AmmConfig saat inisialisasi dan tidak pernah berubah. Nilai ini menentukan indeks tick mana saja yang diizinkan menjadi endpoint posisi.
  • tick_array_bitmap adalah bitmap inline yang mencakup rentang tick yang umum digunakan di sekitar harga spot. Untuk pool dengan posisi yang mencapai jangkauan jauh, pelacakan overflow disimpan di akun TickArrayBitmapExtension yang terpisah.
  • fee_on ditetapkan saat pool dibuat. 0 (FromInput) mereproduksi perilaku klasik Uniswap-V3. 1 dan 2 mengarahkan biaya swap ke satu sisi buku — lihat products/clmm/fees untuk pertimbangannya.
  • dynamic_fee_info menyimpan state volatilitas untuk surcharge dynamic-fee. Jika diaktifkan, setiap swap menghitung ulang dynamic_fee_component di atas AmmConfig.trade_fee_rate. Tata letak didokumentasikan di bawah DynamicFeeInfo; pool tanpa dynamic fee membiarkan seluruh struct bernilai nol.

AmmConfig

Set tier biaya CLMM yang umum dipublikasikan (konfirmasi melalui GET https://api-v3.raydium.io/main/clmm-config): protocol_fee_rate dan fund_fee_rate adalah fraksi dari trade fee; konvensinya sama dengan CPMM. Lihat products/clmm/fees.

TickArrayState

CLMM tidak menyimpan satu record per tick — pendekatan itu akan menghasilkan miliaran akun. Sebagai gantinya, TICK_ARRAY_SIZE tick yang berdekatan (umumnya 60 atau 88 tergantung versi program), baik yang sudah diinisialisasi maupun belum, dikelompokkan ke dalam sebuah TickArrayState yang dibuat secara lazy saat pertama kali digunakan.
Keempat field limit-order bernilai nol pada tick yang belum pernah digunakan untuk limit order. Ketika order dibuka pada sebuah tick, program melacaknya sebagai urutan kohort:
  • order_phase adalah id kohort. Nilainya bertambah setiap kali sebuah kohort bertransisi dari “semua belum terisi” menjadi “sebagian terisi.”
  • orders_amount adalah total token input dari kohort saat ini (terbaru).
  • part_filled_orders_remaining melacak kohort sebelumnya yang sedang diisi oleh swap yang sedang berjalan.
  • unfilled_ratio_x64 adalah multiplier Q64.64 yang dibawa pada kohort: ketika swap mengisi X% dari kohort, rasionya dikalikan dengan (1 − X). Setiap order yang terbuka menyimpan snapshot (order_phase, unfilled_ratio_x64) saat dibuka, sehingga matematika penyelesaian cukup membandingkan snapshot.
Aturan:
  • Tick endpoint posisi t harus memenuhi t % tick_spacing == 0. Program menolak posisi yang tidak sesuai spacing.
  • Array dari sebuah tick berada pada floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing).
  • Array tick diinisialisasi secara lazy: posisi atau swap pertama yang menyentuh array yang belum diinisialisasi akan membuatnya sekaligus membayar rent.
  • Array tick tidak pernah ditutup oleh program. Setelah dialokasikan, akun ini bertahan selama pool ada, bahkan setelah setiap tick di dalamnya kembali ke liquidity_gross == 0. Posisi dan swap berikutnya menggunakan kembali akun yang sudah ada tanpa biaya rent tambahan. Tidak ada jalur pembersihan berbasis ClosePosition untuk array tick.

TickArrayBitmapExtension

PoolState.tick_array_bitmap (inline) mencakup rentang “dekat spot” — ±1.024 array tick. Di luar rentang tersebut (untuk nilai tick yang ekstrem), program memelihara akun extension:
Jika rentang posisi Anda “normal”, Anda tidak perlu memikirkan akun extension ini. Posisi full-range (misalnya (MIN_TICK, MAX_TICK)) membutuhkannya; SDK akan menanganinya untuk Anda.

Posisi

Sebuah posisi CLMM adalah gabungan dari tiga akun ditambah satu mint:

Position NFT mint

Mint SPL Token dengan supply 1. Alamat mint adalah PDA deterministik; NFT posisi di wallet pemilik hanyalah ATA yang menyimpan satu token tersebut. Memindahkan NFT adalah cara suatu posisi berganti pemilik — program mengaitkan otorisasi ke pemegang saldo ATA NFT saat ini, bukan ke Pubkey yang tersimpan dalam state.

PersonalPositionState

Satu per posisi yang terbuka. Dikunci berdasarkan NFT mint.

ProtocolPositionState (tidak digunakan lagi)

Rilis CLMM yang lebih lama menyimpan pembukuan agregat per (pool, tick_lower, tick_upper) dalam PDA ProtocolPositionState. Rilis terbaru tidak lagi membuat atau membaca akun ini. Slot tersebut masih muncul dalam daftar akun OpenPosition / IncreaseLiquidity / DecreaseLiquidity sebagai UncheckedAccount untuk kompatibilitas ABI, tetapi program tidak menulisi akun tersebut. Akun yang ada di on-chain bersifat vestigial; admin dapat memanggil CloseProtocolPosition untuk mengklaim kembali rent-nya.Pembukuan rentang agregat kini diturunkan langsung dari dua tick endpoint (liquidity_gross, liquidity_net, dan fee_growth_outside_* / reward_growths_outside_x64 per tick) dalam TickArrayState. Formula fee-growth-inside fee_growth_inside = global − outside_lower − outside_upper tetap berfungsi tanpa akun posisi agregat.

Observation

Buffer observasi CLMM menyimpan tick kumulatif, bukan harga kumulatif. Konsumen eksternal menghitung harga rata-rata geometris dalam suatu interval dari (tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0), kemudian price = 1.0001 ** tick. Lihat algorithms/clmm-math.

DynamicFeeConfig dan DynamicFeeInfo

Parameter dynamic fee berada di dua tempat. Template yang dapat digunakan ulang — DynamicFeeConfig — dikelola admin dan dibagi bersama pool yang ikut serta. State runtime per pool — DynamicFeeInfo — tertanam dalam PoolState dan diperbarui oleh setiap swap.

DynamicFeeConfig

PDA seed: ["dynamic_fee_config", index.to_be_bytes()]. Dibuat melalui create_dynamic_fee_config (dibatasi admin) dan dimodifikasi melalui update_dynamic_fee_config. Pool yang dibuat dengan enable_dynamic_fee = true menyalin lima parameter kalibrasi konfigurasi (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator) ke dalam DynamicFeeInfo-nya sendiri saat pembuatan; pengeditan selanjutnya pada DynamicFeeConfig tidak berlaku surut bagi pool yang sudah ada.

DynamicFeeInfo (tertanam dalam PoolState)

Empat field terbawah adalah state; lima field teratas adalah kalibrasi yang disalin dari DynamicFeeConfig. Matematika biaya dan aturan decay didokumentasikan di products/clmm/math dan products/clmm/fees. Konstanta yang digunakan dalam formula:

LimitOrderState

Satu akun per limit order yang terbuka.
Siklus hidup:
  1. Buka — pengguna memanggil open_limit_order, menyetor total_amount token input, order terikat ke kohort TickState.
  2. (opsional) Tambah / Kurangiincrease_limit_order menambah total_amount; decrease_limit_order mengembalikan token yang belum terisi (dan output yang sudah diselesaikan hingga saat itu).
  3. Selesaikan — ketika kohort terisi penuh atau sebagian, pemilik atau keeper operasional memanggil settle_limit_order untuk mendorong token output ke ATA pemilik.
  4. Tutup — setelah unfilled_amount == 0, akun dapat ditutup. Rent selalu dikembalikan ke owner.
PDA seed: [owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]. PDA order oleh karena itu unik per (owner, nonce_index, order_nonce).

LimitOrderNonce

Counter per (wallet, nonce_index) yang memungkinkan satu pengguna menjalankan beberapa pipeline limit order secara paralel tanpa bentrokan pada PDA.
PDA seed: [user_wallet.as_ref(), &[nonce_index]]. Sebagian besar klien menggunakan nonce_index = 0 dan membiarkan order_nonce menangani kardinalitas.
String seed yang tepat harus selalu diverifikasi ulang terhadap IDL on-chain dan reference/program-addresses.

Referensi cepat siklus hidup

Akun TickArrayState tidak pernah ditutup oleh program — akun ini bertahan selama pool ada. Setelah sebuah array tick diinisialisasi, akun tersebut tetap ada di on-chain bahkan ketika setiap tick di dalamnya kembali ke liquidity_gross == 0. Menggunakan kembali array tick yang sudah ada tidak dikenakan biaya; hanya posisi pertama yang menyentuh array yang belum pernah diinisialisasi yang membayar rent-nya.

Panduan referensi selanjutnya

Sumber: