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%.
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’sfeeRecipient(), read live at the moment of the call. Anyone else getsNotAFeeRecipient(). - 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 — thetoaddress 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:graduationFeeBpsof the whole raise —reserveas it stands, which is already net of trading fees. The contract caps this atMAX_GRADUATION_FEE_BPS, 1,000 bps (10%).- The reward comes out of that fee, not on top of it:
min(config().graduationReward, graduationFee), paid in the quote token to themsg.senderof the filling buy. - The rest of the graduation fee is the protocol’s, unsplit — the creator’s share of the raise is their curve fees, not this.
- 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.
- 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 tofactory.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:protocolBpsis set when the position is locked — from the launch’spoolFeeProtocolBps— and there is no setter: read it fromlocker.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 withwithdrawOwed(tokenId, token); a leg that cannot be collected leaves the fees in the pool and emitsFeesUncollected. - 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.