ETH$3,420
Launchpad/liquidity

Liquidity & LP fees

The FeeLocker holds every launch position permanently while swap fees stay claimable by anyone, and split creator/protocol.

A launch mints its whole supply into one concentrated-liquidity position and hands that NFT to a FeeLocker. The locker has no function that transfers, approves, decreases, burns or sweeps a position it holds — not for the owner, not for anyone. The liquidity is there permanently. What stays live is the fee stream, and collecting it is open to anybody.

#The lock

Positions can only enter through onERC721Received, and the locker rejects everything that is not a launch:

  • the caller must be this venue’s position manager (immutable at deploy) — foreign NFT collections bounce with OnlyPositionManager;
  • the sender must be the launcher (immutable) — OnlyLauncher otherwise;
  • the range must reach an extreme usable tick on at least one side — RangeNotExtreme otherwise. A defensive backstop: the real invariant is that the launcher only ever mints one-sided-to-infinity curve positions.

The deposit carries abi.encode(creator, creatorBps), which becomes the position’s permanent configuration. creatorBps is fixed at that moment and cannot be changed by anyone, ever — not by the creator, not by the protocol.

What “locked forever” actually means here
Not a timelock with a long expiry, and not a lock a multisig could release. The FeeLocker exposes no code path that moves a position or reduces its liquidity. Anyone can verify that by reading the verified source on Blockscout — the surface is small enough to check in a few minutes.

#Collecting fees

collect(tokenId) and collectMany(tokenIds[]) are permissionless. Anyone can crank them — the creator, a holder, a keeper bot, a curious stranger — and the destination of the proceeds is fixed by the position’s config, not by who called. Cranking is a favour, not a privilege.

textone collect, end to end
  anyone ──▶ FeeLocker.collect(positionId)
                    │  pulls both fee amounts from the position manager
                    ▼
             V3FeeReceiver.onFeesCollected(...)
                    │
      ┌─────────────┴──────────────┐
      ▼                            ▼
  TOKEN side                   WETH side
      │                            │
  token fee policy set?        split by creatorBps (70/30)
      │                            │
   yes│ no                creator │       │ protocol
      ▼   ▼                       ▼       ▼
  full   70/30 split      creator policy  paid in kind
 amount  in kind          set? yes -> policy
 to the                        no  -> creator recipient
 policy

#The split

SideWith a fee policyWithout one
Token sideThe full amount is handed to the token-side policy — burn, vest, or stake.Split creator/protocol in kind by creatorBps.
WETH sideSplit by creatorBps first; the creator’s 70% goes to the creator-side policy (buy-burn, stake, or a backing vault). The protocol’s 30% is always paid in kind.Split by creatorBps; the creator’s 70% is paid straight to the position’s creator recipient.

creatorBps is currently 7000 — a 70/30 split, 70% to the creator — and it is protocol-wide, not a per-creator deal. The protocol can change it for future launches but never below the compiled-in floor of 1000 (10%), and never for a token already launched.

#Nothing can brick collection

Two independent fallbacks make collect() effectively un-revertable, which matters because it is the shared path for every launched token:

  • Push with a pull fallback. If paying a recipient fails — a blocklisted address, a paused token, a contract that reverts on receive — the amount is credited to claimable[recipient][token] and can be pulled later with claim(token). One bad recipient cannot block collection for anyone else.
  • Delegation is try/catch’d. The receiver approves the fee manager and calls it; if the policy reverts, the approval is cleared and that amount falls back to the plain in-kind split for this collection. A broken policy module cannot strand fees or halt the crank.

#Rotating where your fees land

FeeLocker.updateCreatorRecipient(tokenId, newCreator) changes where a position’s creator share is paid. It is gated by TokenOwnerRegistry.ownerOf(token) — the same key that controls metadata and the vesting recipient — so a single ownership transfer moves this power along with everything else. The share itself (creatorBps) is not touchable; only the destination is.

#Admin surface

ContractOwner powersCannot
FeeLockersetFeeReceiver only — swap what happens to fees. Renounce to ossify.Touch liquidity, move NFTs, change a creatorBps, or change a creator recipient.
V3FeeReceiverNone. The protocol recipient can only rotate itself.Everything else — the contract has no owner.

The setFeeReceiver seam is the one deliberate piece of mutability. It is what lets the protocol add a new fee behaviour (say, converting the token side to ETH) without ever relaunching the locker or moving a single position. A future policy is just a new contract implementing IV3FeeReceiver.

#Per-venue deployments

A locker binds its position manager immutably, so each venue has its own locker and its own receiver. Everything downstream is shared.

FeeLocker · Uniswap V3
Holds every Uniswap-venue launch position forever. collect() is permissionless.
FeeLocker · SushiSwap V3
Same contract, bound to the Sushi position manager.
V3FeeReceiver · Uniswap V3
Splits collected fees and hands each side to its policy.
V3FeeReceiver · SushiSwap V3
Same, for the Sushi locker.
chain 4663·on-chain values read 2026-07-29·Blockscout