Spot Market Fees
How swap fees are collected and shared on Uniswap V4 pools
When a CCA auction completes and the Uniswap V4 pool goes live, every swap on that pool can charge a protocol fee. This fee is collected automatically by a V4 hook attached to the pool and sent to a configurable recipient.
Fee parameters
Two parameters control the fee, both set at qOrg creation and immutable after deployment:
| Parameter | What it controls | Constraints |
|---|---|---|
feeBps | Fee rate in basis points, applied to swap output | 0–100 bps (0–1%) |
feeRecipient | Address that receives all collected fees | Cannot be address(0) |
Setting feeBps to 0 disables fee collection entirely — the hook becomes a no-op on swaps.
How fees are collected
The pool's hook implements Uniswap V4's afterSwap callback. On every swap:
- The hook calculates the fee as a percentage of the unspecified token amount (output for exact-input swaps, input for exact-output swaps)
- The fee is minted as an ERC6909 claim inside the Uniswap V4 PoolManager
- Claims accumulate until someone triggers a withdrawal
For exact-input swaps the fee is taken from the output side; for exact-output swaps the fee is taken from the input side.
Claiming fees
Anyone can call claimFees(currency) on the LBP contract at any time. This:
- Burns the accumulated ERC6909 claims from the PoolManager
- Transfers the underlying tokens to
feeRecipient - Emits a
FeesCollectedevent
There is no access control on claiming — it's a permissionless operation that always sends to the same recipient.
Fee sharing between Umia and projects
Since feeRecipient is a single address, fee sharing is handled at the recipient level rather than in the hook itself. The recommended approach:
- Deploy a revenue-splitting contract (e.g. 0xSplits) with the desired split between Umia and the project
- Set that splitter contract as the
feeRecipientwhen creating the qOrg - Fees flow to the splitter, which distributes according to its configured ratios
This keeps the hook simple and gas-efficient while allowing arbitrary split configurations — 50/50, 80/20, or any other ratio — without requiring changes to the core contracts.
Fees vs. qOrg share
These are two separate revenue streams that should not be confused:
| Revenue type | Source | When it applies | Parameter |
|---|---|---|---|
| qOrg share | Currency raised in the CCA | Once, at pool migration | qorgBps |
| Swap fees | Ongoing trading volume | Every swap after launch | feeBps |
The qOrg share is a one-time cut of the auction proceeds, transferred directly to the qOrg treasury when the pool is created. Swap fees are ongoing and flow to feeRecipient (which may or may not be the qOrg itself).
Setting up fees
When creating a qOrg through UmiaHub, include the fee parameters in CreateQOrgParams:
CreateQOrgParams({
// ... other params
feeRecipient: 0x..., // splitter contract or direct recipient
feeBps: 50, // 0.5% of swap output
// ...
})These values are forwarded through the LBP factory to the hook contract and cannot be changed after deployment. Choose carefully — the fee rate and recipient are permanent for the lifetime of the pool.