TESTNETRobinhood Chain testnet (id 46630). USDG here is a faucet token anyone can mint — prices, liquidity and fees on this page are not real money.

Roles and Limits

The buzz

"Who can do what?" is the question that matters, so here is the whole answer with no adjectives. The hook has four keys and one pressed button: the key that opened the pool (used once), the one that earns the creator's share, the one that owns three settings, the keeper that only presses compound(), and — beside them — the key that owns the seed's time lock. Each can do a short list of things and NOTHING else. The list of things nobody can do is longer, and it is the part we are proud of. Print it. Frame it. Check it against the bytecode.

The boring part

flowchart TB
  subgraph PC [poolCreator · immutable]
    A1[create the one pool] --- A2[open trading<br/>once, one-way]
  end
  subgraph CR [creator · two-step]
    A3[receive its share<br/>of the protocol fee]
  end
  subgraph CT [controller · two-step]
    A5[setCompoundBounty<br/>≤ 0.5 %] --- A6[setFeePaused<br/>the fee, never trading] --- A10[setKeeper<br/>who presses first]
  end
  subgraph KP [keeper · named by the controller]
    A11[compound only<br/>nothing else]
  end
  subgraph LO [seed locker owner · two-step]
    A7[collectFees<br/>liquidity untouched] --- A8[extendLock<br/>later only] --- A9[withdraw<br/>only after unlockAt]
  end

The keys

Key Can do Bound by Can it be changed?
poolCreator create the one pool; open trading (once) pair, fee flag and tick spacing enforced; opening is one-way No. Immutable. Used at launch, then it has nothing left to do.
creator receive its share of the protocol fee nothing else — no other function checks this address Yes: two-step transfer (propose, then the new address accepts)
controller setCompoundBounty
setFeePaused
setKeeper
and may press compound() itself
bounty ≤ 0.5% (and ≤ 3 USDG a call); nothing else — the protocol fee, its split and the curve are immutable Yes: two-step transfer
keeper compound() — first, ahead of everyone a hot key with no owner powers: the hook refuses it every other function. After six hours without a compound the button is public again whatever is set Yes: the controller names a new one, or setKeeper(0) reopens compound() to everyone at once
seed locker owner collectFees (the seed's LP fees, liquidity untouched)
extendLock (later only)
withdraw — only after unlockAt
one position, once; the lock never shortens; nothing else in the contract Yes: two-step transfer

At launch the controller, the creator and the seed locker's owner are the same hardware wallet; the keeper is a separate hot key. Every hat is listed, every transfer is two-step and an on-chain event, and the transfer paths were exercised on testnet before mainnet (The Launch).

Things nobody can do 🚫

  • Withdraw the locked liquidity. There is no function. Not a disabled one — none.
  • Withdraw the seed before its unlockAt. Not even its owner; the locker has no rescue path, because a rescue path is a rug path.
  • Mint FLY. The token has no mint function; supply was created once.
  • Halt trading. Once openTrading() has run, nothing in the hook can refuse a swap again. setFeePaused stops the fee, not trading. You can always leave. That is the point.
  • Change the protocol fee, its split or the fee curve. They are set once, in the constructor, and there is no setter: 0.90 %, half to the creator and half to the floor, k = 15 — for the life of the pool. Not the controller, not the creator, nobody.
  • Upgrade anything. No proxies. What you read is what runs, forever.
  • Create a second pool through this hook, or change the pair.
  • Take the pot anywhere but into the pool. compound() has exactly one destination.
  • Make the keeper more than a button-presser. The keeper's whole power is who presses first; it cannot move funds, change a fee, or touch liquidity, and a dead or hostile one delays the floor by hours at most.

What the controller's knobs are for

  • setFeePaused is a circuit breaker for the fee path: if the stablecoin issuer ever restricted an address the fee is paid to, trading would continue without the fee. It is a way to make trading cheaper in an emergency, not a way to take anything.
  • setCompoundBounty prices the keeper's click, 0–0.5 % of the tranche (3 USDG at most).
  • setKeeper names the hot key that presses compound() on a schedule, or clears it. That is the whole list: three knobs.

Things anyone can do

  • Add or remove their own liquidity.
  • Call compound() and be paid for it — once the keeper has been idle for six hours, or at any time if no keeper is set.
  • Call sweepBands() and burnAccruedFly().
  • Read everything: every number on the dashboard is a public view. Don't trust. Verify. Then vibe.

Events to watch, if you watch such things

TradingOpened, FeePausedUpdated, CompoundBountyUpdated, KeeperUpdated, CreatorTransferStarted / CreatorTransferred, ControllerTransferStarted / ControllerTransferred, LiquidityLocked, AccruedFlyBurned, WeatherChanged, ProtocolFeeCollected. On the seed locker: Locked, LockExtended, FeesCollected, Unlocked, OwnershipTransferStarted / OwnershipTransferred. Set alerts on these and you will know about any change to the machine before anyone can spin it. 🪰

The launchpad's keys

The launchpad (The Launchpad) has its own, smaller set. The FLY owner (the same hardware wallet) holds the owner roles; one hot key presses the furnace's burn.

flowchart TB
  subgraph FO [FLY owner · the hardware wallet]
    B1[LaunchFactory<br/>launch fee, protocol fee<br/>for FUTURE launches only] --- B2[QuoteRegistry<br/>which assets may be a pairing] --- B3[LaunchHook<br/>the LP-fee curve<br/>≤ 5 %]
    B4[FlyFurnace<br/>burn by hand, name the keeper,<br/>set tolerance and cap]
  end
  subgraph FK [furnace keeper · a hot key]
    B5[autoBurn only]
  end
  subgraph LC [a launch's creator]
    B6[its share of the fee<br/>claimed, never pushed] --- B7[its description and logo<br/>signed edit]
  end
Key Can do Bound by
LaunchFactory owner setLaunchFee; setProtocolFeeBps applies to future launches only: a live pool's fee is fixed when it is registered and never moves under its holders; the protocol fee is ≤ 1.00%
QuoteRegistry owner setQuote: allow or disallow a pairing asset a launch's pairing is fixed when it is created
FLY owner on LaunchHook setLpFeeSchedule: start fee, base fee, decay LP fee ≤ 5.00%, decay ≤ one day; it is paid to liquidity providers, not the protocol
FlyFurnace owner burn(asset, minFlyOut) by hand; setKeeper; setTolerance (1% to 10%); setMaxAutoBurnUsdg; setFlyUsdgPool once the FLY/USDG pool cannot be re-pointed afterwards, so no one can later route every burn through a pool they control
furnace keeper autoBurn(asset); the owner can call it too, as the backup no minimum stated by the caller: the contract requires the USDG-to-FLY swap to return at least what the FLY hook's reference price buys, less the tolerance, or the call reverts. A sandwich in front of it makes it revert instead of burn less.
a launch's creator receive its share of each pool's fee (50% of the protocol fee); sign an edit to its own description and logo the share is credited, then claimed: anyone can trigger the payout to the creator, and a frozen address can never block a trade

Things nobody can do on the launchpad: change a live pool's fee; remove the liquidity a graduation seeds (the hook only ever adds liquidity or collects fees); change a launch's pairing; or make a trade depend on a recipient being able to receive.

One honest limit, on purpose: the furnace's price guard covers the USDG-to-FLY swap only. An asset that is neither USDG nor FLY (ETH from launch fees, WETH, a stock token) is first swapped to USDG through its pairing pool, and that first hop has no time-weighted price to check against. A sandwich of that hop could take part of that asset's balance in the furnace. The balances are small, the keeper cannot reach anything else, and the owner can always burn by hand with a minimum of their own.