Chuyển đến nội dung chính
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 →
Trang này là tài liệu tham khảo hướng dẫn chính thức. Để xem mã thực tế soạn các hướng dẫn này, hãy xem products/cpmm/code-demos. Để biết ý nghĩa mã lỗi, xem reference/error-codes.Nâng cấp chương trình 2026-09 đã xây dựng lại CPMM trên Anchor 1.0.2 / Solana 3.1.10, thêm hướng dẫn quản trị viên CollectExcessLamports, loại bỏ danh sách mint Token-2022 được mã hóa cứng, và thay đổi những gì CreateAmmConfig ghi vào protocol_owner / fund_owner. Không có hướng dẫn nào hướng tới người dùng thay đổi tài khoản, đối số hoặc toán học của nó. Xem mục nhật ký thay đổi 2026-09-09.Nâng cấp 2026-10-30 thêm InitializeV2: tạo pool không cần phép, trong đó người tạo chọn có bật phí người tạo hay không và bật ở phía nào. Đây là thay đổi thuần bổ sung. Initialize, InitializeWithPermission và mọi hướng dẫn khác giữ nguyên discriminator, tài khoản và đối số. Xem mục nhật ký thay đổi 2026-10-30.
Cả hai hướng dẫn thu thập phí người tạo đã thay đổi danh sách tài khoản của chúng vào ngày 2026-09-19. CollectCreatorFee nhận creator_fee_share; CollectCreatorFeePermissionless nhận amm_config và creator_fee_share. Cả hai đều được thêm vào sau system_program, vì vậy mọi tài khoản mà máy khách hiện có đã chuyển giữ chỉ mục của nó — nhưng các tài khoản mới là bắt buộc, vì vậy giao dịch được xây dựng dựa trên bố cục cũ hơn sẽ không đủ và bị từ chối bằng AccountNotEnoughKeys (3005) của Anchor. Hai hướng dẫn quản trị viên — CreateCreatorFeeShare và CloseCreatorFeeShare — được thêm vào, và UpdateAmmConfig nhận param = 8 mới. Xem mục nhật ký thay đổi 2026-09-19.

Tóm tắt hướng dẫn

Bitmask trạng thái: status của mỗi pool là u8 trong đó bit 0 = deposit bị vô hiệu hóa, bit 1 = withdraw bị vô hiệu hóa, bit 2 = swap bị vô hiệu hóa (PoolStatusBitIndex { Deposit, Withdraw, Swap } trong chương trình). Bit rõ ràng có nghĩa là hoạt động được phép; bit được đặt có nghĩa là nó bị tạm dừng. UpdatePoolStatus nhận u8 thô và ghi đè giá trị hiện có. Các phần tiếp theo đi qua từng phần chi tiết. Thứ tự tài khoản tuân theo IDL CPMM; SDK và máy khách Rust trong raydium-cp-swap/programs/cp-swap/src/instructions khớp với thứ tự này.

Initialize

Tạo pool CPMM mới. Đối số
Tài khoản (W = có thể ghi, S = người ký) * pool_state chỉ ký trên đường dẫn keypair ngẫu nhiên; đường dẫn PDA chính tắc chạy mà không cần pool_state ký. Điều kiện trước
  • Mint được sắp xếp (token_0_mint < token_1_mint theo thứ tự byte).
  • Không mint nào sử dụng tiện ích mở rộng ngoài danh sách cho phép CPMM (TransferFeeConfig, MetadataPointer, TokenMetadata, InterestBearingConfig, ScaledUiAmount) — xem products/cpmm/accounts. Mint có PDA SupportMintAssociated (seed [b"support_mint", mint]) tồn tại sẽ bỏ qua kiểm tra tiện ích mở rộng — nhưng bạn phải thêm PDA đó vào remaining_accounts. Chương trình chỉ quét các tài khoản bạn chuyển và không bao giờ tải PDA tự nó, vì vậy dựa vào sổ đăng ký mà không cung cấp tài khoản vẫn thất bại với NotSupportMint (6007). Thứ tự không quan trọng (khớp theo khóa); chuyển một mục cho mỗi mint cần bỏ qua. Sổ đăng ký đó là bỏ qua duy nhất kể từ khi nâng cấp 2026-09 loại bỏ danh sách mint bốn được mã hóa cứng.
  • creator có ít nhất init_amount_0 và init_amount_1 trong các ATA tương ứng.
  • amm_config.disable_create_pool == false.
Điều kiện sau
  • pool_state.lp_supply = sqrt(init_amount_0 * init_amount_1) — căn bậc hai đầy đủ. Người tạo được mint lp_supply − 100; 100 đơn vị cơ sở bị khóa được tính trong lp_supply nhưng không bao giờ được mint.
  • Vì vậy lp_mint.supply == pool_state.lp_supply − 100 trong suốt vòng đời của pool. Tất cả toán học chia sẻ LP (deposit, withdraw) chia cho lp_supply, vì vậy hãy sử dụng trường đó và không thay thế cung cấp trên chuỗi của mint. Hoàn nguyên với InitLpAmountTooLess nếu sqrt(...) < 100.
  • observation_state được khởi tạo; observation_index = 0 và pool_id = pool_state.key().
  • Lamport create_pool_fee được chuyển từ người tạo đến người nhận và được đồng bộ hóa dưới dạng SOL gốc (nó là ATA wSOL).
  • Bitmask trạng thái của pool là 0 (deposit / withdraw / swap đều được bật).
  • enable_creator_fee = false và creator_fee_on = BothToken. Initialize không hỗ trợ bật phí người tạo. Sử dụng InitializeV2 để bật nó mà không cần cấp quyền.
  • open_time được tăng lên block_timestamp + 1 nếu người gọi chuyển giá trị <= block_timestamp. Swap bị từ chối trước open_time; deposit và withdrawal hoạt động ngay lập tức.
Lỗi phổ biến (danh sách đầy đủ trong reference/error-codes)
  • InvalidInput — mint không được sắp xếp, hoặc mint giống hệt nhau.
  • NotSupportMint — tiện ích mở rộng Token-2022 bị chặn.
  • ExceededSlippage — hiếm khi; nếu init_amount_0/1 dẫn đến LP bằng không do không khớp số thập phân.

InitializeV2

Tạo pool CPMM mới và chọn cài đặt phí người tạo của nó. Được thêm vào trong nâng cấp 2026-10-30. InitializeV2 chạy cùng luồng tạo như Initialize. Khác biệt duy nhất là những gì nó ghi vào enable_creator_fee và creator_fee_on trên pool mới. Trước hướng dẫn này, chỉ InitializeWithPermission mới có thể tạo pool với phí người tạo được bật, và đường dẫn đó cần PDA Permission do quản trị viên cấp. Đối số
CreatorFeeOn là một enum Borsh, vì vậy đối số được mã hóa thành một byte tag cho Option, cộng thêm một byte biến thể khi nó là Some: Bất kỳ byte nào khác đều làm thất bại quá trình deserialize đối số của Anchor trước khi handler chạy. Discriminator: initialize_v2 → [67, 153, 175, 39, 218, 16, 38, 32]. Tài khoản (W = có thể ghi, S = người ký) 19 tài khoản đầu tiên giống hệt Initialize, theo cùng thứ tự. InitializeV2 chỉ bỏ sysvar rent ở cuối. * pool_state chỉ ký trên đường dẫn keypair ngẫu nhiên. remaining_accounts hoạt động giống như trên Initialize: thêm PDA SupportMintAssociated cho bất kỳ mint Token-2022 nào cần bỏ qua sổ đăng ký.
Vì 19 tài khoản đầu tiên khớp nhau, bạn có thể điều chỉnh một trình xây dựng Initialize hiện có: thay đổi discriminator, thêm các byte creator_fee_on và bỏ rent. Nếu bạn giữ rent, Anchor chuyển nó qua như một mục remaining_accounts, và lần quét support-mint bỏ qua nó vì nó không phải là tài khoản do CPMM sở hữu. Dù vậy, hãy bỏ nó để tiết kiệm một vị trí tài khoản.
Điều kiện trước — giống như Initialize. Không có kiểm tra quyền và không có ràng buộc mới nào đối với creator_fee_on. Điều kiện sau — giống như Initialize, ngoại trừ:
  • enable_creator_fee và creator_fee_on được đặt từ đối số, như trong bảng trên.
  • pool_creator luôn là creator đang ký. Trên InitializeWithPermission, người tạo là một tài khoản riêng biệt, không ký; trên InitializeV2, nó không thể được đặt thành bất kỳ ai khác.
Bật phí người tạo không chọn mức phí của nó. Pool tính AmmConfig.creator_fee_rate của tầng phí mà nó liên kết. Trên một tầng có mức phí đó là 0, pool được bật sẽ không tích lũy gì. Hãy đọc cấu hình trước khi chọn tầng. Lựa chọn này cũng là vĩnh viễn: không có hướng dẫn nào thay đổi enable_creator_fee hoặc creator_fee_on sau khi tạo. Xem products/cpmm/fees.
Khi phí được bật, các swap tích lũy nó vào creator_fees_token_{0,1}. Người tạo thu thập nó thông qua CollectCreatorFee hoặc CollectCreatorFeePermissionless, và phần chia cho giao thức từ nâng cấp 2026-09-19 được áp dụng như bình thường. Lỗi phổ biến — giống như Initialize.

Deposit

Thêm thanh khoản với cả hai token theo tỷ lệ của pool. Arguments
Accounts Math
Hai chi tiết cần lưu ý: cơ sở tính theo tỷ lệ là tổng vault không tính phí (vault_amount_without_fee, tức là số dư thô trừ đi các bộ đếm phí protocol, fund và creator), không phải số dư vault thô; và giới hạn slippage được kiểm tra so với những gì người trả tiền thực sự chuyển, sau khi phí chuyển Token-2022 được thêm vào, không phải so với chuyển động vault tổng. Không có thay đổi đối với tính tỷ lệ của k — cả tổng và lp_supply đều được chia tỷ lệ theo cùng một hệ số. Postconditions
  • lp_supply += lp_token_amount.
  • vault_0 += needed_token_0 (sau khi trừ bất kỳ phí chuyển Token-2022 nào trên đầu vào).
  • vault_1 += needed_token_1 (sau khi trừ bất kỳ phí chuyển Token-2022 nào trên đầu vào).
Common errors — ExceededSlippage, ZeroTradingTokens, InvalidStatus nếu deposit bị tạm dừng.

Withdraw

Đốt token LP và nhận cả hai token cơ bản theo tỷ lệ. Arguments
Accounts 13 account đầu tiên giống hệt với Deposit, và lp_mint có thể ghi được vì token LP được đốt. Withdraw còn yêu cầu thêm account thứ 14, memo_program (bị ràng buộc address = memo::ID) — Deposit không có. Một Withdraw với 13 account sẽ thất bại khi Anchor deserialize, vì vậy LP không thể thoát. Math
Postconditions
  • lp_supply -= lp_token_amount.
  • Vault gửi out_token_0 / out_token_1 (tổng; người dùng nhận được sau khi trừ bất kỳ phí chuyển Token-2022 nào).

SwapBaseInput

Swap với đầu vào chính xác. Arguments
Accounts Thứ tự input → output được xác định bởi hướng của người dùng, không phải bởi token_0 / token_1 chính tắc của pool. Chương trình xác định vault nào là gì bằng cách so khớp mint. Math — xem products/cpmm/math. Preconditions
  • open_time <= now.
  • pool_status cho phép swap.
  • Không mint nào bị tạm dừng hoặc đóng băng cho authority này.
  • amount_in > 0.
Common errors
  • ExceededSlippage — amount_out < minimum_amount_out.
  • ZeroTradingTokens — giao dịch làm tròn thành không.
  • NotApproved — pool bị tạm dừng cho swap thông qua UpdatePoolStatus.
  • InvalidInput — mint không khớp với bất kỳ mint vault nào của pool.

SwapBaseOutput

Swap với đầu ra chính xác. Arguments
Accounts — giống như SwapBaseInput. Math — đường cong ngược với ceiling, xem products/cpmm/math. Common errors — ExceededSlippage (gross_in > max_amount_in), ZeroTradingTokens, InvalidInput, NotApproved.

CollectProtocolFee

Quét phí protocol tích lũy từ vault đến điểm đến của protocol. Arguments — không có. Accounts Effect
Không có thay đổi đối với số dư hiệu quả của đường cong (phí tích lũy đã được loại trừ). Common error — InvalidOwner (6001) nếu người ký không phải là amm_config.protocol_owner cũng không phải là admin chương trình. (Không có NotApproved trên đường dẫn này.)

CollectFundFee

Cùng hình dạng với CollectProtocolFee nhưng được ký bởi amm_config.fund_owner — hoặc, một lần nữa, admin chương trình — và đặt lại các bộ đếm fund_fees_*. Cùng InvalidOwner khi người ký sai.

CollectCreatorFee

Được ký bởi pool_state.pool_creator. Nó thanh toán phí creator tích lũy và chuyển phần của creator đến các account token của creator. Arguments — không có. Accounts Effect
Phần của protocol không bao giờ rời khỏi vault ở đây — nó được gắn nhãn lại thành phí protocol và chờ CollectProtocolFee. Cả hai bộ đếm đã được loại trừ khỏi cách nhìn của đường cong đối với vault, vì vậy giá của pool không thay đổi. Đạo hàm đầy đủ trong products/cpmm/fees. Common errors — NoFeeCollect khi cả hai bộ đếm creator đều bằng không (được kiểm tra trước khi chia), InvalidInput (6003) nếu share_rate được giải quyết vượt quá 1_000_000, MathOverflow (6011) nếu ghi lại phần chia sẻ sẽ tràn protocol_fees_token_*, và lỗi ConstraintSeeds của Anchor nếu creator_fee_share không phải là PDA chính tắc.

CollectCreatorFeePermissionless

Bất kỳ ai cũng có thể kích hoạt việc thu phí creator. Instruction luôn gửi phần của creator đến các associated token account chính thức được sở hữu bởi pool_state.pool_creator; người gọi không thể chọn creator hoặc đích đến khác. Nếu một trong hai ATA bị thiếu, payer sẽ tài trợ cho việc tạo nó. CollectCreatorFee gốc vẫn có thể gọi được, vì vậy một creator muốn ký cho việc thu phí của riêng họ vẫn có thể làm được. Arguments — không có. Accounts
Hai account mới được thêm sau system_program, không được chèn vào. Mỗi account từ payer đến system_program giữ vị trí mà nó có trước khi nâng cấp, vì vậy sự ngắt quãng là sạch sẽ: một transaction được xây dựng dựa trên bố cục mười bốn account trước khi nâng cấp sẽ không đọc nhầm vault thành config — nó chỉ đơn giản là truyền quá ít account và Anchor từ chối nó với AccountNotEnoughKeys (3005) trước khi bất kỳ constraint nào chạy. Các account vẫn là bắt buộc, vì vậy hãy thêm cả hai và làm mới IDL; không có đường dẫn tương thích cho bố cục cũ.
Effect — giống hệt với CollectCreatorFee ở trên: share được giải quyết từ creator_fee_share hoặc amm_config, phần của protocol được ghi vào protocol_fees_token_{0,1}, phần của creator được chuyển đến creator ATA, cả hai bộ đếm creator được đặt lại về 0, và recent_epoch được cập nhật. Trả về NoFeeCollect khi cả hai bộ đếm đều bằng 0.

UpdatePoolStatus

Tạm dừng hoặc tiếp tục các hoạt động riêng lẻ trên một pool. Trường status là một bitmask: Arguments
Accounts Admin key là một pubkey được biên dịch vào program (crate::admin::ID), không phải BPF upgrade authority — thay đổi nó yêu cầu nâng cấp program. Xem reference/program-addresses để biết giá trị và security/admin-and-multisig để biết ai giữ nó.

CreateAmmConfig

Tạo một fee tier mới. Arguments
Accounts Preconditions
  • Không có AmmConfig hiện tại nào có cùng index.
  • protocol_fee_rate + fund_fee_rate <= FEE_RATE_DENOMINATOR_VALUE.
Thay đổi vào 2026-09: các fee owner của config mới không còn đến từ signer. create_amm_config hiện ghi protocol_fee_owner::ID được hardcode của program vào protocol_owner và fund_fee_owner::ID vào fund_owner, thay vì sao chép key của admin signer vào cả hai. Các địa chỉ nằm trong reference/program-addresses.Hậu quả: phí trên một AmmConfig mới được tạo sẽ đi vào các ví phí chuyên dụng thay vì của admin. Admin vẫn là một signer được chấp nhận cho việc thu phí — CollectProtocolFee / CollectFundFee chấp nhận amm_config.protocol_owner / fund_owner hoặc crate::admin::ID — vì vậy không có gì phải xoay vòng để quét; những gì thay đổi chỉ là nơi các khoản thu nhập đi theo mặc định. Các account AmmConfig hiện tại không được viết lại — bất kỳ điều gì được lưu trữ trên chúng vẫn chi phối, vì vậy luôn đọc protocol_owner / fund_owner từ account thay vì giả định bất kỳ giá trị nào. Các tham số UpdateAmmConfig 3 và 4 vẫn xoay vòng chúng.

UpdateAmmConfig

Thay đổi fee rate hoặc quyền sở hữu trên một AmmConfig hiện tại. Lấy một param: u8 (trường nào để cập nhật) và một value: u64. Bảng dispatch đầy đủ:
  • param = 0 → trade_fee_rate (asserts trade_fee_rate + creator_fee_rate < 1_000_000)
  • param = 1 → protocol_fee_rate (asserts ≤ 1_000_000 và + fund_fee_rate ≤ 1_000_000)
  • param = 2 → fund_fee_rate (asserts ≤ 1_000_000 và + protocol_fee_rate ≤ 1_000_000)
  • param = 3 → protocol_owner. Key mới không nằm trong value: thêm nó như remaining_accounts[0] (read-only là được). Nó không được là default pubkey, và bỏ qua account sẽ panic trên một unwrap().
  • param = 4 → fund_owner. Cơ chế giống như 3.
  • param = 5 → create_pool_fee
  • param = 6 → disable_create_pool (bất kỳ value khác 0 nào sẽ vô hiệu hóa)
  • param = 7 → creator_fee_rate (asserts creator_fee_rate + trade_fee_rate < 1_000_000)
  • param = 8 → creator_fee_share_rate (asserts ≤ 1_000_000). Thêm vào 2026-09-19. Share mặc định của protocol của phí creator trên tier này; xem products/cpmm/fees. Nó không liên quan đến protocol_fee_rate, cái mà chia trade fee.
Bất kỳ param nào khác trả về InvalidInput. Các thay đổi được ký bởi admin và ảnh hưởng đến mỗi pool được ràng buộc với AmmConfig này trên swap tiếp theo. Không có migration; các pool chỉ đơn giản đọc các giá trị mới.

CreateCreatorFeeShare

Đặt một share tùy chỉnh của protocol cho phí creator cho một cặp (creator, amm_config), ghi đè AmmConfig.creator_fee_share_rate cho mỗi pool mà creator sở hữu trên fee tier đó. Thêm vào nâng cấp creator-fee-share 2026-09-19. Arguments
Accounts Preconditions
  • share_rate <= 1_000_000, nếu không InvalidInput (6003).
  • PDA không được tồn tại — Anchor’s init thất bại trên lệnh gọi thứ hai cho cùng một cặp. Để thay đổi rate, hãy đóng account và tạo lại nó.
Postconditions
  • creator_fee_share lưu trữ bump, creator, amm_config và share_rate.
  • Mỗi CollectCreatorFee / CollectCreatorFeePermissionless tiếp theo trên một pool được tạo bởi creator dưới amm_config giải quyết share từ account này thay vì config.
Pool creator không phải là một bên trong instruction này và không ký nó. Rate được đọc tại thời điểm thu phí, vì vậy một override được tạo sau khi phí đã tích lũy áp dụng cho số dư tích lũy đó.

CloseCreatorFeeShare

Loại bỏ override. Cặp quay lại AmmConfig.creator_fee_share_rate. Arguments — không có. Accounts Postconditions
  • Account được đóng và lamports của nó đi đến owner.
  • Thu phí cho cặp đó giải quyết share từ amm_config.creator_fee_share_rate lại — cái mà là 0 trừ khi một admin đã đặt UpdateAmmConfig param 8.

CollectExcessLamports

Quét lamports của admin nằm trên mức tối thiểu miễn phí thuê trên các tài khoản mà CPMM kiểm soát. Được thêm vào trong bản nâng cấp 2026-09 để giao thức có thể thu hồi quỹ dư thừa mà SIMD-0437 rent reduction để lại trên các tài khoản được tạo trước mỗi bước. Chỉ phần dư thừa được di chuyển. Số dư token, dữ liệu tài khoản, chủ sở hữu, trạng thái pool và đường cong không bị ảnh hưởng, và lệnh này là no-op đối với tài khoản đã ở mức tối thiểu của nó — vì vậy nó an toàn để chạy lại sau mỗi bước triển khai. Arguments — không có. Accounts
Sửa lỗi thứ tự, 2026-09-19. Chương trình hiện thực hiện hai lần quét remaining_accounts — mỗi CPI token-program trước, sau đó là các khoản ghi nợ trực tiếp của các PDA do CPMM sở hữu. Xen kẽ chúng sẽ hủy bỏ với UnbalancedInstruction của runtime (“tổng số dư tài khoản trước và sau lệnh không khớp”) bất cứ khi nào một PDA được ghi nợ trước một CPI, vì các thay đổi lamport đang chờ xử lý của người gọi chỉ được xóa vào tài khoản mà CPI thực sự thực hiện. Người gọi không phải tự mình nhóm hoặc sắp xếp danh sách.
Cách xử lý mỗi tài khoản nguồn Chương trình phân loại dựa trên owner của tài khoản nguồn: Vì nó nhận một danh sách remaining_accounts không giới hạn, kích thước giao dịch là giới hạn thực tế — cùng một ràng buộc như quét phía ví được mô tả trong solana-fundamentals/rent-and-reclaimable-rent. Lỗi phổ biến — InvalidOwner (6001, người ký sai), LamportsCalculateError (6015, vòng wSOL không bằng không), và InsufficientFunds từ đường dẫn do chương trình sở hữu khi tài khoản giữ ít hơn mức tối thiểu thuê của chính nó. Không có SDK builder. @raydium-io/raydium-sdk-v2 không cung cấp builder cho lệnh này, và raydium-sdk-V2-demo repo cũng không — đó là một đường dẫn admin. Mã hóa nó bằng tay, theo cách quét phía ví trong solana-fundamentals/rent-and-reclaimable-rent làm cho lệnh token-program.

Ma trận thay đổi trạng thái

Bước tiếp theo

Nguồn: