> ## 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.

# CPMM 수수료

> CPMM이 거래 수수료와 별도의 크리에이터 수수료를 어떻게 부과하고, 거래 수수료를 LP, 프로토콜 트레저리, 펀드 멀티시그 간에 어떻게 분배하며, 누가 언제 수수료를 수거하는지 설명합니다.

<Info>
  **이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.**

  [영문판 보기 →](/products/cpmm/fees)
</Info>

## 두 개의 독립적인 수수료, 네 개의 목적지

CPMM은 모든 스왑에 **두 개의 별도 비율의 수수료**를 부과합니다:

1. **거래 수수료** — `AmmConfig.trade_fee_rate`에서 부과되며 세 개의 목적지로 분배됩니다:
   * **LP 몫** — 볼트에 남아 `k`를 증가시킵니다. LP 토큰을 소각하여 암시적으로 청구됩니다.
   * **프로토콜 몫** — `PoolState.protocol_fees_token*`에 누적되며, `CollectProtocolFee`를 통해 `protocol_owner`가 수거합니다.
   * **펀드 몫** — `PoolState.fund_fees_token*`에 누적되며, `CollectFundFee`를 통해 `fund_owner`가 수거합니다.
2. **크리에이터 수수료** (선택 사항, 풀별) — `AmmConfig.creator_fee_rate`에서 부과되며 거래 수수료와 **독립적**이고, `PoolState.creator_fees_token*`에 누적되며, `CollectCreatorFee`를 통해 `pool_state.pool_creator`가 수거합니다. 풀이 `enable_creator_fee = true`로 생성된 경우에만 활성화됩니다.

크리에이터 수수료는 거래 수수료의 일부가 **아닙니다**. 두 비율은 스왑 입력에서 수수료를 취할 때 함께 추가되지만, 각각은 자신의 버킷으로 유지됩니다 — 프로토콜과 펀드 몫은 항상 `trade_fee`에서만 파생되며, `creator_fee`에서는 절대 파생되지 않습니다. `creator_fee_rate = 1000` (0.10%)과 `trade_fee_rate = 2500` (0.25%)을 가진 풀은 크리에이터-수수료-온-입력 스왑에서 입력의 0.35%를 청구하며, 이 중 크리에이터가 0.10%을 유지하고 거래 수수료 버킷이 0.25%를 받습니다.

거래 수수료 비율(`trade_fee_rate`, `protocol_fee_rate`, `fund_fee_rate`)과 `creator_fee_rate` 모두 `AmmConfig`에 존재합니다. 풀별 `enable_creator_fee` 플래그와 `creator_fee_on` 모드(거래의 어느 쪽에서 크리에이터 수수료를 취할지)는 `PoolState`에 존재합니다. [`products/cpmm/accounts`](/ko/products/cpmm/accounts)를 참조하세요.

## 비율과 단위

모든 비율은 `1 / FEE_RATE_DENOMINATOR` 단위로 계산된 `u64`이며, 여기서 `FEE_RATE_DENOMINATOR = 1_000_000`입니다.

* \*\*`trade_fee_rate`\*\*은 **스왑 거래량**의 분수입니다. `2500` ⇒ 관련 쪽의 0.25% (입력 또는 출력, `creator_fee_on`에 따라 다름 — 아래 "거래의 어느 쪽에서 수수료를 취할지" 참조).
* \*\*`creator_fee_rate`\*\*은 **스왑 거래량**의 분수이며, 거래 수수료와 **별도로** 취합니다. `1000` ⇒ 관련 쪽의 0.10%.
* \*\*`protocol_fee_rate`\*\*과 \*\*`fund_fee_rate`\*\*은 거래량이 아닌 **거래 수수료**의 분수입니다. `120_000` ⇒ 거래 수수료의 12%.

메인넷의 `AmmConfig[index=0]` (표준 0.25% 풀)에 대한 기본 파라미터 참조용:

| 필드                  | 값         | 실제 퍼센트                        |
| ------------------- | --------- | ----------------------------- |
| `trade_fee_rate`    | `2500`    | 거래량의 0.25% (거래 수수료 버킷)        |
| `protocol_fee_rate` | `120000`  | 거래 수수료의 12% ≈ **거래량의 0.030%** |
| `fund_fee_rate`     | `40000`   | 거래 수수료의 4% ≈ **거래량의 0.010%**  |
| `creator_fee_rate`  | `0` (기본값) | 0% (별도 버킷)                    |
| → LP 몫 실제           |           | **거래량의 0.210%**               |

따라서 `AmmConfig[0]`에 대해 `enable_creator_fee = false`인 \$1,000 스왑에서: 총 \$2.50 거래 수수료 중 \$2.10이 LP와 남고, \$0.30이 프로토콜로, \$0.10이 펀드로 갑니다. 크리에이터 버킷은 크리에이터 수수료가 비활성화되어 있으므로 0입니다.

같은 풀이 `enable_creator_fee = true`이고 `creator_fee_rate = 1000` (0.10%)을 가지면, 사용자는 `creator_fee_on`으로 설정된 같은 쪽의 거래에서 취해진 추가 \$1.00을 크리에이터 버킷에 지불합니다 — 총 \$3.50의 수수료를 위해서입니다. 거래 수수료 버킷과 프로토콜/펀드 분배는 변경되지 않습니다.

현재 메인넷 값을 `GET https://api-v3.raydium.io/main/cpmm-config`에서 확인하세요 — 비율은 관리자가 변경 가능하며 하드코딩하기보다는 신선하게 읽어야 합니다.

## 코드의 분배

```rust theme={null}
// raydium-cp-swap/programs/cp-swap/src/curve/{calculator,fees}.rs에서 의역됨.
// 실제 코드는 `is_creator_fee_on_input`에서 분기합니다; 두 분기 모두
// creator_fee가 자신의 비율이며 trade_fee의 조각이 아니라는 불변성을 유지합니다.

const FEE_RATE_DENOMINATOR_VALUE: u64 = 1_000_000;

pub struct FeeBreakdown {
    pub amount_in_after_fees: u64,    // 입력 수수료 차감
    pub amount_out_after_fees: u64,   // 출력에서 취해진 크리에이터 수수료 차감
    pub trade_fee:    u64,            // → 아래의 LP / 프로토콜 / 펀드 버킷으로 분배
    pub protocol_fee: u64,            // trade_fee의 몫
    pub fund_fee:     u64,            // trade_fee의 몫
    pub creator_fee:  u64,            // 독립적인 버킷 (입력 또는 출력 쪽)
}

fn take_fees_on_input(
    amount_in: u64,
    trade_rate: u64,
    creator_rate: u64,
    protocol_rate: u64,
    fund_rate: u64,
) -> (u64 /* trade_fee */, u64 /* creator_fee */, u64 /* amount_in_after_fees */) {
    // 두 비율이 추가되므로 조합 수수료에서 한 번만 반올림한 후
    // 비례적으로 분배합니다 — 이는 순전히 반올림/효율성 트릭입니다.
    // 분배는 비율을 정확히 따릅니다: creator_fee/trade_fee == creator_rate/trade_rate.
    let total_fee = ((amount_in as u128) * ((trade_rate + creator_rate) as u128))
        .div_ceil(FEE_RATE_DENOMINATOR_VALUE as u128) as u64;

    let creator_fee = ((total_fee as u128) * (creator_rate as u128)
                       / ((trade_rate + creator_rate) as u128)) as u64;
    let trade_fee   = total_fee - creator_fee;

    (trade_fee, creator_fee, amount_in - total_fee)
}

fn take_creator_fee_on_output(amount_out_swapped: u64, creator_rate: u64) -> (u64, u64) {
    // creator_fee_on이 크리에이터 수수료를 출력 쪽으로 라우팅할 때,
    // trade_fee는 입력에서 단일 비율로 취해지고, creator_fee는
    // 곡선 출력에 대해 계산됩니다.
    let creator_fee = ((amount_out_swapped as u128) * (creator_rate as u128))
        .div_ceil(FEE_RATE_DENOMINATOR_VALUE as u128) as u64;
    (amount_out_swapped - creator_fee, creator_fee)
}

fn split_trade_fee(
    trade_fee: u64,
    protocol_rate: u64,
    fund_rate: u64,
) -> (u64 /* protocol_fee */, u64 /* fund_fee */) {
    let protocol_fee = (trade_fee as u128 * protocol_rate as u128
                        / FEE_RATE_DENOMINATOR_VALUE as u128) as u64;
    let fund_fee     = (trade_fee as u128 * fund_rate as u128
                        / FEE_RATE_DENOMINATOR_VALUE as u128) as u64;
    (protocol_fee, fund_fee)
}
```

참고:

* 입력의 총 수수료는 **올림**하므로 풀이 과소 청구하지 않습니다.
* `trade_fee`의 부분 분배 (프로토콜, 펀드)는 **내림**하므로 합이 `trade_fee`를 초과하지 않습니다; 나머지가 LP 몫입니다.
* `lp_share = trade_fee − protocol_fee − fund_fee` (creator\_fee는 자신의 버킷이기 때문에 여기서 **차감되지 않습니다**).
* 크리에이터 수수료는 입력 또는 출력에서 `PoolState.creator_fee_on`에 따라 취합니다 (다음 섹션 참조). 비율은 어느 쪽이든 변경되지 않습니다.

## 거래의 어느 쪽에서 수수료를 취할지

CPMM은 풀별 `creator_fee_on` 설정 (`BothToken` / `OnlyToken0` / `OnlyToken1`)을 가지며, 이는 크리에이터 수수료가 주어진 스왑의 **입력** 쪽에서 취해질지 **출력** 쪽에서 취해질지를 결정합니다. 런타임 헬퍼 `is_creator_fee_on_input(direction)`은 스왑별로 이를 부울로 축약합니다:

| `creator_fee_on`   | 스왑 `0 → 1` | 스왑 `1 → 0` |
| ------------------ | ---------- | ---------- |
| `BothToken` (`0`)  | 입력 쪽       | 입력 쪽       |
| `OnlyToken0` (`1`) | 입력 쪽       | 출력 쪽       |
| `OnlyToken1` (`2`) | 출력 쪽       | 입력 쪽       |

크리에이터 수수료가 **입력** 쪽에 있을 때, 거래 수수료와 크리에이터 수수료 모두 곡선이 실행되기 전에 `amount_in`에서 차감됩니다. 가격 계산: `trade_rate + creator_rate`를 입력에서 빼십시오.

크리에이터 수수료가 **출력** 쪽에 있을 때, 거래 수수료만 `amount_in`에서 차감됩니다; 곡선은 수수료 없는 출력을 생성한 후, 크리에이터 수수료가 그 출력에서 차감됩니다. 가격 계산: `trade_rate`를 입력에서 빼고; `creator_rate`를 출력에서 빼십시오.

거래 수수료 자체는 항상 입력 쪽에서 취합니다 (표준 Uniswap-V2 패턴). 크리에이터 수수료만 출력에 도착할 수 있습니다.

## "누적된" 수수료가 곡선과 상호작용하는 방식

중요한 미묘한 점: **프로토콜, 펀드, 크리에이터 수수료는 각 `Collect*` 명령어가 호출될 때까지 물리적으로 볼트에 남아 있습니다**. 하지만 곡선의 볼트 잔액 보기에서는 제외됩니다.

한 스왑 후의 구체적인 그림:

```
raw_vault_0_balance = getTokenAccountBalance(vault_0).amount
                    = lp_entitled + protocol_fees_token0
                      + fund_fees_token0 + creator_fees_token0

curve_x = raw_vault_0_balance − (protocol_fees_token0
                                  + fund_fees_token0
                                  + creator_fees_token0)
```

프로그램은 `k' ≥ k`를 강제할 때 `curve_x` (및 유사한 `curve_y`)를 사용합니다. 이것이 비-LP 수수료가 **LP 몫을 부풀리지 않고** 목적지에 도달하는 방식입니다.

설계해야 할 결과:

* **원시 잔액에서 가격 계산은 잘못되었습니다.** `getTokenAccountBalance`에서 가격 계산기를 작성하면, 풀이 수용할 가격을 지속적으로 과대평가합니다. 항상 누적된 수수료를 빼거나, `SwapBaseInput` / API를 통해 시뮬레이션하세요.
* **`CollectProtocolFee`는 가격을 이동하지 않습니다.** 토큰을 볼트 밖으로 이동하고 `protocol_fees_token*` 카운터를 0으로 설정하므로, `curve_x`와 `curve_y`는 변경되지 않습니다.
* **LP 수수료는 카운터에 누적되지 않습니다.** 이들은 볼트 잔액에 암시적입니다. LP의 누적된 LP 수수료에 대한 자격은 LP 토큰을 소각하여 행사됩니다 (`Withdraw`를 통해) — `CollectLpFee`는 없습니다.

## Token-2022 전송 수수료와의 상호작용

Token-2022 전송 수수료는 CPMM이 아닌 **민트**에서 적용됩니다. 모든 토큰 전송에 작용합니다 — 스왑, 예치, 인출, `Collect*` 수거. CPMM의 거래 수수료 계산은 **실제로 볼트에 도착한** 금액에 대해 계산됩니다. 즉, 입력 민트의 전송 수수료를 차감한 것입니다 (있는 경우).

따라서 최악의 경우 사용자는 입력-정확 스왑에서 세 가지 서로 다른 세금을 지불합니다:

1. 입력 민트의 전송 수수료 (민트의 수수료 권한에).
2. 풀의 `trade_fee` (위와 같이 분배됨).
3. 출력 민트의 전송 수수료 (민트의 수수료 권한에).

SDK의 가격 계산기는 세 가지를 모두 고려하므로 `minimum_amount_out`은 사용자가 실제로 받는 것으로 표시됩니다. 자신만의 가격 계산기를 작성하는 경우, 그 동작을 반영하세요. 그렇지 않으면 슬리피지 확인이 체계적으로 너무 관대할 것입니다.

자세한 유도는 [`algorithms/token-2022-transfer-fees`](/ko/algorithms/token-2022-transfer-fees)를 참조하세요.

## 크리에이터 수수료

크리에이터 수수료는 선택 사항이며 풀별입니다. **비율**은 `AmmConfig.creator_fee_rate`에 있습니다; **활성화 플래그**와 **쪽** (`creator_fee_on`)은 `PoolState`에 있습니다:

* **풀 생성 시 활성화됩니다.** `Initialize`는 기본적으로 `enable_creator_fee = false`로 설정합니다; `InitializeWithPermission`을 통해 생성된 풀 (LaunchLab 졸업 및 기타 게이티드 경로에서 사용)은 `enable_creator_fee = true`를 전달하고 `creator_fee_on`을 선택할 수 있습니다.
* **비율은 수수료 티어와 공유됩니다.** 비율 자체는 `AmmConfig.creator_fee_rate`이며, 그 설정에 바인딩된 모든 풀에서 같은 값입니다. 각 풀은 그 후 이를 청구할지 (`enable_creator_fee`) 결정하고 스왑의 어느 쪽에서 청구할지 (`creator_fee_on`)를 결정합니다. `enable_creator_fee = false`일 때, 풀의 유효 크리에이터-수수료 비율은 설정 값에 관계없이 0입니다 (소스에서 `PoolState::adjust_creator_fee_rate` 참조).
* **거래 수수료와 독립적입니다.** 크리에이터 수수료는 LP / 프로토콜 / 펀드 몫을 절대 줄이지 않습니다 — 자신의 비율이며, 별도로 적용되고, 자신의 카운터에 누적됩니다.
* **`CollectCreatorFee`를 통해 수거되며**, `PoolState.pool_creator`에서 서명합니다.
* **생성 후 다시 활성화하거나 다시 라우팅할 수 없습니다.** `enable_creator_fee = false`로 초기화된 풀은 크리에이터 수수료를 청구하지 않습니다; 특정 `creator_fee_on`으로 초기화된 풀은 쪽을 전환할 수 없습니다.

크리에이터 수수료는 Raydium의 "Burn & Earn" 패턴의 메커니즘입니다: LP 토큰은 [LP Lock](/ko/reference/program-addresses) 프로그램에서 잠겨 있어 크리에이터가 유동성을 인출할 수 없지만, `CollectCreatorFee`를 무한정 청구할 수 있습니다.

## 수거 운영 흐름

\| 서명자 | 명령어 | 소스 카운터 0 | 카운터 1 | 일반적인 리듬 |
\|--------|-------------|------------------------|-----------------|
\| `amm_config.protocol_owner` | `CollectProtocolFee` | `protocol_fees_token{0,1}` | 주간 또는 프로그래밍 |
\| `amm_config.fund_owner` | `CollectFundFee` | `fund_fees_token{0,1}` | 주간 또는 프로그래밍 |
\| `pool_state.pool_creator` | `CollectCreatorFee` | `creator_fees_token{0,1}` | 언제든지 |

프로토콜과 펀드 소유자는 메인넷의 Raydium 멀티시그입니다; [`security/admin-and-multisig`](/ko/security/admin-and-multisig)를 참조하세요. 크리에이터 서명자는 `Initialize`를 실행한 계정입니다.

## 수수료 티어 변경

수수료 비율은 `UpdateAmmConfig`를 통해 관리자가 변경할 수 있습니다 (([`products/cpmm/instructions`](/ko/products/cpmm/instructions) 참조). 변경 사항은 해당 `AmmConfig`에 바인딩된 모든 풀에 대해 **다음 스왑**에서 적용됩니다 — 풀이 각 스왑에서 설정을 로드하기 때문에 마이그레이션이 없습니다.

관리자가 할 수 없는 것:

* 풀을 한 `AmmConfig`에서 다른 것으로 이동합니다.
* 이미 누적된 수수료를 소급으로 다시 가격 책정합니다.
* `protocol_owner` / `fund_owner` 서명자 없이 수수료를 수거합니다.

## 실행 중인 풀에서 수수료 읽기

```ts theme={null}
// 오프체인: 각 버킷의 현재 누적 수수료
const pool = await connection.getAccountInfo(poolStatePda);
const decoded = PoolState.decode(pool.data);
console.log(
  "Protocol accrued:",
  decoded.protocolFeesToken0.toString(),
  decoded.protocolFeesToken1.toString(),
);
console.log(
  "Fund accrued:",
  decoded.fundFeesToken0.toString(),
  decoded.fundFeesToken1.toString(),
);
console.log(
  "Creator accrued:",
  decoded.creatorFeesToken0.toString(),
  decoded.creatorFeesToken1.toString(),
);

// 오프체인: 오늘의 유효 비율.
// trade_fee_rate, creator_fee_rate는 거래량의 분수 (분모 1e6).
// protocol_fee_rate, fund_fee_rate는 *거래 수수료*의 분수 (같은 분모).
const config = await fetch("https://api-v3.raydium.io/main/cpmm-config")
  .then((r) => r.json());
const tier = config.data.find((t) => t.index === decoded.ammConfigIndex);

const tradeFeeOfVolume   = tier.tradeFeeRate / 1_000_000;
const protocolOfTradeFee = tier.protocolFeeRate / 1_000_000;
const fundOfTradeFee     = tier.fundFeeRate / 1_000_000;
const lpOfTradeFee       = 1 - protocolOfTradeFee - fundOfTradeFee;

console.log("LP fee effective:",       (tradeFeeOfVolume * lpOfTradeFee * 100).toFixed(4), "%");
console.log("Protocol fee effective:", (tradeFeeOfVolume * protocolOfTradeFee * 100).toFixed(4), "%");
console.log("Fund fee effective:",     (tradeFeeOfVolume * fundOfTradeFee * 100).toFixed(4), "%");
console.log(
  "Creator fee effective:",
  decoded.enableCreatorFee
    ? ((tier.creatorFeeRate / 1_000_000) * 100).toFixed(4) + " %"
    : "0 % (disabled on this pool)",
);
```

## CLMM 및 AMM v4와의 비교

[`reference/fee-comparison`](/ko/reference/fee-comparison)에서 나란히 비교 매트릭스를 참조하세요. 요약:

* **AMM v4**는 고정 0.25% 거래 수수료를 다른 LP/프로토콜 분배와 펀드 수수료 없이 사용합니다.
* **CLMM** 수수료는 틱-스페이싱 티어별로, 풀별이 아닌 포지션별로 누적되며, `DecreaseLiquidity` 또는 `CollectFees`를 통해 청구됩니다.

## 다음 단계

* [`products/cpmm/math`](/ko/products/cpmm/math) — 거래 수수료 차감이 곡선에 어떻게 연결되는지.
* [`products/cpmm/instructions`](/ko/products/cpmm/instructions) — `Collect*` 명령어 계정 목록.
* [`algorithms/token-2022-transfer-fees`](/ko/algorithms/token-2022-transfer-fees) — 풀 거래 수수료와 민트 전송 수수료를 올바르게 결합하는 방법.

소스:

* [`raydium-io/raydium-cp-swap` — `states/config.rs`, `states/pool.rs`, `states/curve.rs`](https://github.com/raydium-io/raydium-cp-swap)
* [Raydium API — `GET /main/cpmm-config`](https://api-v3.raydium.io/main/cpmm-config)
