이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
불변식
CPMM은 두 개의 볼트에서 고전적인 상수곱 불변식을 유지합니다: 여기서x는 수령 시 Token-2022 전송 수수료를 제외한 vault0 잔액이고, y도 마찬가지입니다. 모든 스왑은 LP에 적립된 거래 수수료를 고려한 후 k' ≥ k를 유지해야 합니다(프로토콜, 펀드, 크리에이터 버킷은 k에 포함되지 않습니다 — 볼트에 있지만 곡선 보기에서 제외됩니다. 아래의 곡선의 수수료 참조). 따라서 k는 LP가 수수료를 적립함에 따라 시간이 지남에 따라 단조증가합니다.
LP 주식은 풀의 준비금으로 가격이 책정되며, k로는 아닙니다:
ΔLP LP 토큰을 소각하면 정확히 ΔLP × x / lpSupply의 token0과 ΔLP × y / lpSupply의 token1을 반환합니다. 예치 또는 인출 시 곡선이나 k는 움직이지 않습니다 — 스왑만 가격을 변경합니다.
스왑 경로의 수수료 모델
CPMM은 모든 스왑에 두 개의 독립적으로 책정된 수수료를 적용합니다:- 거래 수수료는 입력 측에서 가져오며,
AmmConfig.trade_fee_rate로 청구됩니다. 그런 다음 LP, 프로토콜, 펀드 주식으로 분할됩니다(LP 주식은 볼트에 남아k를 증가시키고, 프로토콜 및 펀드 주식은 볼트 회계에서 추출됩니다). - 크리에이터 수수료(오직
enable_creator_fee == true일 때만 활성화)는AmmConfig.creator_fee_rate로 청구됩니다.PoolState.creator_fee_on과 스왑 방향에 따라 입력 측이나 출력 측에서 가져옵니다(products/cpmm/fees참조). 이는 자체 버킷입니다 — 거래 수수료의 일부가 아닙니다.
크리에이터 수수료의 프로토콜 주식은 이 페이지의 어디에도 나타나지 않으며, 이는 의도적입니다.
CollectCreatorFee가 곡선이 이미 제외하는 두 개의 카운터 사이에서 적립된 수수료를 이동할 때 적용됩니다 — 스왑 중이 아닙니다. 스왑 수학, 견적 및 k는 이것이 있든 없든 동일합니다. products/cpmm/fees 참조.FEE_RATE_DENOMINATOR = 1_000_000trade_fee_rate—AmmConfig에서, 예:2500= 관련 거래량 측의 0.25%creator_fee_rate—AmmConfig에서, 예:1000= 관련 거래량 측의 0.10%protocol_fee_rate,fund_fee_rate— 거래량이 아닌 거래 수수료의1/FEE_RATE_DENOMINATOR단위로 표시됨
protocol_fee + fund_fee + creator_fee 금액은 볼트에 보관되지만 풀 상태에서 별도로 추적됩니다(protocol_fees_token*, fund_fees_token*, creator_fees_token*). 상수곱 불변식이 k' ≥ k를 확인할 때, 볼트 잔액에서 세 가지 적립되었지만 아직 수집되지 않은 수수료를 뺀 값을 사용합니다 — 따라서 LP는 lp_fee만 캡처합니다.
수집 지침 및 작동 수치 예제는 products/cpmm/fees를 참조하세요.
SwapBaseInput (입력 정확)
“사용자가 정확히 입력 민트의amount_in을 제공하고 출력 민트의 최소 minimum_amount_out을 받습니다.”
일단 Token-2022를 무시하면:
Δx_net = amount_in_after_trade_fee입니다.
그런 다음 프로그램은 거래 수수료 중 프로토콜/펀드/크리에이터에 해당하는 부분이 “적립된” 버킷에 앉도록 볼트 회계를 업데이트합니다(다음 스왑의 곡선에 포함되지 않음). 동시에 LP 주식은 다음 스왑을 위해 x에 합류합니다.
입력 측의 Token-2022
입력 민트에 전송 수수료 확장이 있으면, 민트는 사용자 → 볼트 전송 시 수수료를 공제합니다. 따라서 볼트는 실제로amount_in − transfer_fee_in(amount_in)을 받습니다. CPMM 프로그램은 따라서 다음을 계산합니다:
amount_in_after_trade_fee에 대해 곡선을 실행합니다. 이는 곡선 가격이 사용자의 헤드라인 금액이 아닌 볼트에 실제로 도착한 순 금액에서 계산되기 때문에 중요합니다.
출력 측의 Token-2022
출력 민트에 전송 수수료가 있으면, 풀은 자신의 볼트에서 사용자에게amount_out을 보냅니다. 민트는 그런 다음 나가는 길에 수수료를 공제하므로, 사용자는 amount_out − transfer_fee_out(amount_out)을 받습니다. 프로그램은 평소대로 곡선에서 amount_out을 계산하지만, 견적을 표시할 때 풀의 “볼트 전송” 숫자를 “사용자 수신” 숫자로 변환하는 것은 통합자의 책임입니다.
슬리피지 확인
amount_out을 계산한 후:
minimum_amount_out 설정 전에 적용하므로 슬리피지 상수는 볼트가 보내는 것이 아닌 사용자가 실제로 받을 것으로 표시됩니다.
SwapBaseOutput (출력 정확)
“사용자는 정확히 출력 민트의amount_out을 받고 입력 민트의 최대 maximum_amount_in을 지불할 의향이 있습니다.”
Δx_net에 대해 곡선을 반전시키면:
천장은 중요합니다 — 정수 절단 후 k' ≥ k를 보장합니다. 그런 다음:
gross_needed를 받습니다.
슬리피지 확인
작동 예제
풀 상태, Token-2022 무시:x = 1_000_000_000_000(token0 1,000,000.000000, 6 소수 자리)y = 2_000_000_000_000(token1 2,000,000.000000, 6 소수 자리)AmmConfig:trade_fee_rate = 2500,protocol_fee_rate = 120_000,fund_fee_rate = 40_000,creator_fee_rate = 0
amount_in = 1_000_000_000 (token0 1,000.000000)으로 SwapBaseInput. 크리에이터 수수료 비활성화(enable_creator_fee = false).
enable_creator_fee = true와 creator_fee_rate = 1000 (0.10%)을 가지고 있었다면, 프로그램은 total_input_fee = ceil(1_000_000_000 * 3500 / 1_000_000) = 3_500_000을 청구한 다음 creator_fee = 1_000_000과 trade_fee = 2_500_000으로 분할합니다. trade_fee에 대한 프로토콜/펀드/LP 산술은 위의 예제와 동일합니다 — 크리에이터 수수료는 자체 버킷이며, creator_fees_token0에 적립되고 프로토콜 및 펀드 버킷과 함께 curve_x에서 제외됩니다.
입력 민트에 1% Token-2022 전송 수수료가 있으면, 볼트는 1_000_000_000 대신 990_000_000 토큰을 받고, 모든 후속 계산은 해당 순 금액을 사용합니다.
관찰 업데이트 규칙
모든 스왑에서 프로그램은 링 버퍼에 새 관찰을 푸시할지 여부를 평가합니다:- 누적 가격, 현물 가격 아님. 단일 관찰은 가격이 아닙니다. 시간
t0에서t1까지의 TWAP을 얻으려면 각 끝에 가장 가까운 관찰을 읽고(cumulative(t1) − cumulative(t0)) / (t1 − t0)을 계산합니다. - 샘플은 속도 제한됩니다. 동일한 슬롯에서 연속된 스왑은 하나의 관찰을 공유할 수 있습니다. 스왑 직후 관찰을 읽으면 한 슬롯만큼 오래된 것처럼 보일 수 있습니다 — 이는 정상입니다.
products/clmm/accounts를 참조하세요.
곡선의 수수료
이것이 미묘한 부분이며 언급할 가치가 있습니다. 곡선 산술은 순 볼트 잔액에 대해 작동합니다 — 즉, 원본 SPL 잔액에서 적립된 프로토콜, 펀드, 크리에이터 수수료를 뺀 값(세 가지 모두 독립적인 버킷입니다 —products/cpmm/fees 참조). 구체적인 그림:
- 원본 잔액에서 견적을 제시하지 마세요. 먼저 적립된 수수료 필드를 빼거나
SwapBaseInput을 시뮬레이션으로 호출하고 반환값을 가져옵니다. CollectProtocolFee는 토큰을 볼트 밖으로 이동합니다. 수집 후,raw_vault_balance는 떨어지지만curve_balance는 변하지 않습니다. 풀의 가격은 움직이지 않습니다. 이는 의도적입니다.
정밀도 및 오버플로우
- 모든 곡선 산술은
x * y에서 오버플로우를 방지하기 위해u128중간값을 사용합니다. - 나눗셈은 0을 향해 반올림합니다. 단,
SwapBaseOutput의Δx_net은 올림하고, 수수료 계산은trade_fee에서 올림하고 부분 분할에서 내림합니다. 이러한 반올림 방향은 정수 절단으로 인해 불변식이 감소하지 않도록 선택됩니다. - 극단적인 볼트 비율(수십억 : 1)을 가진 풀은 작은 거래에서 정밀도 바닥에 도달할 수 있습니다. 프로그램은 이 경우
ZeroTradingTokens을 반환합니다.reference/error-codes참조.
다음으로 갈 곳
products/cpmm/fees— 전체 수수료 계층 및 수집 의미론.products/cpmm/instructions— 이 수학을 호출하는 지침.algorithms/constant-product— AMM v4 및 CPMM에서 공유되는x · y = k의 유도 및 엣지 케이스.
raydium-io/raydium-cp-swap—states/curve.rs의 스왑 수학security/audits에 링크된 Raydium 감사 보고서

