Skip to main content
Fee logic is delegated the same way authorization is: the core hard-codes where fees may be charged, never how much. Charging a fee never moves tokens — it writes bookkeeping into an on-chain ledger; the actual transfer happens later, on an explicit claim.

The five charging avenues

There is no other place the core can debit a vault: report_on_funds matters most: it’s where the oracle writes reported equity, so it’s where NAV-based performance fees crystallize.

The four buckets

Every fee splits into LP, manager, protocol, performance — each with its own verified recipient. The performance bucket is high-water-mark-gated: a calculator charges only on equity above the prior mark and returns the new mark, so the same gain is never taxed twice.

Charge vs. claim

Charge

Called by the core on a fund op. Accrues into unclaimed and total_collected. No tokens move.

Claim

claim_fees(fee_type, amount) requires recipient == recipients.get_recipient(fee_type) and amount ≤ unclaimed, then moves the amount from unclaimed to total_claimed. The core executes the SPL transfer signing as vault_share_signer.

The dispatcher ledger

The total_collected / total_claimed ledger makes every fee ever charged independently verifiable.

Balance identity

A vault’s total is a signed i64:
The signed type lets a vault carry venue-side debt (capital deployed at the CEX) without underflow. Subtracting accrued-but-unclaimed fees keeps reported NAV net of fees at all times.

Build a custom calculator

Implement calculate_fees with any fee model.