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.
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
| Amount | Treatment |
|---|---|
| LP fee | Owed to positions active on the traded intervals |
| Creator or partner fee | Beneficiary liability from the post-protocol remainder |
| Token-2022 transfer fee | Mint-defined transfer cost, only if supported |
| Frontend or aggregator fee | Route-level cost, not implicitly part of the pool fee |
| Creation or graduation fee | Separate 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.