ETH$3,420
Launchpad/fee-policies

Fee policies

Pick what happens to your LP fees at launch: burn, vest, stake, buy-and-burn, or a redeemable ETH floor. Bound immutably to the token.

Your pool earns fees in two assets — WETH and your own token — and at launch you decide, once and permanently, what happens to each. That is the fee-policy system: a small registry of modules that the fee receiver routes into, chosen with two fields in LaunchParams.

The asymmetry people miss
The token policy governs the entire token side — the protocol takes none of it. The creator policy governs only your 70% of the WETH side; the protocol’s 30% is paid in kind regardless. A creator-side policy decides where your share goes, never how big it is.

#Choosing at launch

Both fields take abi.encode(uint16 policyId, bytes data). Empty bytes means “no module” — the token side splits in kind, the creator side is paid straight to you.

soliditythe two fields in LaunchParams
// token side: burn everything the pool earns in your token
tokenFeeConfig   = abi.encode(uint16(1), bytes(""));

// token side: vest it out at 10% of the vault per day, to msg.sender
tokenFeeConfig   = abi.encode(uint16(2), abi.encode(uint16(1000), address(0)));

// creator side: accrue WETH and buy your own token back with it
creatorFeeConfig = abi.encode(uint16(2), bytes(""));

// either side: pay stakers. Pick it on both and one pool pays both assets.
creatorFeeConfig = abi.encode(uint16(3), bytes(""));

The launcher resolves the id to a module, calls its onRegister hook, records the result, and marks the resulting venue as exempt from the token’s wallet cap so fee routing can never be blocked by the sniper guard. From that moment the token is bound to that module contract — not to the policy id — so a later protocol upgrade cannot change how your token behaves.

#Token-side policies

idPolicyWhat it does
Default (empty)Split creator/protocol in kind, like the WETH side.
1BurnEvery token the pool earns is destroyed the moment it is collected.
2VestingTokens accrue in a vault that pays out a fixed share of its balance, once a day.
3StakingTokens become rewards for holders who stake the token.

#Burn — policy 1

The simplest module in the system. Fees land on it and it calls burn() in the same transaction, permanently reducing totalSupply. It tracks totalBurned[token] so the lifetime figure is readable on-chain, and it has no admin, no storage of value, and nothing to claim. Nobody receives these tokens, including you.

#Vesting — policy 2

Fees accrue in a vault. claim(token) is permissionless — anyone can call it, and it always pays the configured recipient — but it succeeds at most once every 24 hours, releasing dailyReleaseBps of the current balance.

Config data
abi.encode(uint16 dailyReleaseBps, address recipient)
Recipient
Zero defaults to the creator. Rotatable later by the token owner.
Rate
Fixed at launch. Nobody can change it afterwards.
Interval
24 hours (CLAIM_INTERVAL), enforced on-chain
It decays, it does not amortise
The release is a percentage of what is in the vault right now, not of an original total. At 10% a day the vault halves roughly every 6.6 days and never quite empties — while new fees keep flowing in and topping it back up. It is a leaky bucket, not a linear unlock, which is precisely why there is no cliff to dump at.

#Staking — policy 3

The token side becomes staking rewards. Pick it on this side only and stakers earn more of your token; pick it on both sides and the same pool pays them in your token and in ETH. See Staking pools.

#Creator-side policies

idPolicyWhat it does
Default (empty)Your WETH share is paid to your recipient address on every collect.
2Buy back & burnYour WETH accrues, then buys your token on its own pool and burns what it bought.
3StakingYour WETH share streams to holders who stake your token.
4Backing vault (FLOOR)Your WETH collects in a per-token vault that anyone can burn tokens against for ETH.

#Buy back & burn — policy 2

WETH accumulates per token in the module. A buyback spends it on the token’s own launch pool — on whichever venue that token launched on, resolved from the launcher registry at buyback time — and burns everything it buys.

  • The token owner can trigger one at any time, for any size, with their own minTokensOut.
  • Anyone can trigger one after 90 days of inactivity — measured from the last buyback, or from registration if there has never been one. A public call must spend the full pending balance, and any successful buyback resets the clock.
  • There is no admin and no operator. Pending WETH has exactly one exit: a buyback that burns.

Buybacks are deliberately not triggered by fee collection. If they were, anyone could crank collect() to force a buy at a moment of their choosing and sandwich it. Because the trigger is owner-discretionary, the timing and size are unpredictable.

Why the 90-day public fallback exists
If a project is abandoned, its accrued WETH would otherwise be dead money forever. After three months anyone can recycle the pot into buy pressure. The trade-off is real and worth stating: a public caller picks their own minTokensOut and could sandwich their own call. We took that over the alternative of ETH stuck permanently, and the full-balance rule stops dust calls from resetting the clock while leaving the pot hostage.

#Staking — policy 3

Your WETH share is paid into the token’s staking pool as a reward stream. This is the same module and the same pool as the token-side staking policy — a launch that picks staking on either side, or both, gets exactly one pool.

#Backing vault (FLOOR) — policy 4

Instead of being paid out, your WETH share collects in a per-token vault. Anyone may burn tokens against that vault to redeem their pro-rata slice of the ETH inside it. The token’s own trading volume therefore buys it a hard, permissionless floor — one that is redeemable in ETH rather than merely asserted.

textthe whole mechanic
backing     = the vault's ETH balance + its WETH balance
circulating = totalSupply - tokens still sitting inside the locked launch position
floorPrice  = backing / circulating                 // ETH per whole token

redeem(a)   = backing * a / circulating * 0.99      // priced pre-burn; 1% stays behind

#Why the denominator is circulating supply

This is the part that makes the number mean something. At a hood.dev launch ~100% of the supply is minted straight into the launch position, which is locked in the FeeLocker forever. That supply is not held by anyone, so it can never be redeemed — and dividing the backing across it would quote a floor far below what the tokens that actually exist are entitled to.

So the vault subtracts it. Take a 1 000 000 000 supply token with 950 000 000 still in the launch position and 10 ETH in the vault: dividing by total supply gives 1e-8 ETH per token, while dividing by the 50 000 000 in circulation gives 2e-7 — 20× higher, and it is the number that is true. The 50M tokens people hold are collectively entitled to all 10 ETH.

How the position's inventory is measured, and why it is not balanceOf(pool)
The vault reads the locked launch position’s own liquidity, by position id, and values it against the pool’s live price exactly as Uniswap would value burning it. It deliberately does not use the pool’s token balance — that counts every token in the pool contract, including tokens somebody parked there themselves. An attacker holding half the float could mint their own LP position with it, watch a balance-derived “circulating” halve, redeem at the doubled floor, then withdraw their LP and walk off with the tokens too. Third-party LP, direct transfers to the pool, and every other pool-balance game move this number by exactly zero.

#The floor moves in both directions

Because the denominator is the float, the floor is not monotonic, and it would be dishonest to present it as a number that only goes up.

EventCirculating supplyFloor per token
BuyUp — supply leaves the launch positionFalls
SellDown — supply returns to the positionRises
Fee accrual or donationUnchangedRises
Burn (anywhere)DownRises
RedemptionDown by the amount burnedRises, strictly

A buy lowering the per-token floor is not a loss and not a bug: the vault’s ETH is unchanged, it is simply spread across more claimants — and the buyer paid market price for the same claim you hold. What the design does guarantee is that no third party can dilute your claim by any means except buying tokens.

The 1% skim is what makes redemptions ratchet
A redemption pays 99% of the pro-rata slice and leaves the other 1% in the vault for everyone who did not redeem. REDEEM_SKIM_BPS is a constant in the deployed bytecode, not a setting — there is no admin on the vault to change it. It is also why every redemption strictly raises the floor rather than merely holding it flat.

#Redeeming

Approve the vault for the amount you want to burn, then call redeem. The vault burns your tokens with burnFrom — it never custodies them — and pays you in native ETH, unwrapping WETH only when its loose balance is short.

solidityTokenBackingVault
function redeem(uint256 amount, uint256 minEthOut, address to)
    external returns (uint256 ethOut);

// reads
function backing() external view returns (uint256);            // ETH + WETH held
function circulatingSupply() external view returns (uint256);  // totalSupply - position inventory
function launchPositionInventory() external view returns (uint256);
function floorPrice() external view returns (uint256);         // wad, ETH per whole token
function previewRedeem(uint256 amount) external view returns (uint256 ethOut);  // exact, net of the skim

uint256 public constant REDEEM_SKIM_BPS = 100;                 // 1%

// on the module
function vaultOf(address token) external view returns (address);
  • previewRedeem is exact — it is the same computation redeem performs, against the same pre-burn circulating supply, so what it quotes is what you get.
  • minEthOut is ordinary slippage hygiene. The payout only moves against you if the backing shrinks or someone buys in the same block.
  • Pricing uses the pre-burn circulating supply, which is what makes the slice genuinely pro-rata: your own tokens are still counted when your share is computed.
What has no key here
The vault has no owner, no admin and no rescue path. ETH leaves it in exactly one way: somebody burns tokens. Its receive() is deliberately open, so anyone — a creator, a community, a bot — can donate ETH straight into the backing and lift the floor for every holder.

One soundness precondition: the token must be non-mintable, since a mint would dilute the floor without adding backing. Every launchpad token is a fixed-supply HoodToken, which qualifies by construction.

#How the registry works

Two FeePolicyManager instances back the whole thing — one per fee asset. The token-side instance has feeAsset = address(0), meaning “the launched token”; the creator-side instance has feeAsset = WETH.

Registration
onTokenLaunched — launcher-only, once per token, reverts with PolicyAlreadySet on a second attempt.
Fee routing
handleFee(token, amount) permissionless. It pulls the asset from the caller into the policy’s venue before notifying the module, so every accounting entry is backed by tokens that actually arrived. A call from anyone other than the fee receiver is simply a donation to that policy.
Upgrading a policy
setModule(id, module) — owner-only, and it affects future launches only. Tokens keep the module contract they registered with, forever.
Replacing the system
A new manager on the launcher plus a new fee receiver on the locker. Launched tokens are untouched.

#Deployed modules

BurnFeeModule — token policy 1
Burns the token side of LP fees on collect.
VestingFeeModule — token policy 2
Accrues the token side and releases a fixed % of the balance per day.
StakingFeeModule — token & creator policy 3
Clones one staking pool per launch; serves both fee sides.
BuyBurnFeeModuleV2 — creator policy 2
Venue-aware buy-and-burn. Bound to creator policy id 2 since the launcher v3 cutover.
BackingFeeModule — creator policy 4
The FLOOR vault factory. Clones one ETH backing vault per launch that picks it.
TokenBackingVault (implementation)
Master copy. Each token’s vault is an EIP-1167 clone of it; resolve one with vaultOf(token).
TokenStakingPool (implementation)
Master copy. Each launch that picks staking gets its own EIP-1167 clone.

Older tokens may be bound to earlier generations of these modules — most notably the Uniswap-only buy-burn module used before the multi-venue launcher shipped. That is the system working as designed. The authoritative answer for any token is its policy record in the getPolicy(token) on the relevant manager — or its indexed policy record, see Data & indexing.

chain 4663·on-chain values read 2026-07-29·Blockscout