Skip to main content
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.
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: 8creator_fee_share_rate.
  • No new error codes. The new paths reuse InvalidOwner (6001), InvalidInput (6003) and MathOverflow (6011). 60006015 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:
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.
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.

Account-list changes

CollectCreatorFee — one insertion: CollectCreatorFeePermissionless — two insertions:
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.
Full account tables in products/cpmm/instructions.

CreateCreatorFeeShare and CloseCreatorFeeShare

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

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. 60006015 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-comparisoncreator_fee_share_rate called out as a fourth CPMM rate with a different base.