Skip to content

Fee accounting

Keep protocol revenue, LP fees, beneficiary claims, and principal separate.

The trading fee is charged in the received input asset. A dynamic-fee hook may select a rate within a core-enforced cap. Distribution answers a separate question: who receives that fee?

For protocol, treasury, creator, and partner entitlements, read Fees and revenue. It explains mandatory 10% retention, per-mint fractional carry, treasury claims, and the remainder split in the Pool 6 source increment.

A worked example

This is an illustration, not a configured default. With 1,000 input units and a 1% pool fee, 990 units price the swap and 10 units become fee liabilities. The protocol retains 1 unit. With a 70% LP share of the remaining 9 units, active positions receive 6.3 units and external beneficiaries receive 2.7 units. The example uses divisible token units; actual settlement uses integer atoms and carry.

1,000 input units
990Price the swap
10Fee liabilities
1 Protocol6.3 Active LPs2.7 Beneficiaries
Illustrative 1% trading fee, 10% protocol retention, and 70% LP share of the remainder. All amounts use the input asset.

LP fee growth

The design accounts for fees per position, using global growth and growth outside initialized ticks to derive growth inside a range. The earned increment is based on the position's liquidity and the difference since its checkpoint.

Positions earn only over swap segments where they are active. A checkpoint must advance when earned amounts are credited so a later collection cannot claim the same growth again. LP fees remain liabilities until collected or explicitly reinvested; they do not silently increase L.

External splits and dust

Current core behavior: programs/grapl-amm/src/instructions/fees/accounting.rs first reserves the mandatory protocol share with per-pool, per-mint carry, then converts the LP share and four beneficiary shares from bps to ppm, allocates the remainder of each swap-fee event, and assigns split residue to the first nonzero share (LP first). It credits beneficiary debt per token. A collection requires the configured beneficiary signer and clears that debt as part of the transfer transaction.

Each beneficiary claims its own recorded debt. Collecting one recipient’s allocation does not distribute every other recipient’s balance.

Integer division leaves remainders. Specify whether dust stays reserved, accumulates across claims, or belongs to a designated allocation. Never discard it from liabilities or allocate more than the fee collected. Changing weights must not transfer historical claims to new recipients.

Separate costs

AmountTreatment
LP feeOwed to positions active on the traded intervals
Creator or partner feeBeneficiary liability from the post-protocol remainder
Token-2022 transfer feeMint-defined transfer cost, only if supported
Frontend or aggregator feeRoute-level cost, not implicitly part of the pool fee
Creation or graduation feeSeparate policy; no default specified here

A sell that inputs token A produces an input-denominated fee in A. Paying every beneficiary in SOL or USDC would require different fee semantics or a conversion. Neither is implicit.

Read numeric rules and solvency invariants.

Fees during curve mode and zaps

Curve-mode fees use the same input asset, mandatory protocol retention, and configured remainder shares. The LP share is retained for the future graduation position; protocol and beneficiary debts remain excluded from the bootstrap budget. See curve accounting.

A zap pays the ordinary fee on its swap leg. It does not turn a one-sided deposit into a free conversion, and it does not automatically compound existing position fees. ExactOut includes both the input fee and any configured output fee when solving for the required input.