> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lunya.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Fees

> Every fee a launch charges, who receives each side, and where to read it on-chain

Five things charge on the launchpad: creating a launch, trading the curve, the anti-snipe surcharge, graduation, and the fees the graduated position earns for the rest of its life. This page is what each one takes and who ends up with it.

<Note>
  **Read the rates off the launch, not the factory.** Every rate is snapshotted into the launch when it is created and cannot change for that launch afterwards — `config()` on a type-1 launch is what it actually charges. The factory's defaults are what the *next* launch will be created with. All rates are in basis points over `10000`, truncating.
</Note>

## Creation fee

|              |                                                                                                                                       |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| Rate         | `factory.quoteConfig(quote).creationFee` — a flat amount in that quote's units, per quote token                                       |
| Paid by      | the creator, at creation, together with any opening buy                                                                               |
| Received by  | the protocol, accrued in the factory as `feesAccrued(quote)`                                                                          |
| Collected by | `sweepFees(quote)` — **only** `factory.feeRecipient()` may call it; it pays the whole ledger and emits `FeesSwept(quote, to, amount)` |

On the native entry the fee is `creationFee × nativeDivisor` in native units, and whatever `msg.value` is left over becomes the opening buy. Any overshoot goes back to the creator in the same transaction.

## Curve trading fee

**`curveFeeBps` of the trade**, on buys and sells alike — of `amountIn` on a buy, of the gross proceeds on a sell.

**`curveFeeProtocolBps` is a share of that fee, not of the trade.** With a 1% curve fee and a 30% protocol share, the protocol takes 0.3% of the trade and the creator 0.7% — not 30%.

```
base       = fee − snipeFee
toProtocol = base · curveFeeProtocolBps / 10000 + snipeFee
toCreator  = fee − toProtocol
```

Rounding dust falls to the creator, because the protocol's side is the side that multiplies.

**Neither side is paid during a trade.** Both accrue in the launch — `protocolFees()` and `creatorFees()`, in quote units — and leave through:

```solidity theme={null}
function collectFees() external returns (uint256 toCreator, uint256 toProtocol);
```

* **Either recipient may call it, and the call pays both sides**: the launch's `creatorFeeRecipient`, fixed at creation, and the factory's `feeRecipient()`, read live at the moment of the call. Anyone else gets `NotAFeeRecipient()`.
* **A side whose transfer fails keeps its balance** and does not take the other side down: each is attempted in its own frame. Nothing reverts, and nothing is lost.
* **It works in any phase.** A creator collects their curve fees from a launch that never graduates.
* Each side that actually pays emits `FeesSwept(to, amount)`. The event does not say which side it was — the `to` address is what distinguishes them.

## Anti-snipe surcharge

**All of it goes to the protocol**, and none of it to the creator — so a creator cannot profit from their own launch being sniped. It applies to buys only, is keyed on the **recipient** rather than the sender, and is [described in full](/developers/launchpad/trading#the-anti-snipe-window) on the trading page.

It is **not a separate fee to an integrator**: `Trade.fee` and the quoters' `fee` are the single total, surcharge included. The split happens only when the launch books it.

The contract's own bounds, as constants you can rely on: `MAX_SNIPE_WINDOW` is 600 seconds, `MAX_SNIPE_DECAY` is 24, the surcharge rate is under `10000`, and **curve fee plus surcharge is clamped to 9,999 bps** — past that the surcharge is what gets cut, never the curve fee.

## Graduation

Charged once, on the [buy that fills the curve](/developers/launchpad/graduation#the-trigger):

1. **`graduationFeeBps` of the whole raise** — `reserve` as it stands, which is already net of trading fees. The contract caps this at `MAX_GRADUATION_FEE_BPS`, **1,000 bps (10%)**.
2. **The reward comes out of that fee**, not on top of it: `min(config().graduationReward, graduationFee)`, paid in the quote token to the `msg.sender` of the filling buy.
3. **The rest of the graduation fee is the protocol's**, unsplit — the creator's share of the raise is their curve fees, not this.
4. **The quote the pool did not take is also the protocol's.** The position is minted liquidity-first, so one side keeps a remainder; the quote side is booked to the protocol, and the token side stays in the launch as inert dust.
5. **The launch then offers its accrued protocol fees to the factory**, so one sweep per quote collects every launch's. It is an optimisation, not a step: if the quote token refuses the transfer, graduation still completes, the fees stay in the launch, and `collectFees()` pays them straight to `factory.feeRecipient()`.

`Graduated.quoteSeeded` is what actually went into the position — not the raise, and not the raise minus the fee.

## The graduated position

The locked LP position earns pool fees for as long as the pool trades, and the [locker](/developers/launchpad/graduation#after-graduation-the-locker) splits every collection:

```
protocolAmount = received · protocolBps / 10000     // per token leg
creatorAmount  = received − protocolAmount
```

* **`protocolBps` is set when the position is locked** — from the launch's `poolFeeProtocolBps` — and there is no setter: read it from `locker.locks(tokenId)`. Dust falls to the creator here too.
* **The addresses move, the percentage does not.** The creator's side points at an address its holder can change; the protocol's side is `factory.feeRecipient()` read live at every payout, so one governance call redirects every position at once.
* **A payout that cannot be made is booked, not lost** — `creatorOwed` / `protocolOwed`, withdrawn later with `withdrawOwed(tokenId, token)`; a leg that cannot be collected leaves the fees in the pool and emits `FeesUncollected`.
* **Farming rewards split by the same `protocolBps`.** While a position is enrolled, the exchange diverts its own configured share of that position's pool fees to the farming programme's recipient — a DEX-side parameter, outside the launchpad's control.

## Reading it all at runtime

| What                                  | Where                                                                                                                  |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Rates this launch charges             | `launch.config()` → `curveFeeBps`, `curveFeeProtocolBps`, `graduationFeeBps`, `poolFeeProtocolBps`, `graduationReward` |
| Rates the next launch will charge     | `factory.defaultCurveFeeBps()` and siblings; `factory.quoteConfig(quote)`                                              |
| Anti-snipe, for a given buyer         | `launch.currentSnipeTaxBps(recipient)`, `launch.isExempt(recipient)`, `launch.quoteBuyFor(amountIn, recipient)`        |
| Uncollected, on a launch              | `launch.protocolFees()`, `launch.creatorFees()`                                                                        |
| Uncollected, in the factory           | `factory.feesAccrued(quote)`                                                                                           |
| The position's split and destinations | `locker.locks(tokenId)`, `locker.protocolFeeRecipient()`, `locker.creatorOwed(...)`, `locker.protocolOwed(...)`        |

Terms are pinned at creation, so a launch created against `expectedTermsHash` charges what `factory.termsHash(launchType, quote)` covered at that moment — see [terms can move the address](/developers/launchpad/architecture#terms-can-move-the-address).
