Fees and revenue
Follow the mandatory protocol share, LP and beneficiary allocations, and authorized collection in the assets actually earned.
The current source increment reserves 10% of the input trading fee for the protocol, then distributes the remainder between LPs and configured beneficiaries. This is part of the fee already charged to the trader, not an additional 10% charge on the trade amount.
Validation status: the Pool 6 revenue implementation passed isolated local integration verification, including authenticated treasury initialization, claims in both pool assets, repeated collection without double payment, and rollback. These results do not establish a public deployment or a completed audit.
Follow the fee
Let F be the actual input trading fee, in token atoms. The protocol rate is fixed at 1,000 / 10,000 basis points. Fractional carry is kept separately for each pool and input mint:
numerator = F × 1,000 + previous carry
protocol retention P = floor(numerator / 10,000)
new carry = numerator mod 10,000
remainder R = F − P
R = LP allocation + sum of beneficiary allocationsThe carry prevents splitting a fee across small events from avoiding the protocol share. Ten one-atom fees retain one protocol atom in total, just as one ten-atom fee does. Collection does not clear that fractional carry.
The existing LP and beneficiary shares sum to 10,000 and apply to R. Integer split residue goes to the first nonzero configured share, checking LPs first. Total liabilities must conserve the fee: protocol retention plus every remainder allocation equals F.
A dynamic-fee hook changes F within the pool's cap. It does not change the fixed protocol percentage or the configured remainder split. Zero trading fee produces no additional protocol atoms.
A six-decimal USDC example
For a 1,000 USDC swap with a total 0.3% trading fee, F is 3 USDC. Protocol retention is 0.30 USDC, leaving 2.70 USDC. With an 80% LP, 15% creator, and 5% partner remainder split:
| Allocation | USDC | Atoms at six decimals |
|---|---|---|
| Total trading fee | 3.000000 | 3000000 |
| Protocol retention | 0.300000 | 300000 |
| LP allocation | 2.160000 | 2160000 |
| Creator allocation | 0.405000 | 405000 |
| Partner allocation | 0.135000 | 135000 |
The four allocations sum to 3 USDC. All configured recipients, including LPs, participate in the proportional reduction. The 0.3% trading fee and 80/15/5 split are illustrative; the source increment's protocol retention is fixed at 10%.
Configure the remainder when creating a pool
PoolConfiguration contains lp_share_bps and up to four beneficiaries with a recipient and share_bps. Active recipients must be unique and nonzero; empty slots have zero share. The total is 10,000 basis points of the amount remaining after protocol retention.
These weights and recipient addresses are immutable under the current instruction set. The SDK's defaultPoolConfiguration() uses lpShareBps: 10000 and four empty slots: LPs receive all of the remainder, while mandatory protocol retention still applies.
The protocol share is enforced in core fee accounting. Calling the core directly, omitting a hook, or choosing another SDK configuration does not opt a pool out. The protocol does not consume one of the four beneficiary slots.
Keep claims separate
| Balance or cost | Treatment |
|---|---|
protocol_owed_a/b | Protocol claim for the corresponding pool asset |
| LP allocation | Position fee growth on traded intervals, or retained LP fees during curve mode |
beneficiary_owed_a/b | Claims belonging to the pool's configured recipients |
| Optional hook output fee | Separate capped deduction in the output asset; outside this protocol-retention base |
| Network and priority fees | SOL costs for execution; outside pool trading revenue |
| Rent-exempt deposit | SOL backing account storage; outside trading revenue |
Donations accrue directly to active LP fee growth. They do not pass through the protocol trading-fee retention or beneficiary split. During curve mode, protocol and beneficiary claims remain reserved and are excluded from graduation funding.
Initialize the treasury recipient
ProtocolTreasury is a core PDA derived with b"protocol_treasury". initialize_protocol_treasury(recipient) creates it once, rejects a zero recipient, and requires the deployed program's upgrade authority authenticated through its ProgramData account. The initializer also funds this account's deposit.
The current instruction set has no recipient setter and no runtime setter for the fixed 10% rate. The initializer establishes the authorized claim recipient; it does not turn fee retention on or off. Swaps accrue liabilities in their own pool and do not need a shared writable treasury account.
No production recipient address is published here. Applications must derive and read the treasury for their verified deployment. Treasury initialization and collection are explicit on-chain operations with their own authorization.
Collect protocol or beneficiary revenue
collect_protocol_fees operates on one pool and requires the market actor's signature to match the configured treasury recipient. Destination token accounts must belong to that actor and match the pool mints. It clears that pool's protocol owed amounts and transfers both assets atomically. The fractional carry survives collection.
Beneficiary collection is separate. collect_beneficiary_fees checks the selected slot and requires the signed actor to equal its recipient. It clears and transfers only that recipient's debt. Collecting a beneficiary does not claim protocol revenue or distribute every other recipient's balance.
A failed transfer rolls back claim clearing and transfers together. After confirmation, reconcile the receipt and actual token credits before reporting collected revenue. An owed amount is not evidence that a wallet has already received funds.
The treasury increment emits ProtocolTreasuryInitialized and ProtocolFeesCollected events. These specific events do not establish a complete normalized observer API for every protocol operation.
Revenue stays in the collected assets
Trading with input A produces its trading fee in A; input B produces it in B. A recipient can therefore accrue both assets across pools. There is no automatic conversion into USDC, SOL, or a reporting currency.
Keep accrued token amounts, claimed token amounts, estimated valuations, and proceeds from a later conversion distinct. Conversion is another trade with its own fees, price impact, limits, and authorization. An estimated USDC value is not a USDC balance.
Referral and future products
A fixed partner beneficiary is not a dynamic referral recipient selected per swap. The current increment does not implement referral deductions from the protocol share. DCA, native limit orders, and managed market-making products remain separate research directions.
Meteora's revenue guide informs the distinction between the trading-fee base, protocol revenue, and collection in traded assets. Its product-specific rates and referral mechanisms are not grapl behavior.
Implementation sources: instructions/fees/{protocol,accounting,treasury,donate}.rs, state/treasury.rs, instructions/curve/validation.rs, and settlement/accounts.rs under programs/grapl-amm/src/. For user-facing costs, see Fees and account deposits.