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_mint는 LP 토큰이 소각되므로 쓰기 가능합니다. 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

볼트에서 누적된 프로토콜 수수료를 프로토콜 대상으로 수집합니다. 인자 — 없음. 계정 효과
곡선의 유효 잔액에 변화 없음 (누적된 수수료는 이미 제외됨). 일반적인 오류 — InvalidOwner (6001) (서명자가 amm_config.protocol_owner 또는 프로그램 관리자가 아닌 경우). (이 경로에는 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 필드는 비트마스크입니다: 인자
계정 관리자 키는 프로그램에 컴파일된 공개키 (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 (어설션 trade_fee_rate + creator_fee_rate < 1_000_000)
  • param = 1 → protocol_fee_rate (어설션 ≤ 1_000_000 및 + fund_fee_rate ≤ 1_000_000)
  • param = 2 → fund_fee_rate (어설션 ≤ 1_000_000 및 + protocol_fee_rate ≤ 1_000_000)
  • param = 3 → protocol_owner. 새 키는 value에 없습니다: remaining_accounts[0]으로 추가합니다 (읽기 전용 괜찮음). 기본 공개키가 아니어야 하며, 계정을 생략하면 unwrap()에서 패닉합니다.
  • param = 4 → fund_owner. 3과 동일한 메커니즘.
  • param = 5 → create_pool_fee
  • param = 6 → disable_create_pool (0이 아닌 value는 비활성화)
  • param = 7 → creator_fee_rate (어설션 creator_fee_rate + trade_fee_rate < 1_000_000)
  • param = 8 → creator_fee_share_rate (어설션 ≤ 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이 제어하는 계정에서 최소 임차료 이상의 lamport의 관리자 수집. 2026-09 업그레이드에서 추가되어 프로토콜이 SIMD-0437 임차료 감소가 각 단계 전에 생성된 계정에 남기는 과잉 자금을 회수할 수 있습니다. 초과분만 이동합니다. 토큰 잔액, 계정 데이터, 소유자, 풀 상태 및 곡선은 변경되지 않으며, 명령어는 이미 최소값에 있는 계정에 대해 작동하지 않습니다 — 따라서 각 롤아웃 단계 후에 다시 실행하는 것이 안전합니다. 인자 — 없음. 계정
순서 수정, 2026-09-19. 프로그램은 이제 remaining_accounts에 대해 두 번의 패스를 만듭니다 — 모든 토큰-프로그램 CPI 먼저, 그 다음 CPMM 소유 PDA의 직접 차변. PDA가 CPI 앞에 차변되면 런타임의 UnbalancedInstruction (“명령어 전후의 계정 잔액 합이 일치하지 않음”)으로 중단되었습니다. 호출자가 실제로 수행하는 CPI만 보류 중인 lamport 변경 사항을 계정으로 플러시하기 때문입니다. 호출자는 목록을 직접 그룹화하거나 정렬할 필요가 없습니다.
각 소스 계정이 처리되는 방식 프로그램은 소스 계정의 owner에 따라 디스패치합니다: 무제한 remaining_accounts 목록을 사용하므로 거래 크기가 실제 제한입니다 — solana-fundamentals/rent-and-reclaimable-rent에 설명된 지갑 측 수집과 동일한 제약입니다. 일반적인 오류 — InvalidOwner (6001, 잘못된 서명자), LamportsCalculateError (6015, wSOL 왕복이 0으로 정산되지 않음), 그리고 계정이