Skip to main content
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.
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.

Creation fee

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%.
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:
  • 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 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:
  1. graduationFeeBps of the whole raisereserve 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 splits every collection:
  • 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 lostcreatorOwed / 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

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.