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

# 2026-09-13 — CPMM: the protocol takes a share of the creator fee

> CPMM can now retain a configurable share of the creator fee, applied when the fee is collected rather than when it is charged. AmmConfig gains creator_fee_share_rate (carved from padding, same size), a new CreatorFeeShare PDA overrides it per creator, and CreateCreatorFeeShare / CloseCreatorFeeShare manage it. Both CollectCreatorFee paths change their account lists — breaking for existing clients. UpdateAmmConfig gains param 8. No new error codes, no PoolState change, swap math untouched.

<Info>
  This entry covers an upcoming CPMM program update. It was verified against the local release branch (`0dde43d`, 11 September 2026) before deployment. Confirm the deployed program before relying on the new instructions or the changed account lists.
</Info>

CPMM's creator fee has always gone entirely to the pool creator. This release lets the protocol keep a share of it — negotiable per fee tier, or per creator on a fee tier — without touching how the fee is charged.

The design choice that keeps the blast radius small: **the split happens at collection time, not at swap time.** A swap still charges `creator_fee_rate` and still accrues the whole amount to `creator_fees_token_{0,1}`. When `CollectCreatorFee` or `CollectCreatorFeePermissionless` runs, the accrued balance is divided, the protocol's part is re-labelled as a protocol fee on the same pool, and only the creator's part leaves the vault. Quotes, the curve, `k`, and every LP-facing path are unaffected.

## TL;DR for integrators

* **Both creator-fee collection instructions changed their account lists. This is breaking.** `CollectCreatorFee` gains `creator_fee_share` at position 5. `CollectCreatorFeePermissionless` gains `amm_config` at 5 and `creator_fee_share` at 6. Both insertions sit before the vaults, so everything after shifts. Rebuild these transactions; do not patch them.
* **`creator_fee_share` must be passed even when it does not exist.** It is declared with a seed constraint but read as an unchecked account, so the address must be the canonical PDA at `["creator_fee_share", creator, amm_config]` while the account itself is optional. When it is empty, the program falls back to `AmmConfig.creator_fee_share_rate`.
* **`AmmConfig` gains `creator_fee_share_rate`, carved out of the padding.** The account is still **236 bytes** and every existing config keeps deserializing — but the first `u64` of the old `padding: [u64; 15]` is now a live field. Decoders that model the tail as a 15-element array read the share rate as `padding[0]`.
* **`PoolState` is unchanged.** 637 bytes, same offsets, same fields. The protocol's share is booked into the existing `protocol_fees_token_{0,1}` counters — there is no new counter and no new collection instruction for it.
* **`protocol_fees_token*` now grows outside of swaps.** Any monitor that reconciles protocol accrual against trade volume will see jumps at each creator-fee collection.
* **A creator-payout estimator that reads `creator_fees_token*` now overstates.** Multiply by `(1 − share_rate / 1_000_000)`, resolved for that `(creator, amm_config)` pair.
* **Two admin instructions are added:** `CreateCreatorFeeShare` and `CloseCreatorFeeShare`. **One new `UpdateAmmConfig` param:** `8` → `creator_fee_share_rate`.
* **No new error codes.** The new paths reuse `InvalidOwner` (`6001`), `InvalidInput` (`6003`) and `MathOverflow` (`6011`). `6000`–`6015` are unchanged.
* **An IDL refresh is required** — two new instructions, one new account type, two changed account lists, one new config field.

## How the split works

Resolution, in priority order:

1. **`CreatorFeeShare` PDA** at `["creator_fee_share", creator, amm_config]` — when the account exists and is owned by CPMM, its `share_rate` wins.
2. **`AmmConfig.creator_fee_share_rate`** — the fee tier's default, used otherwise.

Both are `u64` over `FEE_RATE_DENOMINATOR_VALUE = 1_000_000` and both are checked against that ceiling. Then, per token side:

```rust theme={null}
// states/creator_fee_share.rs
shared_amount  = floor(creator_fee * share_rate / 1_000_000);
creator_amount = creator_fee - shared_amount;
```

```rust theme={null}
// states/pool.rs — PoolState::settle_creator_fee
self.protocol_fees_token_i = self.protocol_fees_token_i.checked_add(shared_amount_i)?;
self.creator_fees_token_i  = 0;
// creator_amount_i is returned and transferred out to the creator
```

Three properties the program tests pin down:

* **Rounding favours the creator.** The share floors, so the dust stays with the creator — the same direction as `Fees::protocol_fee` and `Fees::fund_fee`, which also carve a share out of an already-accrued fee. 20% of a 1-unit fee is 0, not 1.
* **Value is conserved.** `creator_amount + shared_amount == creator_fee` for every rate and every fee up to `u64::MAX`.
* **`share_rate = 0` is exactly the old behaviour.** Both the default config value and a missing PDA give the creator the whole fee, so nothing changes for any existing pool until an admin sets a rate.

Because `protocol_fees_token*` and `creator_fees_token*` are both already subtracted in `vault_amount_without_fee`, moving value between them does not change the curve's view of the vault. No LP sees a price change across a creator-fee collection, and the `k` check is untouched.

<Note>
  **The rate is read at collection, not at accrual.** Fees that accumulated while the rate was `0` settle at whatever rate is in force when someone finally calls `Collect*`. There is no per-epoch or per-swap snapshot.
</Note>

## Account-list changes

`CollectCreatorFee` — one insertion:

| #   | Before                                             | After                                                |
| --- | -------------------------------------------------- | ---------------------------------------------------- |
| 1–4 | `creator`, `authority`, `pool_state`, `amm_config` | unchanged                                            |
| 5   | `token_0_vault`                                    | **`creator_fee_share`** (new)                        |
| 6.. | —                                                  | `token_0_vault` and everything after, shifted by one |

`CollectCreatorFeePermissionless` — two insertions:

| #   | Before                                        | After                                                |
| --- | --------------------------------------------- | ---------------------------------------------------- |
| 1–4 | `payer`, `creator`, `authority`, `pool_state` | unchanged                                            |
| 5   | `token_0_vault`                               | **`amm_config`** (new)                               |
| 6   | `token_1_vault`                               | **`creator_fee_share`** (new)                        |
| 7.. | —                                             | `token_0_vault` and everything after, shifted by two |

<Warning>
  Neither change fails loudly in a helpful way. The inserted accounts are not at the end of the list, so an old client does not "miss an account" — it hands the program a vault where a config is expected and the transaction fails on deserialization. Regenerate from the new IDL, and check that any SDK release you pin carries the new accounts before pointing it at the upgraded program.
</Warning>

Full account tables in [`products/cpmm/instructions`](/products/cpmm/instructions#collectcreatorfee).

## `CreateCreatorFeeShare` and `CloseCreatorFeeShare`

```rust theme={null}
pub struct CreatorFeeShare {
    pub bump: u8,
    pub creator: Pubkey,
    pub amm_config: Pubkey,
    pub share_rate: u64,
    pub padding: [u64; 8],
}
// CreatorFeeShare::LEN == 145
```

`CreateCreatorFeeShare(share_rate: u64)` inits the PDA; `CloseCreatorFeeShare` closes it and returns the rent to the signer. Both accept the shared program admin **or** a dedicated creator-fee-share owner — a new hardcoded key pair following the same devnet/mainnet `cfg` pattern as the program's other delegated authorities. Addresses in [`reference/program-addresses`](/reference/program-addresses#cpmm-creator-fee-share-authority).

Points worth noting:

* **The pool creator is not a party to either instruction** and does not sign. The `creator` account is unchecked — the PDA can be created for a key that owns no pool yet.
* **One account covers a `(creator, amm_config)` pair**, so it governs every pool that creator owns on that fee tier. A creator with pools on two tiers needs two accounts to be covered on both.
* **There is no update path.** `init` fails on a second create for the same pair; to change a rate, close and re-create.

## `UpdateAmmConfig` param 8

```rust theme={null}
Some(8) => update_creator_fee_share_rate(amm_config, value),   // asserts value <= 1_000_000
```

Sets the fee tier's default share. It is unrelated to `protocol_fee_rate` (param `1`), which splits the **trade** fee — a point worth being careful about in admin tooling, since the two read alike and both land in `protocol_fees_token*`.

## Riding along

**`CollectExcessLamports` ordering fix.** The instruction now makes two passes over `remaining_accounts` — every token-program CPI first, then the direct debits of CPMM-owned PDAs — instead of dispatching in caller order. Interleaving the two aborted with the runtime's `UnbalancedInstruction` ("sum of account balances before and after instruction do not match") whenever a PDA was debited ahead of a CPI, because the caller's pending lamport changes are only flushed into the accounts a CPI actually carries. The instruction's interface is unchanged; callers still pass sources in any order, and now that is genuinely safe.

**Verifiable-build metadata.** The workspace `Cargo.toml` declares `[workspace.metadata.cli] solana = "3.1.10"`, so a verifiable build resolves the same Solana CLI the program was built against. No on-chain effect.

## What did not change

* **`PoolState`** — 637 bytes, same fields, same offsets. The protocol's share reuses the existing protocol bucket rather than adding counters of its own.
* **`AmmConfig::LEN`** — still 236 bytes.
* **Swap math, quoting, and the `k` check.** The creator fee is charged exactly as before.
* **`CollectProtocolFee` / `CollectFundFee`** — same accounts, same signers. `CollectProtocolFee` simply has more to collect.
* **Error codes.** `6000`–`6015` unchanged; nothing appended.
* **Every other instruction**, and the program ID.

## Pages updated

* `products/cpmm/fees` — new "Protocol share of the creator fee" section covering rate resolution, the split arithmetic, rounding, and the integrator consequences; `creator_fee_share_rate` added to the rates/units list and the default-parameters table; collection-flow table reworked.
* `products/cpmm/instructions` — breaking-change warning at the top; full account tables for both creator-fee paths; new `CreateCreatorFeeShare` and `CloseCreatorFeeShare` sections; `UpdateAmmConfig` param `8`; `CollectExcessLamports` ordering note; summary and state-change matrix rows.
* `products/cpmm/accounts` — new `CreatorFeeShare` account section; `AmmConfig` layout and padding-carve warning; `PoolState` fee-counter notes; account-lifecycle rows.
* `products/cpmm/overview` — creator-fee callout and the "Predictable fees" bullet.
* `products/cpmm/math` — a note that the split is deliberately absent from swap math.
* `products/cpmm/code-demos` — warning that pre-upgrade SDK builders emit the old account lists; accrued-fee snippet annotated.
* `reference/program-addresses` — new "CPMM creator-fee-share authority" section; `creator_fee_share` added to the PDA-seed block.
* `reference/fee-comparison` — `creator_fee_share_rate` called out as a fourth CPMM rate with a different base.
