Chuyển đến nội dung chính

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 →

Tại sao tick tồn tại

Tính thanhtí của CLMM được tập trung vào các dải giá. Để làm cho các dải này dễ quản lý trên chuỗi, giá được lượng tử hóa thành các số nguyên tick, trong đó mỗi tick là một bội số hằng của cái trước: price(i)=1.0001i\text{price}(i) = 1.0001^{\,i} Một tick tương ứng với một bước giá 0,01%, hay khoảng 1 điểm cơ bản. Ánh xạ như sau:
Chỉ số tick iHệ số giá
01.0000
1001.0100 (≈ +1.00%)
-1000.9900 (≈ −0.99%)
100002.7181 (≈ e)
MAX_TICK = 4436361.84e19
MIN_TICK = -4436365.42e-20
MIN_TICKMAX_TICK được chọn sao cho sqrt_price_x64 vừa trong một u128 ở cả hai đầu. Mọi pool đều tuân thủ tick_lower >= MIN_TICKtick_upper <= MAX_TICK. Trong thực tế, giao diện web sẽ giới hạn dải này một cách chặt chẽ hơn để ngăn người dùng khóa tính thanh khoản vào các tick không thể truy cập được.

Khoảng cách tick

AmmConfig của một pool xác định tick spacing — các tick duy nhất mà một vị trí được phép sử dụng làm điểm cuối. Nếu tick_spacing = 60, chỉ các tick …, −120, −60, 0, 60, 120, … là hợp lệ. Một nỗ lực mở vị trí với điểm cuối 31 sẽ bị hoàn nguyên với InvalidTickIndex. Các khoảng cách được công bố phổ biến:
Tầng phítrade_fee_rateTick spacingBước giá thô nhất trên mỗi vị trí tick
0.01%10010.01%
0.05%500100.10%
0.25%2500600.60%
1.00%100001201.21%
Khoảng cách càng lớn, càng ít mảng tick cần khởi tạo, chi phí mở vị trí rộng càng thấp, và biên giá càng mờ. Các cặp biến động thường nằm ở các tầng 120-spacing; stablecoin nằm ở các tầng 1-spacing.

Mảng tick

Pool không lưu trữ trạng thái mỗi tick trong các tài khoản riêng biệt. Thay vào đó, TICK_ARRAY_SIZE tick liền kề (60 trong Raydium CLMM hiện tại) được đóng gói thành một TickArrayState duy nhất. Tick đầu tiên của mảng là start_tick_index của nó, và nó bao phủ chính xác TICK_ARRAY_SIZE * tick_spacing đơn vị tick nguyên. Đối với tick_spacing = 60TICK_ARRAY_SIZE = 60:
  • Mỗi mảng tick bao gồm 60 × 60 = 3600 tick nguyên.
  • start_tick_index là bội số của 3600: …, -7200, -3600, 0, 3600, 7200, ….
Một điểm cuối vị trí t = 2040tick_spacing = 60 nằm trong mảng tick có start_tick_index = 0. Một điểm cuối vị trí t = 4200 nằm trong mảng có start_tick_index = 3600.

Khi một mảng được tạo

Một mảng tick là lười biếng: vị trí đầu tiên tham chiếu bất kỳ tick nào trong nó sẽ khởi tạo mảng, trả tiền cho rent. Các swap không khởi tạo mảng tick — chúng bỏ qua các mảng chưa khởi tạo bằng cách sử dụng bitmap. Quy trình mở vị trí của SDK kiểm tra phạm vi được chọn, tính toán danh sách các mảng tick mà nó chạm vào, và thêm các hướng dẫn init_tick_array trong cùng một giao dịch với OpenPosition nếu có bất kỳ cái nào bị thiếu.

Mảng tick không được đóng

Sau khi một mảng tick đã được khởi tạo, nó tồn tại suốt vòng đời của pool. Chương trình không cung cấp một cách để đóng mảng tick, thậm chí sau khi initialized_tick_count quay trở về không. Không có phục hồi rent cho mảng tick; tiền rent được trả bởi vị trí đầu tiên chạm vào một mảng bị khóa vào tài khoản đó vĩnh viễn. Đây là một sự cân bằng cố ý: tái sử dụng một mảng tick hiện có là miễn phí cho mọi vị trí tiếp theo, vì vậy một pool được giao dịch nhiều chỉ trả chi phí rent một lần cho mỗi slot (pool, start_tick_index) bất kể có bao nhiêu sự thay đổi.

Bitmap

Việc tìm “tick được khởi tạo tiếp theo ở bên trái/phải của tick hiện tại” phải nhanh — một swap có thể vượt qua nhiều tick. Pool lưu trữ một bitmap 1-bit-trên-mỗi-mảng-tick trong PoolState cho phạm vi ±1,024 mảng xung quanh tick 0. Ngoài phạm vi đó (vị trí phạm vi đầy đủ, thiết lập exotic), TickArrayBitmapExtension cung cấp tràn. Một swap bước đi qua bitmap: lowest_set_bit_above(tick_current_array_index) cho mảng tiếp theo có một tick được khởi tạo ở phía swap đang vượt qua. Trong mảng đó, một quét bit tương tự định vị tick được khởi tạo tiếp theo.

liquidity_grossliquidity_net

Mỗi tick được khởi tạo lưu trữ hai giá trị tính thanh khoản:
  • liquidity_gross — tổng của L trên tất cả các vị trí tham chiếu tick này làm điểm cuối. Khi liquidity_gross đạt không, tick trở nên chưa khởi tạo và có thể bị loại bỏ khỏi bitmap.
  • liquidity_netcó dấu thay đổi tính thanh khoản ở cấp độ pool khi giá vượt qua tick này di chuyển lên (từ trái sang phải trong không gian tick). Nếu tick này là giới hạn dưới của vị trí với kích thước L, nó đóng góp +L; nếu nó là giới hạn trên của vị trí đó, nó đóng góp −L.
Ví dụ cụ thể: hai vị trí trên cùng một pool.
  • Vị trí A: tick_lower = -120, tick_upper = 0, tính thanh khoản L_A = 100.
  • Vị trí B: tick_lower = -60, tick_upper = 60, tính thanh khoản L_B = 50.
Trạng thái từng tick:
TickĐược tham chiếu bởiliquidity_grossliquidity_net
-120A lower100+100
-60B lower50+50
0A upper100−100
60B upper50−50
Tính thanh khoản ở cấp độ pool cho các giá trị tick_current khác nhau:
  • tick_current = -180: liquidity = 0 (trước bất kỳ vị trí nào)
  • tick_current = -90: liquidity = 100 (bên trong chỉ vị trí A)
  • tick_current = -30: liquidity = 150 (bên trong A và B)
  • tick_current = 30: liquidity = 50 (bên trong chỉ vị trí B)
  • tick_current = 90: liquidity = 0 (vượt qua cả hai)
Trên mỗi lần vượt qua tick trong một swap, chương trình thêm liquidity_net (có thể âm) vào PoolState.liquidity. Đây là cơ chế chính xác của Uniswap v3.

Vị trí dưới dạng NFT

Một vị trí Raydium CLMM là một NFT. Mở một vị trí sẽ mint một mint mới hoàn toàn có cung cấp 1 vào ví của người gọi, và quyền kiểm soát mint của chương trình CLMM. Chương trình liên kết quyền sở hữu vị trí với bất kỳ ai giữ số dư trong một ATA của mint đó vào thời điểm CPI. Hậu quả:
  • Vị trí có thể chuyển nhượng. Một ví có thể bán hoặc airdrop một vị trí bằng cách chuyển NFT. Chủ sở hữu mới sau đó có thể gọi CollectRewards, IncreaseLiquidity, v.v.
  • Vị trí có thể được định địa chỉ bên ngoài CLMM. Các marketplace và ví hiển thị các vị trí như các NFT khác. SDK đặt một name/symbol hợp lý trên siêu dữ liệu mint.
  • PDA của một vị trí được lấy từ mint NFT. Bạn có thể tìm PersonalPositionState mà không cần biết ai đang giữ nó.

Vị trí Token-2022

Các pool CLMM mới hơn có thể mint vị trí dưới Token-2022 thay vì SPL Token cổ điển. Chương trình công bố hai hướng dẫn song song — OpenPositionOpenPositionWithToken22Nft — với ngữ nghĩa giống hệt nhau ngoại trừ chương trình token nào sở hữu mint NFT. Khả năng tương thích ví và marketplace khác nhau; giao diện Raydium theo dõi cả hai.

Quy tắc phạm vi cho phép

Tại thời điểm OpenPosition, chương trình thực thi:
  1. tick_lower < tick_upper.
  2. tick_lower % tick_spacing == 0tick_upper % tick_spacing == 0.
  3. MIN_TICK <= tick_lowertick_upper <= MAX_TICK.
  4. Người gọi đã cung cấp các mảng tick chứa tick_lowertick_upper — hoặc đã được khởi tạo hoặc thông qua một init_tick_array trong cùng một giao dịch.
  5. Tài khoản mở rộng bitmap, nếu vị trí này kéo dài vào phạm vi mở rộng.
Nếu bất kỳ kiểm tra nào thất bại, hướng dẫn sẽ bị hoàn nguyên với InvalidTickIndex, NotApproved, hoặc InsufficientLiquidity tùy thuộc vào ràng buộc nào. Xem reference/error-codes.

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

Một vị trí ở trong dải khi tick_lower <= tick_current < tick_upper. Chỉ các vị trí trong dải mới đóng góp vào PoolState.liquidity và do đó chỉ chúng mới kiếm được phí swap. Một vị trí ngoài dải:
  • Giữ 100% một token (cái mà dải của nó đã đi qua). Cụ thể, nếu tick_current < tick_lower, vị trí chỉ giữ token1 (nó đã bị “bán” bởi giá di chuyển); nếu tick_current >= tick_upper, nó chỉ giữ token0.
  • Không kiếm được phí swap.
  • Tiếp tục tích lũy phần thưởng nếu các luồng phần thưởng của pool phát hành cho tính thanh khoản ngoài dải — nhưng hành vi mặc định của Raydium là “chỉ phát hành cho in-range”, khớp với quy ước Uniswap v3. Xem products/clmm/fees.
Các LP quản lý vị trí CLMM dành phần lớn sự chú ý của họ để giữ các vị trí trong dải khi giá di chuyển.

Những cạm bẫy tích hợp phổ biến

  • Điểm cuối không khớp khoảng cách. Mã tính toán một tick từ giá mục tiêu phải snap thành bội số của tick_spacing trước khi truyền nó tới OpenPosition. Các trình trợ giúp SDK (TickUtils.getTickWithPriceAndTickspacing) làm điều này; toán học tự tạo thường không làm.
  • Mảng tick bị thiếu. Mở một vị trí rộng có thể yêu cầu khởi tạo một số mảng tick; quên truyền chúng làm các tài khoản writable sẽ hoàn nguyên. SDK’s openPositionFromBase trả danh sách cho bạn.
  • Tick cũ sau một swap. tick_current có thể vượt qua nhiều tick trong một swap. Nếu UX của bạn hiển thị một “tick hiện tại” từ một lệnh gọi RPC và sau đó mở một vị trí trong một lệnh gọi sau đó, vị trí tương đối so với giá trực tiếp có thể chênh lệch hàng chục tick. Tìm lại ngay trước khi ký.
  • NFT vị trí với siêu dữ liệu bổ sung. Nếu bạn xây dựng một ví nhận ra các vị trí Raydium, phát hiện chúng bằng thẩm quyền mint (= PDA của chương trình CLMM), chứ không phải bằng một trường siêu dữ liệu được mã hóa cứng.

Nơi đến tiếp theo

  • Math — bước swap từng bước và dẫn xuất tăng trưởng phí mà ranh giới tick tham gia vào.
  • Accounts — các bố cục TickArrayStatePositionState.
  • Fees and rewards — cách in-range-ness kiểm soát tích lũy phí.
  • algorithms/clmm-math — dẫn xuất chung của các công thức tính thanh khoản tập trung.
Nguồn: