Skip to main content
이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
이 페이지는 권위 있는 명령어 참고서입니다. 실제로 이 명령어들을 구성하는 코드는 products/cpmm/code-demos를 참고하세요. 오류 코드의 의미는 reference/error-codes를 참고하세요.2026-09 프로그램 업그레이드는 CPMM을 Anchor 1.0.2 / Solana 3.1.10으로 재구축했으며, 관리자 명령어 CollectExcessLamports를 추가했고, 하드코딩된 Token-2022 민트 화이트리스트를 제거했으며, CreateAmmConfig가 protocol_owner / fund_owner에 기록하는 내용을 변경했습니다. 사용자 대면 명령어는 계정, 인자 또는 수학을 변경하지 않았습니다. 2026-09-09 변경 로그 항목을 참고하세요.
두 개의 크리에이터 수수료 수집 명령어가 2026-09-19에 계정 목록을 변경했습니다. CollectCreatorFee는 creator_fee_share를 추가하고, CollectCreatorFeePermissionless는 amm_config 그리고 creator_fee_share를 추가합니다. 둘 다 system_program 뒤에 추가되므로, 기존 클라이언트가 이미 전달하는 모든 계정은 인덱스를 유지합니다. 하지만 새 계정은 필수이므로, 이전 레이아웃에 대해 구축된 트랜잭션은 부족하며 Anchor의 AccountNotEnoughKeys (3005)로 거부됩니다. 두 개의 관리자 명령어 — CreateCreatorFeeShare와 CloseCreatorFeeShare — 가 추가되고, UpdateAmmConfig는 새로운 param = 8을 사용합니다. 2026-09-19 변경 로그 항목을 참고하세요.

명령어 요약

상태 비트마스크: 각 풀의 status는 u8이며, 비트 0 = 입금 비활성화, 비트 1 = 출금 비활성화, 비트 2 = 스왑 비활성화 (PoolStatusBitIndex { Deposit, Withdraw, Swap } 프로그램에서). 명확한 비트는 작업이 허용됨을 의미하고, 설정된 비트는 일시 중지됨을 의미합니다. UpdatePoolStatus는 원시 u8을 사용하고 기존 값을 덮어씁니다. 다음 섹션에서는 각각을 자세히 설명합니다. 계정 순서는 CPMM IDL을 따릅니다. SDK와 raydium-cp-swap/programs/cp-swap/src/instructions의 Rust 클라이언트는 이 순서와 일치합니다.

Initialize

새로운 CPMM 풀을 생성합니다. 인자
계정 (W = 쓰기 가능, S = 서명자) * pool_state는 임의 키쌍 경로에서만 서명합니다. 정규 PDA 경로는 pool_state 서명 없이 실행됩니다. 사전 조건
  • 민트가 정렬되어 있습니다 (token_0_mint < token_1_mint 바이트 순서로).
  • 어느 민트도 CPMM 허용 목록 외의 확장을 사용하지 않습니다 (TransferFeeConfig, MetadataPointer, TokenMetadata, InterestBearingConfig, ScaledUiAmount) — products/cpmm/accounts를 참고하세요. SupportMintAssociated PDA (시드 [b"support_mint", mint])가 존재하는 민트는 확장 검사를 건너뜁니다 — 하지만 해당 PDA를 remaining_accounts에 추가해야 합니다. 프로그램은 전달하는 계정만 스캔하고 PDA를 직접 로드하지 않으므로, 계정을 제공하지 않고 레지스트리에 의존하면 여전히 NotSupportMint (6007)로 실패합니다. 순서는 중요하지 않습니다 (키로 일치). 바이패스가 필요한 민트당 하나의 항목을 전달하세요. 해당 레지스트리는 2026-09 업그레이드가 하드코딩된 4개 민트 화이트리스트를 제거한 이후 유일한 바이패스입니다.
  • creator는 각 ATA에서 최소 init_amount_0과 init_amount_1을 보유합니다.
  • amm_config.disable_create_pool == false.
사후 조건
  • pool_state.lp_supply = sqrt(init_amount_0 * init_amount_1) — 전체 제곱근입니다. 생성자는 lp_supply − 100을 민팅받습니다. 100개의 잠긴 기본 단위는 lp_supply에 계산되지만 절대 민팅되지 않습니다.
  • 따라서 풀의 수명 동안 lp_mint.supply == pool_state.lp_supply − 100입니다. 모든 LP 공유 수학 (입금, 출금)은 lp_supply로 나누므로 해당 필드를 사용하고 민트의 온체인 공급을 대체하지 마세요. sqrt(...) < 100이면 InitLpAmountTooLess로 되돌립니다.
  • observation_state가 초기화됩니다. observation_index = 0이고 pool_id = pool_state.key()입니다.
  • create_pool_fee lamport는 생성자에서 수신자로 전송되고 네이티브 SOL로 동기화됩니다 (wSOL ATA입니다).
  • 풀의 상태 비트마스크는 0입니다 (입금 / 출금 / 스왑 모두 활성화됨).
  • enable_creator_fee = false이고 creator_fee_on = BothToken입니다. Initialize는 크리에이터 수수료 활성화를 지원하지 않습니다 — 해당 경로는 InitializeWithPermission입니다.
  • open_time은 호출자가 <= block_timestamp 값을 전달한 경우 block_timestamp + 1로 범프됩니다. 스왑은 open_time 이전에 거부됩니다. 입금과 출금은 즉시 작동합니다.
일반적인 오류 (전체 목록은 reference/error-codes에서)
  • InvalidInput — 민트가 정렬되지 않았거나 동일한 민트입니다.
  • NotSupportMint — 차단된 Token-2022 확장입니다.
  • ExceededSlippage — 드물게; init_amount_0/1이 소수 자릿수 불일치로 인해 0 LP를 초래하는 경우입니다.

Deposit

두 토큰에 풀의 비율에 맞춰 유동성을 추가합니다. 인자
계정 수학
두 가지 중요한 세부사항: 비례 기준은 수수료 제외 볼트 총액(vault_amount_without_fee, 즉 원본 잔액에서 누적된 프로토콜, 펀드, 크리에이터 카운터를 뺀 값)이며, 원본 볼트 잔액이 아닙니다. 슬리피지 상한은 지급자가 실제로 이체하는 금액(Token-2022 이체 수수료가 추가된 후)에 대해 확인되며, 총 볼트 이동에 대해서는 아닙니다. k의 비례성에는 변화가 없습니다. 총액과 lp_supply 모두 동일한 계수로 확대됩니다. 사후 조건
  • lp_supply += lp_token_amount.
  • vault_0 += needed_token_0 (입력에 대한 Token-2022 이체 수수료 제외).
  • vault_1 += needed_token_1 (입력에 대한 Token-2022 이체 수수료 제외).
일반적인 오류 — ExceededSlippage, ZeroTradingTokens, 예치가 일시 중지된 경우 InvalidStatus.

Withdraw

LP 토큰을 소각하고 기초 토큰을 비례적으로 받습니다. 인자
계정 처음 13개 계정은 Deposit과 동일하며, LP 토큰이 소각되므로 lp_mint는 쓰기 가능합니다. Withdraw는 추가로 14번째 계정인 memo_program(address = memo::ID로 제약)을 사용합니다. Deposit은 사용하지 않습니다. 13개 계정의 Withdraw는 Anchor 역직렬화에 실패하므로 LP는 나갈 수 없습니다. 수학
사후 조건
  • lp_supply -= lp_token_amount.
  • 볼트는 out_token_0 / out_token_1을 전송합니다 (총액; 사용자는 Token-2022 이체 수수료 제외 순액을 받습니다).

SwapBaseInput

정확한 입력 스왑입니다. 인자
계정 순서는 입력 → 출력으로 풀의 정규 token_0 / token_1이 아닌 사용자의 방향입니다. 프로그램은 민트를 일치시켜 어느 볼트가 어느 것인지 파악합니다. 수학 — products/cpmm/math를 참조하세요. 전제 조건
  • open_time <= now.
  • pool_status가 스왑을 허용합니다.
  • 이 권한에 대해 민트가 일시 중지되거나 동결되지 않았습니다.
  • amount_in > 0.
일반적인 오류
  • ExceededSlippage — amount_out < minimum_amount_out.
  • ZeroTradingTokens — 거래가 0으로 반올림됩니다.
  • NotApproved — UpdatePoolStatus를 통해 스왑에 대해 풀이 일시 중지되었습니다.
  • InvalidInput — 민트가 풀의 볼트 민트 중 어느 것과도 일치하지 않습니다.

SwapBaseOutput

정확한 출력 스왑입니다. 인자
계정 — SwapBaseInput과 동일합니다. 수학 — 천장값이 있는 역곡선, products/cpmm/math를 참조하세요. 일반적인 오류 — ExceededSlippage (gross_in > max_amount_in), ZeroTradingTokens, InvalidInput, NotApproved.

CollectProtocolFee

볼트에서 누적된 프로토콜 수수료를 프로토콜 대상으로 이체합니다. 인자 — 없음. 계정 효과
곡선의 유효 잔액에는 변화가 없습니다 (누적된 수수료는 이미 제외되었습니다). 일반적인 오류 — 서명자가 amm_config.protocol_owner도 프로그램 관리자도 아닌 경우 InvalidOwner (6001). (이 경로에는 NotApproved가 없습니다.)

CollectFundFee

CollectProtocolFee와 동일한 형태이지만 amm_config.fund_owner에 의해 서명됩니다. 또는 프로그램 관리자에 의해 서명되며, fund_fees_* 카운터를 0으로 설정합니다. 잘못된 서명자에 대해 동일한 InvalidOwner가 발생합니다.

CollectCreatorFee

pool_state.pool_creator에 의해 서명됩니다. 누적된 크리에이터 수수료를 정산하고 크리에이터의 부분을 크리에이터의 토큰 계정으로 이체합니다. 인자 — 없음. 계정 효과
프로토콜의 부분은 여기서 볼트를 떠나지 않습니다. 프로토콜 수수료로 다시 레이블이 지정되고 CollectProtocolFee를 기다립니다. 두 카운터 모두 이미 곡선의 볼트 보기에서 제외되므로 풀의 가격은 움직이지 않습니다. 전체 유도는 products/cpmm/fees를 참조하세요. 일반적인 오류 — 두 크리에이터 카운터가 모두 0일 때 NoFeeCollect (분할 전에 확인됨), 해결된 share_rate가 1_000_000을 초과하는 경우 InvalidInput (6003), 공유를 예약하면 protocol_fees_token_*이 오버플로우되는 경우 MathOverflow (6011), creator_fee_share가 정규 PDA가 아닌 경우 Anchor의 ConstraintSeeds 오류.

CollectCreatorFeePermissionless

누구나 크리에이터 수수료 수집을 트리거할 수 있습니다. 이 명령어는 항상 크리에이터의 몫을 pool_state.pool_creator가 소유한 정규 연결 토큰 계정으로 전송합니다. 호출자는 다른 크리에이터나 목적지를 선택할 수 없습니다. ATA 중 하나라도 없으면 지불자가 생성 비용을 부담합니다. 원래의 CollectCreatorFee는 계속 호출 가능하므로, 자신의 수집에 서명하고 싶은 크리에이터는 여전히 그렇게 할 수 있습니다. 인자 — 없음. 계정
두 개의 새로운 계정은 system_program 뒤에 추가되며, 삽입되지 않습니다. payer부터 system_program까지의 모든 계정은 업그레이드 전의 위치를 유지하므로, 구분이 명확합니다. 업그레이드 전 14개 계정 레이아웃으로 구성된 트랜잭션은 볼트를 설정으로 잘못 읽지 않습니다. 단순히 계정이 너무 적어서 Anchor가 제약이 실행되기 전에 AccountNotEnoughKeys (3005)로 거부합니다. 계정은 여전히 필수이므로 둘 다 추가하고 IDL을 새로고침하세요. 이전 레이아웃에 대한 호환성 경로는 없습니다.
효과 — CollectCreatorFee 위와 동일합니다. 공유는 creator_fee_share 또는 amm_config에서 해결되고, 프로토콜의 몫은 protocol_fees_token_{0,1}에 기록되며, 크리에이터의 몫은 크리에이터 ATA로 전송되고, 두 크리에이터 카운터는 0으로 설정되며, recent_epoch이 업데이트됩니다. 두 카운터가 모두 0일 때 NoFeeCollect를 반환합니다.

UpdatePoolStatus

풀의 개별 작업을 일시 중지하거나 재개합니다. status 필드는 비트마스크입니다. 인자
계정 관리자 키는 프로그램에 컴파일된 pubkey입니다 (crate::admin::ID). BPF 업그레이드 권한이 아닙니다. 변경하려면 프로그램 업그레이드가 필요합니다. 값은 reference/program-addresses를 참조하고, 보유자는 security/admin-and-multisig를 참조하세요.

CreateAmmConfig

새로운 수수료 계층을 생성합니다. 인자
계정 전제 조건
  • 동일한 index를 가진 기존 AmmConfig가 없어야 합니다.
  • protocol_fee_rate + fund_fee_rate <= FEE_RATE_DENOMINATOR_VALUE.
2026-09에서 변경됨: 새 설정의 수수료 소유자는 더 이상 서명자로부터 오지 않습니다. create_amm_config는 이제 프로그램의 하드코딩된 protocol_fee_owner::ID를 protocol_owner에 쓰고 fund_fee_owner::ID를 fund_owner에 쓰며, 관리자 서명자의 키를 둘 다에 복사하지 않습니다. 주소는 reference/program-addresses에 있습니다.결과: 새로 생성된 AmmConfig의 수수료는 전용 수수료 지갑으로 이동합니다. 관리자는 여전히 수집을 위한 수락된 서명자로 남아 있습니다. CollectProtocolFee / CollectFundFee는 amm_config.protocol_owner / fund_owner 또는 crate::admin::ID를 수락합니다. 따라서 수집을 위해 아무것도 회전할 필요가 없습니다. 변경된 것은 기본적으로 수익이 가는 위치뿐입니다. 기존 AmmConfig 계정은 다시 쓰이지 않습니다. 저장된 내용이 계속 적용되므로, 항상 계정에서 protocol_owner / fund_owner를 읽고 어느 값이든 가정하지 마세요. UpdateAmmConfig 매개변수 3과 4는 여전히 이들을 회전합니다.

UpdateAmmConfig

기존 AmmConfig의 수수료 비율 또는 소유권을 변경합니다. param: u8 (업데이트할 필드)과 value: u64를 사용합니다. 전체 디스패치 테이블:
  • param = 0 → trade_fee_rate (asserts trade_fee_rate + creator_fee_rate < 1_000_000)
  • param = 1 → protocol_fee_rate (asserts ≤ 1_000_000 and + fund_fee_rate ≤ 1_000_000)
  • param = 2 → fund_fee_rate (asserts ≤ 1_000_000 and + protocol_fee_rate ≤ 1_000_000)
  • param = 3 → protocol_owner. 새 키는 value에 없습니다: remaining_accounts[0]으로 추가합니다 (읽기 전용 가능). 기본 pubkey가 아니어야 하며, 계정을 생략하면 unwrap()에서 패닉합니다.
  • param = 4 → fund_owner. 3과 동일한 메커니즘입니다.
  • param = 5 → create_pool_fee
  • param = 6 → disable_create_pool (0이 아닌 value는 비활성화)
  • 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). 2026-09-19 추가. 이 계층에서 크리에이터 수수료의 프로토콜 기본 공유입니다. products/cpmm/fees를 참조하세요. 거래 수수료를 분할하는 protocol_fee_rate와는 관련이 없습니다.
다른 param은 InvalidInput을 반환합니다. 변경 사항은 관리자가 서명하며 다음 스왑에서 이 AmmConfig에 바인딩된 모든 풀에 영향을 미칩니다. 마이그레이션 없음. 풀은 단순히 새 값을 읽습니다.

CreateCreatorFeeShare

하나의 (creator, amm_config) 쌍에 대한 크리에이터 수수료의 사용자 정의 프로토콜 공유를 설정하여, 해당 수수료 계층에서 해당 크리에이터가 소유한 모든 풀에 대해 AmmConfig.creator_fee_share_rate를 재정의합니다. 2026-09-19 크리에이터 수수료 공유 업그레이드에서 추가되었습니다. 인자
계정 전제 조건
  • share_rate <= 1_000_000, 그렇지 않으면 InvalidInput (6003).
  • PDA가 아직 존재하지 않아야 합니다. Anchor의 init은 동일한 쌍에 대한 두 번째 호출에서 실패합니다. 비율을 변경하려면 계정을 닫고 다시 생성하세요.
사후 조건
  • creator_fee_share는 bump, creator, amm_config 및 share_rate를 저장합니다.
  • amm_config 아래 creator가 생성한 풀에서의 모든 후속 CollectCreatorFee / CollectCreatorFeePermissionless는 설정 대신 이 계정에서 공유를 해결합니다.
풀 크리에이터는 이 명령어의 당사자가 아니며 서명하지 않습니다. 비율은 수집 시간에 읽히므로, 수수료가 이미 누적된 후에 생성된 재정의는 해당 누적 잔액에도 적용됩니다.

CloseCreatorFeeShare

재정의를 제거합니다. 쌍은 AmmConfig.creator_fee_share_rate로 돌아갑니다. 인자 — 없음. 계정 사후 조건
  • 계정이 닫히고 그 lamport는 owner로 이동합니다.
  • 해당 쌍에 대한 수집은 다시 amm_config.creator_fee_share_rate에서 공유를 해결합니다. 관리자가 UpdateAmmConfig 매개변수 8을 설정하지 않은 한 이는 0입니다.

CollectExcessLamports

CPMM이 관리하는 계정에서 최소 렌트 면제액을 초과하는 램포트를 관리자가 회수하는 명령어입니다. 2026-09 업그레이드에서 추가되었으며, SIMD-0437 렌트 감소로 인해 각 단계 이전에 생성된 계정에 남겨진 초과 자금을 프로토콜이 회수할 수 있도록 합니다. 초과분만 이동합니다. 토큰 잔액, 계정 데이터, 소유자, 풀 상태 및 곡선은 변경되지 않으며, 이미 최소값에 있는 계정에 대해서는 명령어가 작동하지 않으므로 각 롤아웃 단계 후에 다시 실행해도 안전합니다. 인수 — 없음. 계정
정렬 수정, 2026-09-19. 프로그램은 이제 remaining_accounts에 대해 두 번 통과합니다 — 모든 토큰 프로그램 CPI를 먼저 실행한 후 CPMM 소유 PDA의 직접 차감을 실행합니다. PDA가 CPI보다 먼저 차감될 때마다 인터리빙하면 런타임의 UnbalancedInstruction (“명령어 전후 계정 잔액의 합이 일치하지 않음”)으로 중단되었습니다. 이는 호출자의 보류 중인 램포트 변경이 CPI가 실제로 수행하는 계정에만 플러시되기 때문입니다. 호출자는 목록을 직접 그룹화하거나 정렬할 필요가 없습니다.
각 소스 계정 처리 방식 프로그램은 소스 계정의 owner에 따라 처리합니다: 무제한 remaining_accounts 목록을 사용하므로 트랜잭션 크기가 실제 제한입니다 — solana-fundamentals/rent-and-reclaimable-rent에서 설명한 지갑 측 회수와 동일한 제약입니다. 일반적인 오류 — InvalidOwner (6001, 잘못된 서명자), LamportsCalculateError (6015, wSOL 왕복이 0으로 정산되지 않음), 계정이 자체 렌트 최소값보다 적게 보유할 때 프로그램 소유 경로의 InsufficientFunds. SDK 빌더 없음. @raydium-io/raydium-sdk-v2는 이 명령어에 대한 빌더를 제공하지 않으며, raydium-sdk-V2-demo 저장소도 마찬가지입니다 — 관리자 경로입니다. 수동으로 인코딩하세요. solana-fundamentals/rent-and-reclaimable-rent의 지갑 측 회수가 토큰 프로그램 명령어에 대해 수행하는 방식처럼 말입니다.

상태 변경 매트릭스

다음 단계

출처: