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

Pengaturan

Setiap demo di halaman ini mengikuti berkas di raydium-sdk-V2-demo/src/clmm. Tautan GitHub berada di samping setiap bagian. Inisialisasi mengikuti config.ts.template di repositori demo (sumber). Untuk integrasi yang tidak sederhana, disableFeatureCheck: true direkomendasikan:

Membuat pool CLMM

Sumber: src/clmm/createPool.ts
SDK akan:
  • Mengurutkan mint1/mint2 berdasarkan urutan byte sebelum derivasi.
  • Menghitung sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64).
  • Membuat akun observation dan tick_array_bitmap_extension.
  • Membayar biaya pembuatan pool yang ditentukan oleh ammConfig.

Membuka posisi pada rentang harga pilihan

Sumber: src/clmm/createPosition.ts
SDK menghitung tick array mana saja yang tersentuh oleh rentang tersebut dan meneruskannya sebagai akun. Tidak perlu menyertakan instruksi inisialisasi tambahan, karena memang tidak ada instruksi init-tick-array. OpenPosition* sendiri mengalokasikan tick array yang belum ada, dengan biaya ditanggung oleh payer.

Menambah likuiditas pada posisi yang sudah ada

Sumber: src/clmm/increaseLiquidity.ts

Mengurangi likuiditas (sekaligus mengumpulkan biaya)

Sumber: src/clmm/decreaseLiquidity.ts dan src/clmm/closePosition.ts
Untuk hanya mengumpulkan biaya dan reward, panggil decreaseLiquidity dengan liquidity = new BN(0). Efek samping instruksi ini adalah menyelesaikan token_fees_owed_{0,1} dan reward_amount_owed, lalu mentransfernya keluar. Ini satu-satunya cara untuk mengumpulkan keduanya. Untuk menutup posisi sepenuhnya setelah likuiditas dan biaya dinolkan, berikan ownerInfo: { closePosition: true } pada pemanggilan decreaseLiquidity terakhir. SDK akan menambahkan ClosePosition dan membakar NFT-nya.
Posisi restricted-issuer memerlukan close builder yang kompatibel. Posisi ini memiliki akun token NFT yang dibekukan. ClosePosition harus menambahkan ID pool posisi sebagai akun remaining pertama agar CLMM dapat mencairkan akun tersebut sebelum membakarnya. Cabang kode program tidak menyertakan perubahan SDK. Pastikan rilis SDK Anda secara eksplisit mendukung jalur close yang dibekukan sebelum mengaktifkan pembuatan posisi restricted-issuer.
Untuk klien Anchor langsung, biarkan akun yang dideklarasikan tetap dan tambahkan pool:
Anda boleh menyertakan poolId pada setiap close. CLMM hanya membacanya ketika positionNftAccount dibekukan, sehingga satu jalur klien tetap kompatibel dengan posisi lama maupun baru.

Mengumpulkan reward

Sumber: src/clmm/harvestAllRewards.ts
harvestAllRewards memproses setiap posisi di setiap pool yang diberikan. Ia mengelompokkan pemanggilan DecreaseLiquidity bernilai likuiditas nol yang menyelesaikan biaya dan reward (ditambah UpdateRewardInfos jika ada), lalu membaginya ke beberapa transaksi bila diperlukan.

Swap

Sumber: src/clmm/swap.ts Contoh ini mengikuti src/clmm/swap.ts, yang melakukan simulasi dengan swapInternal, bukan PoolUtils.computeAmountOutFormat.
Simulasi menelusuri tick map secara off-chain dengan logika yang sama seperti program on-chain, lalu mengembalikan jumlah output (amountCalculated) beserta daftar akun persis yang akan disentuh oleh swap (accounts). Selalu sertakan remainingAccounts yang dikembalikan simulasi: jika kurang, swap akan gagal di tengah penelusuran dengan NotEnoughTickArrayAccount; jika berlebih atau sudah usang, hanya membuang compute.
PoolUtils.computeAmountOutFormat masih tersedia, tetapi memerlukan ComputeClmmPoolInfo (yaitu computePoolInfo dari getPoolInfoFromRpc, bukan objek pool dari API) serta dua argumen wajib lainnya — tickarrayBitmapExtension dan blockTimestamp. Selain itu, tidak ada metode raydium.clmm.fetchTickArrays (fetchTickArrays adalah fungsi mandiri; helper tingkat modul yang tersedia adalah PoolUtils.fetchMultiplePoolTickArrays serta tickData / tickArrays yang dikembalikan oleh getPoolInfoFromRpc).

Membuat pool CLMM yang dapat dikustomisasi

createCustomizablePool adalah titik masuk yang menyediakan sakelar dynamic-fee dan single-sided-fee saat pool dibuat. Fungsi ini memakai bentuk parameter createPool ditambah dua parameter tambahan:
Tidak ada parameter enableDynamicFee, dynamicFeeConfigId, maupun startTime. Menyediakan dynamicFeeConfig adalah yang mengaktifkan dynamic fee — jika dihilangkan, Anda mendapatkan pool dengan fee statis tanpa muncul error. Perhatikan juga bahwa anggota enum di SDK adalah TokenOnlyA / TokenOnlyB, sedangkan enum Rust on-chain menulisnya sebagai Token0Only / Token1Only; nilai numeriknya sama (FromInput = 0).
createPool tetap berfungsi untuk jalur fee default tanpa dynamic fee. Gunakan createCustomizablePool jika Anda membutuhkan salah satu dari kedua opsi tersebut. Lihat products/clmm/instructions untuk daftar akun on-chain.

Limit order

Limit order menyimpan input pengguna pada satu tick dan diisi secara FIFO ketika swap melintasi tick tersebut. Output dikirim ke ATA pemilik saat settlement; pemilik tidak perlu online agar order-nya terisi.

Membuka limit order

Tidak ada akun konfigurasi limit order per pool maupun helper getClmmLimitOrderConfigs() — order diidentifikasi berdasarkan tick.
SDK menurunkan PDA LimitOrderState dari (owner, nonce PDA, order nonce), menaikkan LimitOrderNonce per dompet, dan memasukkan order ke dalam antrean FIFO pada tick tersebut.

Menambah / mengurangi order yang terbuka

decreaseLimitOrder hanya dapat menarik dari bagian order yang belum terisi; bagian yang sudah terisi terkunci hingga settlement. Kedua instruksi akan gagal dengan InvalidOrderPhase jika order sudah terisi penuh.

Settle order yang sudah terisi

settleLimitOrder membaca unfilled_ratio_x64 order terhadap cohort tracker, menghitung output yang sudah terisi, lalu mentransfernya ke ATA pemilik. Pemilik dapat memanggil fungsi ini sendiri; limit_order_admin (keeper operasional off-chain) juga dapat memanggilnya atas nama pemilik — output tetap dikirim ke pemilik. Untuk menutup order yang sudah settle sepenuhnya guna mengambil kembali rent, gunakan closeLimitOrder (satu order) atau closeAllLimitOrder (batch). Untuk men-settle banyak order sekaligus, settleAllLimitOrder mengemas sebanyak mungkin pemanggilan SettleLimitOrder ke dalam satu tx v0.

Daftar order yang tersimpan di dompet (off-chain)

Endpoint order aktif mengembalikan order yang belum terisi maupun yang terisi sebagian dalam satu payload (totalAmount / filledAmount / pendingSettle membedakan fasenya). Untuk riwayat order yang sudah ditutup gunakan /limit-order/history/order/list-by-user?wallet=… (per dompet, dipaginasi dengan nextPageId); untuk log event lengkap dari order tertentu gunakan /limit-order/history/event/list-by-pda?pda=….

Kerangka CPI Rust

Urutan remaining account untuk SwapV2:
Jika swap tidak pernah membutuhkan extension, hilangkan saja; jika tidak, extension menjadi remaining account pertama.

Kesalahan umum

  • Titik ujung tick yang tidak sesuai spacing → TickAndSpacingNotMatch. Selalu sesuaikan dengan TickUtil.getPriceAndTick (TickUtil dalam bentuk tunggal).
  • Jumlah tick array di SwapV2 tidak cukup → NotEnoughTickArrayAccount. Ambil daftarnya dari swapInternal(...).accounts.
  • Posisi full-range tanpa bitmap extension → PDA extension harus bisa ditulis (writable). SDK menanganinya secara otomatis.
  • Menyamakan sqrt_price_x64 dengan price → kesalahan faktor 2 di sini sangat merepotkan. Jika ragu, biarkan SDK menghitungnya dari harga yang mudah dibaca.
  • Mengklaim reward terlalu sering → setiap klaim adalah DecreaseLiquidity dengan likuiditas nol dan memerlukan satu transaksi. Gabungkan dengan harvestAllRewards untuk banyak posisi sekaligus, dan ingat bahwa execute-nya membutuhkan { sequentially: true }.
  • Menutup akun NFT secara manual → ClosePosition membakar NFT dan menutup ATA-nya. Instruksi ini juga menutup mint NFT Token-2022. Mint SPL Token klasik tetap ada dengan supply nol, karena program tersebut tidak dapat menutup mint. Jangan menutup akun yang didukung secara terpisah, karena instruksi akan gagal.
  • Membuka limit order pada tick yang tidak sesuai spacing → TickAndSpacingNotMatch. Selalu kuantisasi dengan helper getOrderTick yang diekspor.
  • Memanggil decreaseLimitOrder pada order yang sudah terisi penuh → InvalidOrderPhase. Gunakan settleLimitOrder lalu closeLimitOrder sebagai gantinya.
  • Mengharapkan flag enableDynamicFee → flag tersebut tidak ada. Jika dynamicFeeConfig dihilangkan, pool yang dibuat hanya akan memakai biaya statis, tanpa peringatan atau error. Jika Anda ingin menggunakan biaya dinamis, berikan PublicKey dari akun konfigurasi yang dipilih dari /main/clmm-dynamic-config.

Langkah selanjutnya

Sumber: