k'hook docs

Everything about k’hook, in one place.

Dual-rail Uniswap v4 launchpad on Robinhood Chain. Quote-only fees, locked LP, modular hooks. No custody. No hidden steps.

34 pages · 33 figures · updated Oct 20, 2018

SectionsOverview

Introduction

Overview

k'hook is a dual-rail Uniswap v4 launchpad on Robinhood Chain. Quote-only fees, locked LP, modular hooks. No custody. No hidden steps.

Every token is a hooked pool. Pick protection, tokenomics and fee modules, then freeze them at launch. The module set covers 384 programmable hook combinations.

The module set is part of the launch transaction and cannot change afterwards.

Every swap feeds $KHOOK

Token buybacks. Holder drops. One connected fee cycle.

Every swap feeds $KHOOKFig. 01
Swap on a k'hook pool1% base + 0–9% hook tax (+ Anti-Snipe at open)
1%Base feealways 60 / 10 / 30
60%Creatorescrowvesthook pot
10%$KHOOK dropbuys the launched ticker$KHOOK holdersepoch push
30%Protocol
80%Buy & burnbuys $KHOOK, burns it
20%Opsfunds operations
0–9%Hook taxhook potBacked FloorAuto-BurnDeepen LPsHolder AirdropHook → Creatorthe sinks you packed

Quotes: ETH, USDG or a Stock Token (NVDA, AAPL, TSLA, SPY, …). The fee is always taken in the quote.

Every Master and graduated Classic swap pays the 1% in quote. The 10% $KHOOK slice cannot be removed. More volume, more dollars routed to $KHOOK holders.

Hold 1 $KHOOK and you are exposed to every token launched on k'hook. 10% of the 1% base fee buys that ticker and epoch-pushes it to live $KHOOK holders. More $KHOOK, larger slice of every launch. Hold $KHOOK, collect all tokens.

The drop makes you a holder of each ticker it buys. You also collect that ticker's holder perks, such as Holder Airdrop payouts in ETH, USDG or Stock Tokens.

Anyone can create a token, lock liquidity and start trading from a wallet. The site never holds ETH, tokens or keys.

Modules

v4 hooks that shape how a launched token trades. Each is packed into the pool at launch.

CategoryModules
ProtectionAnti-Snipe · Anti-MEV · Max Tx · Backed Floor · Deepen LPs
TokenomicsAuto-Burn · NFT Strategy · Buyback Vesting
RewardsHolder Airdrop · Hook → Creator · Creator → Hook
Trading feesFixed Fees · Dynamic Fees

Two launch rails

Master opens a v4 pool with MasterLaunchHook in the same transaction. Classic sells on a bonding curve first, then graduates into a GraduatedFeeHook pool. Both mint 1 billion tokens. Both take fees in quote only.

MasterClassic
PoolFrom block 0, in the launch transactionAfter the curve fills
ModulesProgrammable hooks: floor, burn, vesting, …None. 1% base only
PriceOpens at ~$5,000 FDVBonds, then graduates at ~4.2 ETH-eq
HookMasterLaunchHookGraduatedFeeHook

Before you trade or launch

  • Verify the token contract. Names and logos are copied constantly.
  • Most tokens go to zero. Liquidity can vanish.
  • k'hook is not responsible for losses. This is not financial advice. Read the Terms and Privacy Policy.

Architecture

The app is a wallet interface over Uniswap v4. Fees, floors, burns and airdrops live in the hook, not in a backend that can change the rules after launch.

Protocol stack

ArchitectureFig. 02
Appk'hookmarketplace, launch wizard, token desk
RouterKhookRouter, BalancedAggregatorhooked swaps, USDG multi-pair splits
HookMasterLaunchHook / GraduatedFeeHookquote-only fees + modules
PoolUniswap v4 PoolManagerhooked pool, locked liquidity
ChainRobinhood Chain · 4663ETH gas · ETH, USDG and Stock Tokens as quotes

Money flow

ArchitectureFig. 03
walletKhookRouterPoolManagerMasterLaunchHooktakes 1% + hook tax (+ snipe), quote only

Buys are charged in beforeSwap; sells in afterSwap, on the executed quote leg.

1% base
60%CreatorFeeEscrowBuybackVaulthook pot
10%$KHOOK dropbuys the launched tickerKhookDropVault$KHOOK holdersepoch push
30%ProtocolProtocolRevenueDistributor
80%Buy & burnbuys $KHOOK, burns itKhookBuyback
20%Opsfunds operations
Hook tax
PotFloorVaultAuto-BurnDeepen LPsHolderAirdropVaultcreator

Hook tax sinks are set per launch by the bitmask.

Contracts

ContractJob
LaunchFactoryMaster launches: launch, launchMulti, launchWithNftStrategy. Mints the token, initializes the pool(s) and locks LP in one transaction.
LaunchFactoryQueryRead-only paginated launch index (getLaunchPage).
BondingLaunchFactoryClassic rail: bonding curve, then graduation into a v4 pool.
LaunchTokenThe fixed-supply, burnable ERC-20 every launch mints. Stores metadataURI.
MasterLaunchHookShared v4 hook for Master pools: quote-only fees, locked LP, modules.
GraduatedFeeHookv4 hook for graduated Classic pools: 1% base only.
LiquidityLockerHolds graduated Classic LP.
KhookRouterHooked swaps: one pool, or a bridge leg plus the launch leg in one unlock.
BalancedAggregatorUSDG splits across up to five multi-pair markets.
StockTokenRegistryThe canonical Stock/USDG v4 bridge pool for each listed Stock Token.
FloorVaultBacked Floor quote reserves and redemptions.
FeeEscrowDefault home of creator fees.
BuybackVaultVested creator proceeds, time or FDV unlock.
HolderAirdropVaultHolder Airdrop pots and epoch pushes.
KhookDropVaultThe mandatory 10% $KHOOK holder drop.
V4ClaimsRedeemerTurns ERC-6909 PoolManager claims into tokens.
ProtocolRevenueDistributorSplits the 30% protocol cut: 20% ops, 80% buyback.
FeeEthRailConverts protocol fee inventory: Stock Token → USDG, USDG → ETH.
KhookBuybackSpends buyback ETH on $KHOOK and burns it.
NftSweeperRegistry, SweepVault, NftSweepRaffleNFT Strategy: fee routing, one vault per collection, raffles.

Addresses are on the Contracts page.

Off-chain pieces

  • Indexer. Read-only. Serves the Explore catalog, trades, candles and holders. It can lag. Everything it serves can be rebuilt from chain data. See Integration.
  • Keeper. Runs the periodic jobs: $KHOOK holder sync and tryPush, Holder Airdrop nudges, KhookBuyback.execute, the protocol fee rail, NFT Strategy harvest, sweep and raffle. It cannot change a launch's modules or move user balances. Its roles are listed under Risks.

Port notes

k'hook's contracts are an MIT-licensed port of hookit (Ink, chain 57073). Economics, modules, the bitmask layout, limits and event signatures are unchanged apart from renames and a few added events. The chain plumbing differs, and a set of upstream bugs is fixed. Differences from hookit lists every change.

AreaOn Robinhood Chain
Stock venueRobinhood Stock Tokens against USDG. One canonical Stock/USDG v4 pool per stock, listed in StockTokenRegistry.
PricesChainlink feeds for ETH/USD, USDG/USD and every listed Stock Token.
Block counterArbSys(0x64).arbBlockNumber() for per-block limits. block.number is an L1 estimate on this chain.
NFT sweepsSeaport 1.6 on Robinhood Chain.
RenamesHookitSwapRouter → KhookRouter, HktHolderDropVault → KhookDropVault, HkitBuyback → KhookBuyback, $HKT → $KHOOK.

Protocol

How launches work

A launch is one (or two) wallet transactions. The second is an approval, needed only when a dev buy spends USDG or a Stock Token. What you pick, Master or Classic, decides whether a pool exists from block 0 or after the curve fills.

Master Launch Studio, step by step

Six screens. Nothing is written on-chain until you sign on step 6.

StepScreenWhat you decide
1 / 6Token & pairName, symbol, art, and the quote the pool will trade against: ETH, USDG, or a Stock Token. Multi-pair can add more markets later in this step. Metadata pins via IPFS; the token stores its metadataURI on-chain.
2 / 6ProtectionOptional shields that freeze at launch: Anti-MEV, Anti-Snipe, Max Tx. Off by default. You cannot edit them after the tx.
3 / 6TokenomicsWhere hook-tax value goes over the life of the token: Holder Airdrop, Auto-Burn, Backed Floor, Buyback Vesting, Deepen LPs, Hook → Creator. Buyback Vesting cannot combine with Creator → Hook.
4 / 6Trading feesHow much extra tax sits on top of the mandatory 1%: a Fixed hook tax or Dynamic Fees, not both. A tax needs a 100% destination. Creator → Hook can route the 60% creator cut into the pot.
5 / 6Fee splitSplit the hook pot to 100% across the sinks you turned on, for example Auto-Burn 80% · Deepen LPs 20%. Floor + burn + deepen + airdrop + Hook → Creator must sum to 100% when the pot is funded. No pot if tax is 0 and Creator → Hook is off.
6 / 6Review & launchRead the recap, set an optional same-tx dev buy, sign. The bitmask and vestPacked freeze here. LP locks in the same transaction. Trading is live when the receipt lands.

The recap on step 6:

FieldValue
Supply1,000,000,000
Base fee1% · 60 / 10 / 30
LPLocked same tx
  • The same six screens back every Master launch. The bitmask and vestPacked freeze when you sign. Classic uses a shorter bonding form instead of these six steps.
  • The pool opens at ~$5,000 FDV, sized in the chosen quote at launch. ETH uses Chainlink ETH/USD. A Stock Token uses its own Chainlink feed. See Why Stock Tokens.
  • The dev buy runs inside the launch transaction. It is exempt from Anti-Snipe and still pays the 1% base and any hook tax. Two caps apply: tokens out ≤ 2.5% of supply, and quote in ≤ 2.5% of the $5,000 launch FDV ($125 worth).
  • The launch fee is 0.0005 ETH plus gas, paid in ETH whatever the quote. See Fees.

Master swap lifecycle

One unlock. The hook runs on both sides of the swap.

Master swap lifecycleFig. 04
KhookRouteropens the unlockPoolManager.unlockswap on the launch poolbeforeSwapAnti-MEV, Anti-Snipe, Max Tx checks; due Holder Airdrop and $KHOOK batches push. Buy: take 1% + hook tax (+ snipe) from the quote in, then split it.swapthe v4 curve fills the tradeafterSwapSell: take 1% + hook tax from the quote the pool paid out, then split it. Auto-Burn, the $KHOOK drop buy and Deepen LPs run; FDV is observed for vest and airdrop targets.

Split: 60 / 10 / 30 on the 1%, hook tax into the pot. Floor and airdrop shares are credited at the split.

The fee is never a memecoin tax. A buy's fee is known before the swap. A sell's fee waits for the fill and is charged on the quote that actually executed. Auto-Burn, the $KHOOK drop buy and Deepen LPs spend their queued quote in afterSwap, after that swap's fee has filled the pots. The 1% split never changes.

Classic

  • Quote pairs: ETH, USDG, or a Stock Token.
  • Same 1B supply. 80% sells on the curve. 20% is reserved for graduation LP.
  • The curve graduates at ~4.2 ETH, or the USDG / Stock Token equivalent fixed at launch.
  • After graduation, the remaining tokens and the collected quote seed a full-range v4 pool.
  • GraduatedFeeHook keeps the same 1% quote-only base. No Master hook tax.

See Graduation.

Multi-pair

One token, up to five quote markets, launched in a single LaunchFactory.launchMulti. Each market is its own Uniswap v4 pool with the same MasterLaunchHook bitmask. Supply is split by the bps you set (must sum to 10_000).

Multi-pairFig. 05
$TICKER1,000,000,000 supply
USDG pool40% · 4000 bpsAAPL pool30% · 3000 bpsNVDA pool30% · 3000 bps

The same MasterLaunchHook bitmask runs on every pool.

  • 1–5 markets. USDG and Stock Tokens only. ETH is single-pair (NativeQuoteNotAllowedInMulti).
  • Each market has its own poolId, tick range and liquidity. The token page has a market switcher.
  • Explore marks multi-pair tokens. Indexer fields: marketCount, markets[].
  • Backed Floor is rejected in multi (BackedFloorNotAllowedInMulti). The wizard hides the floor card when you add a second market.
  • Buyback Vesting and Holder Airdrop run on every market. Holder Airdrop keeps a separate pot per quote.
  • A market at 0 bps reverts InvalidMarketBps. The same quote twice reverts DuplicateQuote.
  • Gas scales: ~2.8M base + ~950k per extra market. These are execution gas figures. On Robinhood Chain the receipt also carries a data-posting component.

Balanced aggregator

BalancedAggregator is the PAIR-style router for multi-market tokens. Automatic routing is USDG only: pay USDG, or sell the project token for USDG. Stock legs hop USDG ↔ Stock Token on the canonical Stock/USDG v4 pool registered in StockTokenRegistry, then Stock Token ↔ project token on the canonical launch v4 pool. ETH is not a multi-pair quote. Picking a ticker (AAPL, NVDA, …) trades that pool directly and is not the aggregator.

  • It quotes every canonical launch pool: project token → Stock Token on the launch v4 book, then Stock Token → USDG on the bridge pool. The AAPL (or deepest) pool is used when it is the best fill. USDG is that hop, not a different dump.
  • It compares the best single pool with discrete multi-pool allocations. It splits across books when that output matches or beats the single pool, so impact is spread and prices stay aligned.
  • It applies per-leg minimums plus an aggregate minimum, then re-quotes and simulates immediately before wallet signing.
  • If the aggregator cannot simulate a split, the desk still executes the winning single route (token → best Stock Token → USDG) through KhookRouter. Picking a ticker trades that pool directly and skips the USDG hop.
Balanced aggregatorFig. 06
BalancedAggregator.buyExactInput100 USDG, exact input
60USDG legUSDG/NFLX bridgeNFLX/$TICKER pool
40USDG legUSDG/NVDA bridgeNVDA/$TICKER pool

One unlock for every leg. $TICKER lands in the wallet.

Example
Buy100 USDG → 60% NFLX leg + 40% NVDA leg → tokens to your wallet.
BridgeEach stock leg uses the canonical Stock/USDG pool from StockTokenRegistry.bridgeKey(stock), the same hop as the KhookRouter composite.
SellReverse path: token → Stock Token → USDG, still one tx when routed through the aggregator.

BalancedAggregator splits exact input across canonical launch legs in one unlock.

Solidity
struct RouteLeg { uint8 marketIndex; uint256 amountIn; uint256 minAmountOut; }

function buyExactInput(uint256 launchId, address token, uint256 amountIn, uint256 minTotalOut,
    RouteLeg[] calldata legs, address recipient, uint256 deadline) external returns (uint256 totalOut);

function sellExactInput(uint256 launchId, address token, uint256 amountIn, uint256 minTotalOut,
    RouteLeg[] calldata legs, address recipient, uint256 deadline) external returns (uint256 totalOut);

Leg inputs must sum to amountIn. deadline may sit at most 1 day ahead.

Why Stock Tokens

Robinhood Chain is where Robinhood Stock Tokens live, and they trade against USDG. k'hook lets a launch pair against a Stock Token (NVDA, AAPL, TSLA, SPY, …) or against USDG itself. Traders pay and receive USDG. The pool is priced in the stock. Launch sizing and FDV use Chainlink, not a thin pool.

  • Native quotes. Stock Tokens and USDG are the reference assets on this chain. A launch can sit next to them instead of only ETH.
  • USDG in, USDG out. The trader never has to hold the Stock Token. One canonical Stock/USDG pool per stock is the hop.
  • Oracle-priced. Every listed Stock Token has a Chainlink USD feed. The $5,000 start FDV, the 4.2 ETH-eq graduation target and FDV unlocks read it.
  • Stock payouts. Holder Airdrop on a Stock-quoted launch pays holders in that Stock Token.

Stock Tokens

PropertyValue
WhatERC-20 tokens on Robinhood Chain. Each tracks one U.S.-listed stock or ETF. About 195 are live at the time of writing.
Decimals18
RebasingNo. ERC-8056 uiMultiplier() scales the amount wallets display. Raw balances never change.
Price feedOne Chainlink USD feed per listed stock. 8 decimals. Reports the multiplier-adjusted price of one token. Updates 24/5.
Pause flagoraclePaused() on the token. Advisory. Set while the feed is paused, for example during a corporate action.
On k'hookThe live list is StockTokenRegistry.stocks(). A stock must be listed there before it can be a quote.

USDG

PropertyValue
TokenGlobal Dollar (USDG), 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
Decimals6
RoleThe asset Stock Tokens trade against. A launch quote, single or multi-pair. The settlement asset for composite routes and BalancedAggregator.
PriceChainlink USDG/USD feed, set on the factory (quoteConfigs(usdg)), 25 h max age.

Canonical bridge pools

A Stock Token can trade against USDG in many ordinary Uniswap v4 pools. k'hook fixes one per stock. The owner lists it in StockTokenRegistry, and every composite route, aggregator leg and protocol fee conversion uses that pool.

Solidity
function usdg() external view returns (address);
function isStock(address token) external view returns (bool);
function stocks() external view returns (address[] memory);
function bridgeKey(address stock) external view returns (PoolKey memory); // canonical Stock/USDG v4 pool
function zeroForOne(address stock, address tokenIn) external view returns (bool);
function isAllowedBridgeHook(address hooks) external view returns (bool); // hooks == 0 or allowlisted
function spotUsdX18(address stock) external view returns (uint256);       // bridge spot, USDG ≈ $1; 0 if uninitialized
  • list(stock, key) checks that the key pairs exactly {stock, USDG} in sorted order, that key.hooks passes isAllowedBridgeHook, and that the pool is initialized.
  • The registry is routing data. Its spotUsdX18 is a fallback price input only.
  • Delisting only affects new launches and routing. Existing pools keep trading.
  • The bridge pool holds the Stock Token itself. No wrapper.
  • Read the key from bridgeKey(stock). Never derive a pool id from an assumed fee or tick spacing.

USD prices size things. They never fill trades. Swaps always fill on the AMM curve.

Where a USD price is usedWhen
Opening a Master pool at ~$5,000 FDVAt launch
The Classic graduation target in USDG or a Stock Token (4.2 ETH-eq)At launch, then stored
FDV targets for Buyback Vesting and Holder AirdropOn every swap, best effort
USD prints in the appContinuously

A Stock Token quote is priced by quoteUsdPriceX18(stock) in this order:

  1. The Chainlink feed, if answer > 0, updatedAt is within 5 days (EQUITY_ORACLE_MAX_AGE), and the token's oraclePaused() is not true.
  2. Else the bridge spot, StockTokenRegistry.spotUsdX18(stock), if non-zero and within ±20% (STOCK_SPOT_MAX_DEVIATION_BPS = 2,000) of the stored snapshot.
  3. Else the stored snapshot, if no older than 5 days.
  4. Else the call reverts StalePrice().
FeedMax ageFallback
ETH/USD25 h (CRYPTO_ORACLE_MAX_AGE)last synced snapshot, while its round is at most 24 h old (USD_SNAPSHOT_MAX_AGE)
USDG/USD25 hnone
Stock Token / USD5 days (EQUITY_ORACLE_MAX_AGE)bridge spot within ±20%, then snapshot up to 5 days
  • Robinhood Chain feeds have a 24 h heartbeat and a 0.5% deviation threshold. 25 h allows one hour of slack past a heartbeat.
  • Stock feeds pause over weekends, market holidays and corporate actions. They have gone about 80 h without an update over a normal weekend and about 96 h over a long one. 5 days covers a long weekend with slack.
  • Anyone can refresh a quote's snapshot from its live feed with syncQuoteUsdPrice(token) on either factory. It copies only a round that passes the checks in step 1, and dates the snapshot at the round's updatedAt, so the snapshot never outlives its round by more than 5 days.
  • syncEthUsdPrice() does the same for ETH/USD: the snapshot is dated at the round's updatedAt, so the 24 h fallback counts from when Chainlink published the round, not from the sync. Neither call ever replaces a newer snapshot with an older round.
  • decimals() is read from each feed (8 today), never hardcoded.
  • No L2 sequencer-uptime feed is listed for Robinhood Chain. The factories carry an optional sequencerUptimeFeed, unset by default. When set, a down sequencer, or less than 1 h since it came back, makes the feed path unavailable and pricing falls back as above.

The composite hop

A Stock-quoted launch takes USDG on the buy panel. KhookRouter bridges and buys in one unlock.

The composite hopFig. 07
wallet pays USDGKhookRouter.swapExactInCompositeone unlockUSDG → Stock Tokenleg 1 the canonical Stock/USDG pool (bridgeKey); pays that pool's LP fee, no k'hook feeStock Token → $TICKERleg 2 the launch pool; MasterLaunchHook takes 1% + hook tax, in the Stock Token$TICKER to wallet

The wallet never holds the Stock Token.

  • Sells run the other way with swapExactInCompositeSell: token → Stock Token → USDG.
  • The caller supplies the bridge PoolKey. KhookRouter only checks StockTokenRegistry.isAllowedBridgeHook(bridgeKey.hooks). The app passes bridgeKey(stock).
  • minAmountOut guards the final output. Each leg takes its own sqrt price limit.
  • A wallet that already holds the Stock Token can call swapExactIn on the launch pool and skip the bridge. The buy panel itself takes USDG.

What the bridge leg pays

  • The bridge pool's own LP fee: the fee field of its PoolKey. If the key carries the dynamic-fee flag (0x800000), its hook sets the fee per swap.
  • Its hook, if it has one. Only allowlisted hooks pass.
  • Nothing to k'hook. The k'hook fee is charged once, on the launch leg.

Quote the bridge leg live with the V4 Quoter (0x8Dc178eFB8111BB0973Dd9d722ebeFF267c98F94). Do not hardcode a fee.

Composite trades pay the bridge pool's LP fee to that pool's LPs. Deeper bridge pools give tighter USDG fills on the next composite trade.

Protocol fees in Stock Tokens

Fees on a Stock-quoted pool accrue in that Stock Token, like every quote-only fee. Creator fees are claimed in the Stock Token. The protocol's 30% is railed to USDG before the split: ProtocolRevenueDistributor calls FeeEthRail.stockToUsdg on the canonical bridge pool, then routes 20% to ops and 80% to the buyback wallet, KhookBuyback.

  • The conversion is operator-only: distributeToBuyback(stock, minUsdgOut) and railStockToUsdg(stock, minUsdgOut). The caller sets the minimum USDG out, so an open call could be sandwiched. The keeper runs it. ETH and USDG revenue never swaps at this step, and its distribute stays permissionless.
  • KhookBuyback.executeUsdg swaps the USDG share to ETH through FeeEthRail, then buys and burns $KHOOK. Also operator-only.

Corporate actions and the multiplier

  • A stock split or similar action changes uiMultiplier(). Raw balances and pool reserves do not move.
  • Pools trade raw token units. Nothing in k'hook rescales on a corporate action.
  • The Chainlink feed already reports the multiplier-adjusted price of one token. k'hook never multiplies the feed by uiMultiplier().
  • Wallets may show a different share-equivalent amount after an action. Pool math, fees and FDV use raw units.

Oracle pauses

Stock feeds update 24/5. Over weekends, market holidays and corporate actions they stop updating. During a corporate action the token's oraclePaused() returns true.

  • k'hook skips a paused or stale feed and falls back to the bridge spot (within ±20% of the snapshot) or a snapshot up to 5 days old.
  • If every path fails, a new launch quoted in that stock reverts StalePrice().
  • A Classic graduation target is fixed at launch, so graduation itself never waits on the oracle.
  • FDV targets do not advance while the price read reverts. The swap still goes through, and it counts as an FDV of $0 in the 1-hour hold window, so that window confirms nothing.
  • Pools keep trading 24/7 on their own curves, including while the stock's market is closed. Prices can gap when it reopens.

Read it from the source

  • StockTokenRegistry (—): listed stocks and their bridge keys.
  • LaunchFactory.quoteUsdPriceX18(quote): the USD price k'hook uses, with the full fallback chain.
  • The Stock Token contract: uiMultiplier(), oraclePaused().
  • The Chainlink feed for each stock: LaunchFactory.quoteConfigs(stock).

Trading

Buys and sells hit the live Uniswap pool (Master or graduated Classic) or the bonding curve (Classic before graduation). The price on screen is the on-chain spot, not a k'hook quote.

Hooked swap path

TradingFig. 08
walletsign a buy or sellKhookRouterkeeps hook accountingv4 pool1% quote feeMasterLaunchHookquote fee → 60 / 10 / 30
TermMeaning
PriceQuote per token, from sqrtPriceX96 (pool) or virtual reserves (curve).
Market cap / FDVPrice × 1B supply, in USD via Chainlink ETH/USD, the Stock Token's Chainlink feed, or USDG/USD.
LiquidityTVL in USD near spot. Thin books still move a lot per trade.
SlippageIf spot moves more than this % before inclusion, the swap reverts.
Price impactHow far this size walks the curve or the book.

The trade panel shows a fee breakdown before you sign: base 1%, hook tax, snipe, and the amount you receive.

Why the k'hook router

Master and graduated pools need KhookRouter so the fee take, floor fills, burns and airdrop pushes run as the hook expects. A generic DEX UI can route to a pool without the k'hook hook, which skips the fees and modules, or mis-quote the hooked pool and revert.

Why the k'hook routerFig. 09
Generic DEX UI
  • wallet → generic router
  • skips hook accounting, or reverts
KhookRouter
  • wallet → KhookRouter
  • fees and modules run
FunctionUse
swapExactInSingle hooked pool, paying in the pool's quote currency.
swapExactInCompositeBridge leg (canonical Stock/USDG pool, or an ETH ↔ USDG pool) then the hooked launch leg, one unlock.
swapExactInCompositeSellToken → quote → stable, one unlock.
  • Stock-quoted pools: pay USDG. ETH-quoted pools take ETH.
  • Bridge keys must pass StockTokenRegistry.isAllowedBridgeHook: no hook, or an allowlisted one. Anything else reverts UnauthorizedBridgeHook.
  • minAmountOut is the slippage guard. A sqrtPriceLimitX96 of 0 means no price limit.
  • Every exact-input leg must consume its whole input. If a price limit or the edge of a pool's liquidity stops a leg early, the router reverts PartialFill(), so no one pays a fee on input that did not trade. A price limit is a hard stop, not a partial fill.
  • Native ETH is paid as msg.value. Unused ETH is refunded in the same transaction.
Solidity
function swapExactIn(PoolKey calldata key, bool zeroForOne, uint256 amountIn,
    uint256 minAmountOut, uint160 sqrtPriceLimitX96) external payable returns (uint256 amountOut);

function swapExactInComposite(PoolKey calldata bridgeKey, bool bridgeZeroForOne, uint256 amountIn,
    PoolKey calldata hookKey, bool hookZeroForOne, Currency quoteCurrency, uint256 minAmountOut,
    uint160 bridgeSqrtLimit, uint160 hookSqrtLimit) external payable returns (uint256 amountOut);

function swapExactInCompositeSell(PoolKey calldata bridgeKey, bool bridgeZeroForOne, uint256 amountIn,
    PoolKey calldata hookKey, bool hookZeroForOne, Currency quoteCurrency, uint256 minAmountOut,
    uint160 bridgeSqrtLimit, uint160 hookSqrtLimit) external payable returns (uint256 amountOut);

Classic before graduation trades on BondingLaunchFactory.buy(launchId, quoteIn, minTokensOut) and sell(launchId, tokensIn, minQuoteOut), not through the router. sell returns the quote paid after the 1% fee.

For integrators

  • Quotes. The Uniswap V4 Quoter simulates the hook, fee included. A buy pays its fee out of the quote it sends. A sell receives the pool's quote output minus 1% + hook tax of that output. With Dynamic Fees the tax ramps on that output: preview it with MasterLaunchHook.dynamicFeeForSwap(poolId, output, false) before the swap. See Fees.
  • Gas headroom. A Master pool swap can pay out a Holder Airdrop or $KHOOK drop batch, up to 48 holders, inside the hook, in try/catch. eth_estimateGas returns the least gas at which the swap does not revert. That can starve the batch, or fall short when a batch comes due before inclusion. Add headroom: the k'hook app sends 1.6× the estimate on hook swaps and on launches with a dev buy. Robinhood Chain caps one transaction at 32M gas.
  • Anti-MEV. On Anti-MEV pools one tx.origin gets one swap per pool per block. Wait for a swap to land before sending the next one on the same pool. Quote with an eth_call that does not use the trader as tx.origin, so the lock cannot trip the simulation.

Graduation

Classic only. Master already has a pool.

GraduationFig. 10

Virtual constant product. At 4.2 ETH-eq collected the v4 pool opens at the last curve price; 20% of supply is reserved for its full-range LP.

  • The next trade that pushes collected quote through ~4.2 ETH-equivalent graduates in the same flow. No button. Anyone can also call graduate(launchId) once the target is met.
  • Trading moves from BondingLaunchFactory to a Uniswap v4 pool.
  • 20% of supply + collected quote become locked full-range LP, held by LiquidityLocker.
  • The pool opens at the last curve price. The virtual reserves are sized so the curve sells out exactly at the target and the LP starts where the curve ended. No discount for the first pool buyers.
  • Curve math rounds in the curve's favour. After a buy the new token reserve rounds up, after a sell the new quote reserve rounds up. k never falls, a buy-then-sell round trip never extracts a wei, and the quote collected at graduation is at least the target. A dust sell whose output rounds to 0 returns 0.
  • sell(launchId, tokensIn, minQuoteOut) returns the quote actually paid, after the 1% fee: the same number minQuoteOut checks and Sold.quoteOut logs.
  • Fees stay the 1% base, split 60% / 10% / 30% creator / $KHOOK / protocol.
  • Graduation is a funding threshold, not a quality stamp.
  • Creator fees after graduation sit on GraduatedFeeHook.pendingCreatorTax. sweepQuote(poolId) moves them into FeeEscrow, then claim.

Targets in USDG and Stock Tokens

The target is 4.2 ETH for an ETH-quoted launch. For USDG or a Stock Token, the factory converts 4.2 ETH at launch: 4.2 × ETH/USD ÷ quote/USD, using Chainlink ETH/USD and the quote's feed (see Why Stock Tokens). The result is stored as graduationQuote and does not move afterwards, whatever ETH or the stock does.

Example: at ETH/USD = $3,000, a USDG-quoted Classic launch graduates at 12,600 USDG.

Read it on-chain from BondingLaunchFactory.launches(launchId) (realQuote, graduationQuote), or from the indexer's bondingPhase, realQuote, graduationQuote and bondedPct.

Fees

Every swap pays a quote-only fee: ETH, USDG, a Stock Token, whatever the pool trades against. You never pay the fee in the launched memecoin.

Where the 1% goes

FeesFig. 11
Any swapquote-only fee → MasterLaunchHook, one take, packed at launch
1%Base fee
60%Creatorescrowvesthook pot
10%$KHOOK dropbuys the launched ticker$KHOOK holdersepoch push
30%Protocol
80%Buy & burnbuys $KHOOK, burns it
20%Opsfunds operations
opt.Hook taxhook potmodulesvestcreator, via Hook → Creator

The 1% always splits 60 / 10 / 30. Hook tax never uses that split. It fills the pot, then modules.

1% base feeShareWhere it goes
Creator60%FeeEscrow, BuybackVault if vesting is on, or the hook pot if Creator → Hook is on.
$KHOOK10%Buys the launched token and epoch-pushes it pro-rata to live $KHOOK holders.
Protocol30%Then 20% ops / 80% native-token buyback.

The three fee layers

LayerRule
Base (1%)Mandatory. Always 60% creator / 10% $KHOOK / 30% protocol. The 10% $KHOOK slice cannot be removed or rerouted at launch.
Hook taxOptional Master extra, 0–9%, so base + tax ≤ 10%. Funds the modules you pick as destinations. Shares of the pot (Hook → Creator, burn, floor, Deepen LPs, airdrop) must sum to 100%. Fixed or Dynamic Fees with no destination cannot launch.
Anti-SnipeTemporary buy-only tax that decays to 0. Its take follows the same 60 / 10 / 30 as the base.

What the fee is charged on

The fee is a share of the swap's quote amount. Which amount depends on the side the trader fixes.

SwapFee basisWhen
Buy, exact inputThe quote you paybeforeSwap, out of that amount. The pool swaps the rest.
Sell, exact outputThe quote you receivebeforeSwap. The pool pays out your amount plus the fee.
Sell, exact inputThe quote the pool pays for your tokensafterSwap. You receive it minus the fee.
Buy, exact outputThe quote the pool charges for your tokensafterSwap. You pay it plus the fee.
What the fee is charged onFig. 12
beforeSwap · quote fixed up front
  • exact-input buy
  • exact-output sell
  • fee on the specified quote
afterSwap · quote known after the fill
  • exact-input sell
  • exact-output buy
  • fee on the quote leg that executed
same rate, same split: 1% base + hook tax (+ snipe on buys)
  • The rate is the same on every path: 1% base + hook tax, split the same way. Anti-Snipe only reaches exact-input buys: sells never pay it, and exact-output buys revert while it is live.
  • When the quote amount is not fixed up front, the hook waits for the fill and charges the quote leg that executed. Price impact never inflates or shrinks the fee.
  • Dynamic Fees ramp on that executed quote leg, against the in-range depth the pool had before the swap.
  • KhookRouter and BalancedAggregator send exact-input swaps only: buys pay on the quote in, sells on the quote out.
  • Graduated Classic pools charge their 1% the same way.

Worked example

A 1 ETH exact-input buy on a Master pool with 1% base + 2% hook tax. Auto-Burn 80% and floor 20% of the hook pot.

SliceQuoteWhere it goes
Base 1%0.010 ETH0.006 creator · 0.001 $KHOOK drop · 0.003 protocol
Hook tax 2%0.020 ETH0.016 burn buyback (Auto-Burn) · 0.004 FloorVault
Trader pays1.000 ETHReceives 0.97 ETH worth of tokens

Same buy with Hook → Creator at 100% and no other destination: the 0.020 ETH hook tax is credited to the creator and is claimable. Protocol still only takes 0.003 ETH from the 1% base.

Same 1 ETH buy with Buyback Vesting + a 5% hook tax, 100% Hook → Creator. The tax is subject to the vest. It is not instant creator fees.

SliceQuoteWhere it goes
Base 1%0.010 ETH0.006 vests (creator cut) · 0.001 $KHOOK drop · 0.003 protocol
Hook tax 5%0.050 ETH0.050 vests in BuybackVault (100% Hook → Creator)
Total vesting0.056 ETH5.6% of the buy. Claim after the time / FDV unlock.
Trader pays1.000 ETHReceives 0.94 ETH worth of tokens

"Worth of tokens" is valued at spot before price impact.

The sell side of the first pool (2% hook tax): tokens that fetch 1.000 ETH from the pool pay 0.030 ETH (1% + 2% of 1.000 ETH) in afterSwap. The seller receives 0.970 ETH. The split is the same as for the buy.

Launch fee

0.0005 ETH, plus gas. Paid in ETH with the launch transaction, whatever the quote, and forwarded by the factory to the treasury. Not refundable. Separate from swap fees.

Fixed at launch

  • Pool LP fee is 0%. The hook is the fee switch. Dynamic Fees pools carry the dynamic-fee flag and the hook overrides the LP fee to 0 on every swap.
  • Hook tax funds destinations you pick. Shares (Hook → Creator, burn, floor, Deepen LPs, airdrop) must equal 100% whenever the pot is funded.
  • Fixed or Dynamic Fees with no destination cannot launch. Hook → Creator alone is 100% to the creator.
  • Creator → Hook and Buyback Vesting cannot both take the creator's 60%.
  • Fees come from the quote leg only: the specified quote in beforeSwap, or the executed quote leg in afterSwap. See What the fee is charged on.

Creator fees

The creator's 60% of every 1% base, and of the temporary snipe take, is not paid inside the swap. Where it sits depends on the modules you packed.

Creator feesFig. 13
1% basealways onAnti-Snipe taketemporary
Creator 60%packed at launch, one stream
FeeEscrowdefault; claim the quote on the token page
BuybackVaultif vesting is on; clock or FDV unlock
Hook potif Creator → Hook; no creator claim

Both inputs are quote only. Anti-Snipe uses the same 60 / 10 / 30 while the window is open.

The 10% $KHOOK drop and the 30% protocol cut never go to the creator.

DestinationWhenHow to collect
FeeEscrow (default)Neither Buyback Vesting nor Creator → HookMasterLaunchHook.feeEscrow(). Claim quote on the token page (FeeEscrow.claim(quote), or claimAll for several quotes). Classic after graduation: sweepQuote(poolId) on GraduatedFeeHook first, then claim.
BuybackVaultBuyback Vesting is onTime vest or FDV cliff / steps. Also takes the Hook → Creator slice of the hook pot. Creator-only claim of the unlocked slice (BuybackVault.claim(token)).
Hook potCreator → Hook is onThe 60% joins Hook → Creator / floor / burn / deepen / airdrop. Nothing to claim as creator fees unless Hook → Creator takes a share.
  • Buyback Vesting and Creator → Hook cannot both be on.
  • The 10% $KHOOK drop is mandatory. It and the 30% protocol cut never go to the creator.
  • Fees are paid in the pool's quote. A Stock-quoted pool pays its creator in that Stock Token.
  • Read live vaults from the hook: feeEscrow(), buybackVault(). Do not trust a stale deployments file.

Modules

Hook modules

MasterLaunchHook is the shared v4 hook. Every Master pool packs its module choices into one immutable bitmask at launch. Modules are grouped in four categories: Protection → Tokenomics → Rewards → Trading Fees. Deepen LPs sits in Protection (it thickens the book), not Rewards.

Protection

ModuleWhat it does
Anti-SnipeDecay tax on opening buys. High extra buy fee at open, linear decay to 0 over the window you set. Snipers pay the most in the first seconds.
Anti-MEVSame-block opposing swap cooldown. One swap per tx.origin per pool per Robinhood Chain block. Same-block buy → sell or sell → buy reverts. Not a private mempool.
Max TxCaps a single swap at 0.1%–2.5% of total supply. Fixed at launch. Oversized swaps revert. Exact-output sells are rejected.
Backed FloorQuote vault + ratchet redeem price. Every swap can lift the floor, and the floor never moves down. More volume, higher floor.
Deepen LPsA share of hook tax minted back into the launch LP range as extra liquidity. A deeper book for whales and traders.

Tokenomics

ModuleWhat it does
Auto-BurnA share of hook tax buys the token from its own pool and burns it after each swap. A failed nested buy stays queued.
NFT StrategyETH fees sweep the floor of one listed Robinhood Chain collection into a vault with no withdraw. Each NFT is raffled to holders or burned. Up to 90% of its pot can buy back and burn the coin instead.
Buyback VestingThe creator's 60% of the 1% base and any Hook → Creator share of hook tax both vest in BuybackVault, on a timer or until a market-cap target. A fixed 5% tax at 100% Hook → Creator locks 5.6% of volume.

Rewards

ModuleWhat it does
Holder AirdropEvery swap accrues. Hook pot → HolderAirdropVault in quote. Holders of that token get ETH, USDG or Stock Tokens on a time window or FDV target, pro-rata by balance.
Hook → CreatorA share of the hook pot paid to the creator. Alone it is 100%. Split it with burn, floor, Deepen LPs or airdrop so the shares still add to 100%.
Creator → HookRoutes the creator's 60% of the 1% base into the hook pot instead of escrow. Cannot combine with Buyback Vesting.

The $KHOOK holder drop is not a module. It is mandatory on every hooked pool. See $KHOOK.

Trading fees

ModuleWhat it does
Fixed FeesFlat extra hook tax on every swap, quote only, so no token is sold to pay it. Mutually exclusive with Dynamic Fees. You must pick a 100% destination (Hook → Creator, burn, floor, Deepen LPs or airdrop). The wizard will not advance until you do.
Dynamic FeesHook tax ramps with the in-range LP depth a swap consumes. Larger trades pay more. No oracle. You must pick a 100% destination.

Limits

  • Floor + burn + Deepen LPs + airdrop + Hook → Creator shares of the hook pot must equal 100% whenever the pot is funded.
  • Floor, burn, Deepen LPs, airdrop and Hook → Creator need hook tax > 0, unless Creator → Hook feeds the pot.
  • Base 1% + hook tax ≤ 10%.
  • Base 1% + hook tax + initial snipe tax ≤ 100%.
  • Classic does not use these modules.

Launch packing reverts when a rule breaks:

RevertCause
HookTaxTooHighHook tax above 900 bps (9%).
TotalFeeTooHighBase + hook tax above 1,000 bps (10%).
OpenFeeTooHighBase + hook tax + initial snipe tax above 10,000 bps.
SnipeTaxTooHighInitial snipe tax above 9,900 bps.
AntiSnipeWindowTooShort / AntiSnipeWindowTooLongAnti-Snipe on with a window outside 1–3,600 s.
MaxTxTooLow / MaxTxTooHighMax Tx outside 10–250 bps.
FeeRouteIncompleteThe pot is funded and the shares do not sum to 10,000 bps.
FeeRouteTooHighThe shares sum above 10,000 bps.
HookFundingRequiredShares are set but there is no hook tax and Creator → Hook is off.
CreatorShareConflictCreator → Hook and Buyback Vesting together.
BuybackVestingTooShort / BuybackVestingTooLongVest duration outside 7 days–5 years.
HolderAirdropEpochTooShort / HolderAirdropEpochTooLongAirdrop epoch outside 60 s–7 days.
DynamicFeeMinTooLow / DynamicFeeRangeInvalidDynamic min total below 1%, or less than 0.10% under the max total.
NftStrategyExclusiveNFT Strategy combined with another pot sink or Max Tx.

Anti-Snipe

A buy-only extra tax at open. Linear decay to 0 over the window packed at launch. The take uses the same 60 / 10 / 30 split as the 1% base. It is not hook tax.

Anti-SnipeFig. 14

Buys only. After T only the 1% base and the hook tax remain.

Example: 1 ETH buy, 5 s window, 98% open tax.

WhenWhat happens
First second+0.98 ETH snipe on top of the 1% base. The sniper pays ~1.99 ETH in.
After 5 sSnipe is 0. The same 1 ETH buy pays only 0.01 ETH base.
Where the 0.98 goes60% creator · 10% $KHOOK drop · 30% protocol.

Parameters

ParameterValue
Initial taxWizard default 98%. Slider 1%–99%. Contract fallback if unset: 50%. Max 9900 bps.
Window1–3600 seconds, enforced at launch: 0 reverts AntiSnipeWindowTooShort, above 3,600 reverts AntiSnipeWindowTooLong. Wizard default 5 seconds.
CapBase 1% + hook tax + snipe ≤ 100% at open. Steady fee (after decay) still 1% + hook tax ≤ 10%.
Exact-output buysRejected while the snipe tax is above 0 (ExactOutputDuringSnipe). Their fee is taken after the swap, on the quote they spent, and that charge carries no snipe. Exact-input buys pay the snipe on the quote they send. Sells never pay it.
Dev buyThe creator's launch-time dev buy is exempt from the tax.

Formula

τ_snipe(t) = τ0 · (1 − (t − t0) / T)
0 after T. Applied on buys only. 1 s ≤ T ≤ 3,600 s.

t0 is the pool's initialization time, the timestamp of the launch transaction's block.

On Robinhood Chain

Time is the block timestamp, in whole seconds. Robinhood Chain produces about ten blocks per second at the time of writing, so every block inside the same second sees the same tax. The tax steps down once per second, not once per block.

Anti-MEV

A per-origin lock that lasts one Robinhood Chain block. One swap per tx.origin per pool per block. A same-block opposing swap (buy then sell, or sell then buy) reverts SandwichBlocked.

Anti-MEVFig. 15
Block N one swap per origin
origin Abuyallowed; lock (pool, A) = N
origin Asellreverts SandwichBlocked
origin Abuyreverts SandwichBlocked (same direction too)
origin Bsellallowed; B has its own lock
Block N + 1 a new lock
origin Asellallowed; next block, new lock

Blocks are Robinhood Chain L2 blocks (ArbSys.arbBlockNumber). The lock is per pool and per origin.

Example: Alice in one block.

Robinhood Chain blockSwapResult
100Buy 1 ETHAllowed.
100SellReverts SandwichBlocked.
101SellAllowed. Next block, new lock.
  • This is not a private mempool and not a builder-only lane.
  • A same-direction second swap in the same block from the same origin also reverts.
  • It does not stop cross-block sandwiches or other searchers. Two different origins can each swap once in the same block.
  • NFT Strategy launches force Anti-MEV on.

Which block

On Robinhood Chain, an Arbitrum Nitro chain, block.number inside a contract returns an estimate of the L1 block number. It advances in steps, and many Robinhood Chain blocks share one value. A lock keyed on it would hold for the whole L1 step, not one block.

k'hook keys the lock on the Robinhood Chain block number instead:

Solidity
library ChainBlock {
    function number() internal view returns (uint256) {
        if (block.chainid == 4663 || block.chainid == 46630) {
            return IArbSys(address(0x64)).arbBlockNumber();
        }
        return block.number;
    }
}

arbBlockNumber() matches the block numbers the RPC and the explorer show. Robinhood Chain produces a block about every 0.1 s at the time of writing, so the lock clears quickly. It still blocks the classic same-block sandwich from one origin.

Max Tx

Caps a single swap at 0.1%–2.5% of total supply (10–250 bps). Fixed at launch. Oversized swaps revert MaxTxExceeded, checked before the swap (SupplyCapLib.checkMaxTx).

Max TxFig. 16
This swap1.05% of supply
Cap2.50%

Pick the cap at launch, from 0.10% to 2.50% of supply.

Example: 1B supply, 1% max tx = 10M tokens.

SwapResult
Buy 8M tokensGoes through.
Buy 12M tokensReverts. One swap cannot eat more than the cap.

What the cap measures

SwapMeasured as
Buy, exact inputThe quote after fees, converted at the pre-swap spot. Price impact only lowers the real fill, so the check never under-counts.
Buy, exact outputThe tokens requested.
Sell, exact inputThe tokens sold.
Sell, exact outputRejected: MaxTxExactOutput(). Sell exact input instead.
  • 0.1%–2.5% of supply.
  • The cap applies to buys and sells.
  • Exact-output sells revert on Max Tx pools. Their token input depends on price impact and on the fee paid on top of the requested quote, so no pre-swap check is exact. The k'hook app, KhookRouter and BalancedAggregator only send exact-input swaps.
  • The cap is a share of live total supply. Burns shrink it in step.
  • Max Tx cannot combine with NFT Strategy.

Backed Floor

Every swap can lift the floor. Hook-tax quote goes into FloorVault, P_floor = vault ÷ circulating, and it only ratchets up. More volume, higher floor. Single-pair only: launchMulti reverts BackedFloorNotAllowedInMulti.

Hook tax → floor$1M volume$10M volume
2%~$20k floor~$200k floor
5%~$50k floor~$500k floor

The example assumes a ~$5k launch that sends 100% of hook tax to the vault. The starting floor is near zero until the first fees land. Split the pot with burn / Deepen LPs / airdrop and the floor grows slower.

Backed FloorFig. 17

P_floor = vault quote ÷ circulating supply. Redeeming burns tokens and pays quote; holders keep the new floor.

Formulas

P_floor = V_quote / S_circ

Quote wei in the vault over circulating token wei. Scaled 1e18 on-chain as floorPriceX18. S_circ is the token's live total supply, so burns and redemptions lower it.

q = amount · V_quote / S_circ

FloorVault.redeemFloor(token, amount). Burns the tokens, pays quote, rounds down. The remaining holders keep a floor that never decreases.

premium = (P_spot − P_floor) / P_floor

Hidden while the vault is dust versus launch FDV, so a few cents of collateral is not a +30,000,000% badge.

Sells into the floor

While the vault holds collateral, an exact-input sell does not fill below the floor. One that would cross it is split: the market first, the floor for the rest.

Sells into the floorFig. 18

One exact-input sell, filled in two legs.

Spot before the sellWhat happens
Above the floor, the sell does not reach itA normal swap.
Above the floor, the sell would cross itThe pool buys the tokens that take the price down to P_floor, at market. The rest fills at P_floor.
At or below the floorThe whole sell fills at P_floor.
  • The output only grows with the sell size. Crossing the floor never reprices the market part at P_floor.
  • The market leg stops at the launch range's lower edge when the floor sits below it: the pool has no liquidity past the edge.
  • The market leg is sized from the protocol's own liquidity: the launch position plus the Deepen LPs position. Liquidity others add only deepens the book, so the market leg can stop above the floor, never below it. The rest still fills at P_floor.
  • Fees: the floor leg pays 1% + hook tax on its floor quote, in beforeSwap. The market leg pays on its executed quote leg, in afterSwap.
  • Logs: FloorFill(poolId, tokenIn, quoteOut) for the floor leg only, with quoteOut net of the fee, and a normal Swap for the market leg. Each leg logs its own FeesDistributed.
  • Exact-output sells keep hookit's rule: a sell that would cross fills whole at P_floor. The k'hook app and KhookRouter send exact-input sells.

FloorFillExceedsInventory

The floor leg takes its tokens from the PoolManager before the seller's tokens arrive at settlement. It cannot exceed the launched tokens the PoolManager holds at that moment, and reverts FloorFillExceedsInventory() when it would. Split the sell: a fill does not use up that inventory, so each smaller sell goes through. With the market leg first, only a sell larger than the pool's whole token inventory, with spot already at or below the floor, can hit this.

Behaviour

  • The floor is not pegged to the DEX. Spot can sit far above the vault.
  • Empty vault: no floor fills, and redeem reverts until fees refill it.
  • Every deposit, draw and redeem checks that P_floor did not decrease (FloorWouldDecrease).
  • The floor is paid in the pool's quote. A Stock-quoted floor pays in that Stock Token.

Read it with FloorVault.floorPriceX18(token) and FloorVault.reserve(token). The vault address comes from MasterLaunchHook.floorVault().

Deepen LPs

A share of the hook pot is minted back into the launch LP range as extra liquidity. Protection category: it thickens the book, it does not pay holders.

Deepen LPsFig. 19
At launchthin
After volumedeeper, larger

Same trade size, less price movement after deepening.

Example: 2% hook tax, 100% to Deepen LPs.

VolumeDepth added
1 ETH buy0.02 ETH minted into the LP after the swap.
50 such buys+1 ETH of depth in the launch range.
100 such buys+2 ETH. The same size walk moves price less.

Hook-tax quote is minted back into the same launch ticks. Not paid to holders.

  • Hook tax is queued to pendingDeepenLps[poolId] and minted in afterSwap.
  • In range, the quote is split into both assets at the current price, then minted. Out of range, it is minted single-sided.
  • The split buys tokens first, and that buy moves the price, so a mint rarely uses both sides exactly. Nothing it cannot use is lost: leftover quote stays queued in pendingDeepenLps[poolId], and leftover launched tokens are carried in pendingDeepenTokens[poolId]. The next mint folds the carried tokens in, valued at spot.
  • A mint spends only its own budget: the queued quote, the carried tokens and what it bought. In range it never mints one side alone. Otherwise it reverts DeepenFailed and nothing moves.
  • If the nested mint fails, the quote and the carried tokens are both re-queued. Funds are not lost.
  • The deepened liquidity is the hook's own position in the launch range. beforeRemoveLiquidity blocks its removal, like the launch position (LaunchPositionLocked). Liquidity anyone else adds in that range stays theirs to remove.
  • LpDeepened(poolId, quoteAmount) carries the quote each mint consumed. Σ LpDeepened + pendingDeepenLps is the whole budget. The token page shows both. Read the carried tokens with MasterLaunchHook.pendingDeepenTokens(poolId).
  • The share of the hook pot must sum to 100% with floor / burn / airdrop / Hook → Creator when the pot is funded.

Auto-Burn

A share of the hook pot buys the launched token from its own pool after the swap and burns it. LaunchToken.burn removes the tokens from total supply.

Auto-BurnFig. 20
At launch1,000,000,000
After burnslower

Hook tax bought these tokens and burned them.

Example: 2% hook tax, 80% to Auto-Burn.

VolumeBurned
1 ETH buy0.016 ETH buys the token and burns it.
$100k volume~$1.6k of token bought and burned.
$1M volume~$16k burned. Circulating supply is lower. FDV math uses what's left.

Hook tax buys the meme from its own pool and burns it. Not the $KHOOK buyback.

  • Queued as pendingAutoBurn[poolId], executed in afterSwap.
  • A failed nested buy re-queues the same amount. A partial fill keeps the unspent quote queued.
  • The hook emits AutoBurn(poolId, quoteIn, tokenBurned).
  • This is not the protocol $KHOOK buyback and not Buyback Vesting.

NFT Strategy

Trading fees sweep the floor of one listed Robinhood Chain collection. The NFTs land in a vault with no withdraw function. At launch the creator picks what happens to every NFT the fees buy: it is raffled to one holder of the token, or it is burned. The creator can also send up to 90% of the pot to Auto-Burn: that share buys the token back on its own pool and burns it. The token still trades against ETH.

NFT StrategyFig. 21
Hook potswap → hook tax → pot
0–90%Burn sharebuys the coin, burns it in the swap
NFT sharecredited to NFT Strategy
harvest(token)SweepVault for the collection (no withdraw)keeper sweepcheapest Seaport listings at or under the capevery NFTraffled to holders, or burned to 0x…dEaD

Example: 1 ETH of hook fees, floor at 0.035 ETH.

StepWhat happens
HarvestThe 1 ETH moves into the collection's vault, credited to this token.
CapThe keeper posts ~0.037 ETH (floor + 5%). A sweep never pays more than that per NFT bought.
SweepThe cheapest listings under the cap: about 28 NFTs for 1 ETH.
RaffleEach NFT is drawn among holders. Hold 1% of the tickets, get a 1% chance per draw.
BurnEach NFT goes to the dead address 0x000…dEaD. The collection's circulating supply shrinks by 28.

One listed Robinhood Chain collection. ETH only. The vault has no withdraw and never pays above the floor cap per NFT bought.

From launch to NFT

#StageWhat happens
01LaunchThe creator picks a collection and raffle or burn. Both are final. ETH pair, Anti-MEV on. LaunchFactory.launchWithNftStrategy(params, collection).
02TradeEvery swap pays the hook tax. The Auto-Burn share buys the coin and burns it in that same swap. The NFT share is credited to NFT Strategy.
03HarvestAnyone calls harvest(token). The NFT share moves into the collection's vault.
04SweepThe keeper buys the cheapest Seaport listing, never above the floor cap. The NFT lands in the vault.

The vault has no withdraw. ETH only leaves it to buy NFTs at the floor.

Two exits for every NFT

Picked at launch.

ExitWhat happens
Raffle to holdersDrawn among the token's holders. It goes from the vault straight to the winner's wallet.
Burn the NFTAnyone calls burn(). The NFT goes to the dead address. Gone for good.

Dead address: 0x000000000000000000000000000000000000dEaD. Nobody holds its key.

Vault rules

RuleWhat it means
No withdrawETH only leaves the vault through a sweep. NFTs only leave through a burn to the dead address or a raffle claim.
Keeper-only sweepOnly a keeper can spend. It cannot pick a target: only an allowlisted Seaport is callable. The registry owner appoints the keepers, and can appoint itself.
Floor capSpend ≤ floorCap × NFTs bought. The keeper posts the cap from the collection floor, its lowest live Seaport listing. The cap expires after 1 hour. The deploy also gives every collection it lists an owner ceiling on the cap: 1 ETH per NFT unless the listing sets another. The owner can raise or remove it.
Outcome isolationRaffle credit only buys raffle NFTs and burn credit only buys burn NFTs. One token cannot spend another's ETH.
AttributionEach sweep is paid by one token's credit, and every NFT it buys belongs to that token: raffled to its holders or burned. No other token's credit ever pays for it.
No donationsThe vault rejects plain ETH except the Seaport refund. NFTs sent to it by hand are not tracked.
Auto-Burn share0 to 90%, final at launch. That share buys the token and burns it in the same swap, after the trader's trade. A failed buy waits for the next swap. The NFT share stays in the vault for the keeper.

How a raffle runs

One NFT, one draw.

#StageWhat happens
01SnapshotHolders of the token. One whole token = one ticket. Pools and contracts are left out. The keeper publishes the list and its Merkle root, and proves the root's last range ends at the ticket total.
02Challenge15 minutes for anyone to check the published list against its Merkle root.
03DrawThe keeper calls requestDraw. The hash of the block 5 blocks later picks the winning ticket. Anyone can call finalizeDraw to lock it in, and the keeper does it right away.
04ClaimThe keeper claims the NFT for the winner right after the draw. The winner, or anyone, can also submit the claim. The NFT always goes to the winner's wallet.

More tokens, more tickets: P(win) = your tickets / total tickets.

The draw on Robinhood Chain

  • Blocks are Robinhood Chain blocks. requestDraw records ArbSys.arbBlockNumber() and the draw reads the hash of the block 5 later with ArbSys.arbBlockHash(n). At about 0.1 s per block, that block lands roughly half a second later.
  • PREVRANDAO is constant (1) on Robinhood Chain and is never used.
  • arbBlockHash only returns the last 256 block hashes, about 25 s at current block times. The draw has to be settled inside that window.
  • The sequencer produces Robinhood Chain blocks. The draw is a block-hash draw, not a VRF: Chainlink VRF is not available on Robinhood Chain. Fairness trusts the keeper and the sequencer.
  • Only the keeper can request a draw, or request it again after the 256-block window lapsed. Anyone can finalize a request inside the window, and that fixes the result.
  • If a drawn ticket cannot be claimed (a bad snapshot), the registry owner can reset the draw 3 days later. The keeper then publishes a corrected snapshot and the NFT is drawn again.

Checks

sweep:  spent ≤ floorCap × bought

Checked by the vault on its own balance before and after the call. Also spent ≤ the funding token's credit for that outcome.

split:  vault = pot × (100% − burn share)
        burn  = pot × burn share

The burn runs in the swap, like Auto-Burn, and does not pay the hook tax again. The vault share is what harvest later sweeps.

odds:   P(win) = your tickets / total tickets

Tickets are whole tokens held at the snapshot.

Contracts

ContractJob
NftSweeperRegistryRegistry and fee router. Lists collections, deploys one SweepVault per collection, registers launches and harvests fees.
SweepVaultOne per collection. Holds the ETH and the NFTs, enforces the rules above.
NftSweepRaffleMerkle snapshot, challenge window, block-hash draw and claim. The only address allowed to release raffle NFTs.

Listed collections live in NftSweeperRegistry (—) and show in the launch wizard. Sweeps go through Seaport 1.6 (0x0000000000000068F116a894984e2DB1123eB395).

Launch rules

  • ETH quote only (NftStrategyEthOnly). Anti-MEV is forced on.
  • The strategy takes the whole hook pot. No bitmask pot sink (Backed Floor, the Auto-Burn module, Deepen LPs, Holder Airdrop, Hook → Creator) and no Max Tx (NftStrategyExclusive). The 0–90% burn share is set on NFT Strategy itself.
  • The pot must be funded: a hook tax, or Creator → Hook.

Buyback Vesting

Buyback Vesting locks two streams in BuybackVault, not FeeEscrow: the creator's 60% of the 1% base, and the Hook → Creator share of hook tax. A 5% fixed tax with 100% Hook → Creator therefore vests 5% of every swap plus the 0.6% creator cut (5.6% of volume). Unlock is a clock (7 days–5 years, set in the module bitmask) or a USD FDV target packed in vestPacked (low 128 bits), not in the module bitmask.

Buyback VestingFig. 22

Example: 1 ETH buy, 5% hook tax, 100% Hook → Creator.

SliceWhat happens
Base 1%0.006 ETH creator cut vests. 0.001 $KHOOK drop + 0.003 protocol stay unlocked.
Hook tax 5%0.050 ETH vests in the same BuybackVault. Not FeeEscrow.
Total locked0.056 ETH = 5.6% of the buy. The trader receives 0.94 ETH worth of tokens.
$100k volume$5,600 locked ($5,000 tax + $600 creator cut).
30-day vest, day 15Half claimable. Linear. A dump later does not relock it.
Until $10M FDV$0 until mcap holds $10M for 1 hour, then the full bag.

Hook tax needs Hook → Creator as a destination. Cannot combine with Creator → Hook. The 10% $KHOOK drop stays mandatory.

Unlock modes

ModeRule
Time vestLinear unlock from 7 days to 5 years. Claim the unlocked slice on the token page. A duration of 0 means 5 years.
Until FDVCliff presets start at $10M (not $5M): $10M, $50M, $100M, $500M, $1B, $10B. All at the cliff, or by % at each rung (percents must sum to 100). A level counts once FDV has held it for 1 hour.
HoldobserveFdv on each swap feeds a 1-hour window. When the window closes, its lowest FDV is confirmed. A spike that does not last the hour unlocks nothing.
RatchetThe confirmed FDV only rises. A dump after the unlock does not relock fees already freed.
  • Cannot combine with Creator → Hook. Both spend the same 60% creator cut of the 1% base.
  • Hook tax is in scope. Turn on Fixed or Dynamic Fees and pick Hook → Creator as a destination (100%, or a share next to burn / floor / Deepen LPs / airdrop). That slice vests. This module is not a leftover sink. Fees still need an explicit destination.
  • Example: 5% hook tax, 100% Hook → Creator → 5% of volume + 0.6% creator cut = 5.6% of volume into BuybackVault. Protocol 0.3% and the 0.1% $KHOOK drop stay live and unlocked.
  • The 10% $KHOOK drop is mandatory and unchanged. The 30% protocol cut is unchanged.
  • Buyers can see the vest on the token page. An instant creator dump of trading fees is off the table.
  • The token page shows quote accrued into BuybackVault, still pending / claimable, and the until-FDV cliff or the first / next by-% rung.

The 1-hour hold

An FDV target unlocks only once the FDV has held it for 1 hour (FDV_HOLD_SECONDS). One spot print is not enough.

The 1-hour holdFig. 23

The next swap after the window confirms $12M: unlocked.

  • The first swap opens a window. Each swap lowers the window's minimum to its own FDV.
  • The first swap 1 hour or more after the window opened confirms that minimum, its own print included. The next window opens at that swap.
  • A flash pump and dump in one transaction is two prints in the same window, so the dump sets its minimum.
  • A dip below the target during the window means that window confirms the dip. The target then needs a full clean window.
  • A new level counts from the first window that opens at or above it. In an active pool the unlock comes 1 to 2 hours after the FDV first reaches the target.
  • In a quiet pool, the next swap confirms the whole quiet stretch: the price cannot move without a swap.
  • Read the state with confirmedFdvUsd(token) (unlock basis, also highWaterFdvUsd), fdvWindowStart(token) and fdvWindowMinUsd(token). FdvObserved is emitted when the confirmed FDV rises.

FDV observations on Robinhood Chain

The hook observes FDV after every swap: pool spot × live total supply × the quote's USD price from LaunchFactory.quoteUsdPriceX18. ETH uses Chainlink ETH/USD. A Stock Token uses its Chainlink feed, with the fallbacks in Why Stock Tokens. If no price can be read, the swap still goes through and counts as an FDV of $0: the price could have moved unseen, so its window confirms nothing.

Name

"Buyback" here means the creator's proceeds sit in BuybackVault, not that the hook market-buys $KHOOK for the creator.

The protocol $KHOOK buyback is a separate 80% of the protocol pot (KhookBuyback.execute, then burn).

Claim with BuybackVault.claim(token). Read the claimable amount with vestedOf(account, token).

Holder Airdrop

A launch-time share of the hook pot accrues in HolderAirdropVault as quote: ETH, USDG, or a Stock Token. Holders of that launched token get paid, not $KHOOK holders. That other flow is the mandatory $KHOOK drop, in the $KHOOK section.

Holder AirdropFig. 24
hook pot shareHolderAirdropVaultpot 0.01 ETH
epoch ends, next swappushes up to 48 holders
2%you2% of the pot
2%B2% of the pot
1%C1% of the pot
…

Quote is split to holders of that token, pro rata.

Example: 2% hook tax, 50% to airdrop, you hold 2% of supply.

VolumePayout
1 ETH buy0.01 ETH into the vault this swap.
Your payout2% × 0.01 = 0.0002 ETH when the epoch pushes.
$100k volume~$20 to you in quote. Not $KHOOK: the launched token's holders.

Optional module. Not the mandatory $KHOOK drop. You receive ETH / USDG / Stock Tokens, not the meme.

Rules

RuleValue
Time windowDefault epoch 15 minutes. Min 60 seconds, max 7 days. The next swap after the epoch can push a batch (tryAutoAirdrop).
Until FDVKeep drops locked until FDV has held $5M–$10B for 1 hour. The airdrop may use the $5M preset; the buyback vest starts at $10M. Unlock all at the cliff, or by % at each rung (must sum to 100). Packed in vestPacked high 128 bits.
HoldSame rule as Buyback Vesting: each swap feeds a 1-hour window, and a closing window confirms its lowest FDV. A spike that does not last the hour releases nothing. The confirmed FDV only rises, so a later dump never relocks. Read confirmedFdvUsd(token), fdvWindowStart(token) and fdvWindowMinUsd(token) on HolderAirdropVault.
Holder setOn-chain. LaunchToken.holderTracker = HolderAirdropVault; every transfer calls syncHolder. Not supplied by the indexer.
PayoutUniswap v4 ERC-6909 quote claims via claimsManager.transfer. Holders redeem with PoolManager.setOperator(redeemer, true) then V4ClaimsRedeemer.claim(quote).
  • Needs hook tax > 0 (or Creator → Hook feeding the pot) so there is something to accrue.
  • The share of the hook pot must sum to 100% with floor / burn / Deepen LPs / Hook → Creator when the pot is funded.
  • Permissionless. Anyone can trigger the push once the epoch is ready.
  • The token page reads released (already airdropped) and potOf (still pending), plus the until-FDV cliff or the first / next by-% rung.
  • Max 48 holders per batch so a swap stays inside the gas envelope.
  • A payout larger than one batch runs over several calls. A holder who sells out or is excluded meanwhile keeps its list slot at a zero balance until the payout finishes: nobody behind the payout cursor is skipped, and the leaver gets nothing more that epoch. The next tryAutoAirdrop with no payout running compacts those slots, up to 48 per call. deferredRemovalCount(token) counts them, and holderList / holderCount include them until then. A holder who buys back in first keeps the slot.
  • Pool, hook and vault addresses are excluded: PoolManager, MasterLaunchHook, LaunchFactory, FloorVault, HolderAirdropVault, FeeEscrow, BuybackVault, KhookDropVault and the zero address. The manual airdrop(token, holders) path must cover circulating supply or it reverts.
  • Each payout (one per quote of the token) is paid on the balances tracked when that payout started: a holder gets pot × min(balance then, balance now) / (total then). Tokens moved between batches are not paid twice, and a multi-market token's payouts never share a snapshot, so parking tokens while another quote's payout starts only lowers what that payout pays you.
  • Multi-pair launches keep one pot per quote.
payout_i = pot · bal_i / Σ bal

The quote pot for this epoch × the wallet's balance of the launched token over circulating supply (exclusions applied).

Redeem your claims

TypeScript
import { parseAbi } from "viem";

// wallet: a viem WalletClient on Robinhood Chain (4663)
// once per wallet: let the redeemer move your ERC-6909 claims
await wallet.writeContract({
  address: "0x8366a39CC670B4001A1121B8F6A443A643e40951", // PoolManager
  abi: parseAbi(["function setOperator(address operator, bool approved) returns (bool)"]),
  functionName: "setOperator",
  args: ["—", true],
});

// then per quote: address(0) for ETH, or the USDG / Stock Token address
await wallet.writeContract({
  address: "—",
  abi: parseAbi(["function claim(address currency) returns (uint256)"]),
  functionName: "claim",
  args: [quote],
});

V4ClaimsRedeemer.claimable(account, quote) shows what you can redeem.

Hook → Creator

Send a share of the hook pot to the creator. If this is the only destination, it is 100%. Pair it with Deepen LPs, Backed Floor or Holder Airdrop and the shares still add to 100%. Fixed or Dynamic Fees with no destination cannot launch.

Hook → CreatorFig. 25
1 ETH buy · 2% hook taxhook pot 0.020 ETH
50%Deepen LPs0.010 ETH minted into the launch range
50%→ Creator0.010 ETH to FeeEscrowBuybackVault if vesting is on

Example: 1 ETH buy, 2% hook tax.

SplitResult
Hook → Creator 100%0.020 ETH tax to creator escrow, plus 0.006 ETH from the 1% base.
Deepen LPs 50% + Creator 50%0.010 ETH minted into the launch range and 0.010 ETH to the creator.

Alone it is 100%. Split with Deepen LPs, floor or airdrop so shares still add to 100%.

  • Alone: 100% of the hook pot is credited to the creator and is claimable in FeeEscrow.
  • Deepen LPs 50% + Hook → Creator 50%: they split the pot.
  • If Buyback Vesting is on, this slice goes to BuybackVault instead of FeeEscrow.
  • The wizard will not advance until destinations sum to 100%.
  • Shares with floor / burn / Deepen LPs / airdrop must equal 100% whenever the pot is funded.

Creator → Hook

Routes the creator's 60% of the 1% base into the hook pot instead of FeeEscrow. Same module split as hook tax (Hook → Creator / floor / burn / deepen / airdrop).

Creator → HookFig. 26
1% base
60%Creatorhook potBacked FloorAuto-BurnDeepen LPsHolder AirdropHook → Creator
10%$KHOOKuntouched
30%Protocoluntouched

Example: 1 ETH buy, no hook tax, Creator → Hook on.

VolumeResult
Base 1%0.006 ETH to Hook → Creator / floor / burn / deepen / airdrop instead of escrow.
$100k volume$600 extra in the pot. The creator claims $0.

Nothing to claim as creator fees. The $KHOOK 10% is untouched.

  • Cannot combine with Buyback Vesting.
  • The 1% base is unchanged. Only the creator slice is redirected.
  • A fee sink can run with hook tax = 0 if this module feeds the pot.
  • The $KHOOK pool itself runs Creator → Hook. See $KHOOK.

Fixed Fees

A flat extra hook tax on every swap, quote only. Mutually exclusive with Dynamic Fees. You must pick a 100% destination (Hook → Creator, burn, floor, Deepen LPs or airdrop). The wizard will not advance until you do.

Fixed FeesFig. 27
Base 1%→ 60 / 10 / 30
Hook tax 2%→ hook pot → 100% destination
Total 3%3%

A flat extra hook tax on every swap, quote only. 1 ETH in, 0.97 ETH of tokens out.

Example: 2% fixed hook tax.

VolumeResult
1 ETH buyPays 1 ETH. Receives 0.97 ETH worth of tokens (0.01 base + 0.02 hook tax).
Sell for 1 ETHThe pool pays 1 ETH for the tokens. The seller receives 0.97 ETH. Same 3%, on the quote out.
10 × 1 ETH buys0.10 ETH base (60/10/30) + 0.20 ETH into the hook pot.
$1M volume$10k base + $20k hook tax. The tax needs a 100% destination (Hook → Creator, burn, floor, Deepen LPs or airdrop).

Mutually exclusive with Dynamic Fees. 1% + tax ≤ 10%.

  • You set the hook tax at launch. Base 1% + hook tax ≤ 10%.
  • Hook tax never uses the 60 / 10 / 30 split. That split is only the 1% base (and snipe).
  • Hook → Creator alone: 100% of the tax is credited to the creator and is claimable.
  • Hook → Creator plus Buyback Vesting: that slice vests in BuybackVault.
  • No destination: launch packing reverts. The wizard blocks Continue.
  • The tax is bitmask bits 7–22, hookTaxBps, 0–900.

Dynamic Fees

The extra hook tax is not a flat bps. It scales with how much of the in-range book the swap eats. A small clip on a deep book stays cheap. The same clip on a thin book pays more. No oracle, no 24h volume window, only current Uniswap v4 liquidity in the launch ticks. You must pick a 100% destination. Hook → Creator alone credits the ramped tax to the creator. With Buyback Vesting, that slice vests.

Dynamic FeesFig. 28

c / σ is the trade's share of the in-range book.

Example: 10 ETH in-range depth, extra tax 1% → 9%.

TradeResult
Retail 0.2 ETHUses 2% of the book. Extra ≈ 1.16%. Pays ~0.002 ETH hook tax + 0.002 ETH base.
Whale 5 ETHUses 50% of the book. Extra = 5%. Pays 0.25 ETH hook tax + 0.05 ETH base.
Clip the whole bookExtra = 9%. A 10 ETH buy pays 0.90 ETH hook tax + 0.10 ETH base.

No oracle. An empty book stays at τ_min so the first buy does not revert.

Formula

c      = n / d
r      = min(1, c / σ)
τ_hook = τ_min + (τ_max − τ_min) · r
SymbolMeaning
nQuote notional of this swap: the quote you send on a buy, the quote the pool pays out on a sell.
dIn-range quote depth in the trade direction, read before the swap.
σThe depth-saturation fraction set at launch (default 100% of in-range depth).
τ_hookAdded on top of the 1% base. Empty depth stays at τ_min so a first buy does not 100% revert.
  • You set a min total fee and a max hook tax at launch. Base 1% + max hook tax ≤ 10%.
  • The min total fee is at least 1% and sits at least 0.10% below the max total fee.
  • Cannot combine with Fixed Fees. One extra-tax mode per pool.
  • The 1% base still splits 60 / 10 / 30. Only the hook-tax slice ramps.
  • Hook → Creator alone: the ramped tax is credited to the creator and is claimable.
  • Hook → Creator plus Buyback Vesting: that slice vests in BuybackVault.
  • No destination: launch packing reverts. The wizard blocks Continue.
  • Preview a size with MasterLaunchHook.dynamicFeeForSwap(poolId, quoteNotional, isBuy). It returns the hook tax in bps. For a sell, pass the quote the pool will pay out, before the swap.
  • A sell's tax is set after the fill: the hook ramps on the quote that executed, against the depth the pool had before the swap. See Fees.

Whale-sized flow pays for the depth it consumes. Retail on a healthy book stays near the floor fee.

Formulas

The identities the contracts enforce. BPS_DENOMINATOR = 10_000. Amounts are integer wei.

FormulasFig. 29
swap feedynamic τUniswap spotFDV unlockClassic curve$KHOOK dropprotocol potchain inputs

Swap fee

fee_total  = 1% + τ_hook + τ_snipe
fee        = fee_total · q

Capped so 1% + τ_hook ≤ 10%. Snipe is buy-only and temporary. q is the quote the trader fixes (exact-input buy, exact-output sell), taken in beforeSwap, or the quote leg that executed (exact-input sell, exact-output buy), taken in afterSwap.

τ_snipe(t) = τ0 · (1 − (t − t0) / T)

0 after the launch window T. Linear decay from the initial tax τ0.

base split = 0.60 creator + 0.10 $KHOOK + 0.30 protocol

Mandatory. Applied to the 1% base and to the snipe take. Hook tax never uses this split.

Dynamic hook tax

c      = n / d

Quote notional of the swap over in-range quote depth in the trade direction. n is q from the swap fee. d is read before the swap.

r      = min(1, c / σ)

σ is the depth-saturation fraction set at launch (default 100% of in-range depth).

τ_hook = τ_min + (τ_max − τ_min) · r

No oracle. Empty depth stays at τ_min so a first buy does not 100% revert.

Uniswap spot

P   = (sqrtPriceX96 / 2^96)^2

Quote per token if the launch token is currency0. Invert if it is currency1.

FDV = P · 10^9 · FX

FX is Chainlink ETH/USD for ETH pools, the Stock Token's Chainlink USD feed for Stock pools, or USDG/USD (USDG ≈ $1) for USDG pools.

FDV unlock

W_min    = min FDV over every swap since W_start      (a swap with no price counts as 0)
confirm  : first swap with now − W_start ≥ 1 h
           FDV_conf = max(FDV_conf, W_min), then W_start = now, W_min = FDV now

An FDV target (Buyback Vesting, Holder Airdrop) counts only once the FDV has held it for a full hour (FDV_HOLD_SECONDS). FDV_conf never falls.

cliff    : unlocked = 100% if FDV_conf ≥ X, else 0
by %     : unlocked = Σ pct_i over the rungs with FDV_conf ≥ X_i

Classic curve

k        = Q_virt · T_virt

Virtual constant-product. The opening reserves are sized so the curve sells exactly its 80% at the graduation target and the pool opens at the last curve price:

Q_virt0  = G · S_lp / (S_curve − S_lp)      = 4.2 · 0.2B / 0.6B = 1.4 ETH-eq
T_virt0  = S_curve + Q_virt0 · S_curve / G

G is the graduation target (4.2 ETH-eq), S_curve = 800M, S_lp = 200M (BondingMath.virtualReserves).

buy      : ΔT = T − ⌈k / (Q + ΔQ)⌉
sell     : ΔQ = Q − ⌈k / (T + ΔT)⌉

Tokens out for quote in, and quote out for tokens in, before the 1% fee. The new reserve rounds up, in the curve's favour: k never decreases and a round trip never extracts value.

graduate : Q_real ≥ 4.2 ETH-eq

Or the same USD value in USDG / a Stock Token, fixed at launch. 20% of supply seeds full-range LP.

$KHOOK holder drop

buy     = V · 1% · 10%

Mandatory. Quote volume × base fee × holder share. Buys the launched token, not $KHOOK.

share_i = bal_i($KHOOK) / Σ bal($KHOOK)

Live balances. LP and protocol sinks are excluded from the weight.

Protocol pot

ops     = 0.20 · protocol

Operating wallet.

buyback = 0.80 · protocol

ETH stays ETH. Stock Tokens convert to USDG on their canonical Stock/USDG pool (operator-only). USDG goes to KhookBuyback, which swaps it to ETH (executeUsdg) before it buys and burns $KHOOK.

Chain inputs (Robinhood Chain)

block_n  = ArbSys(0x64).arbBlockNumber()

The per-block counter for Anti-MEV. block.number is an L1 estimate on this chain.

ETH/USD  : Chainlink, age ≤ 25 h; else snapshot, round age ≤ 24 h
Stock/USD: Chainlink, age ≤ 5 d and oraclePaused() ≠ true;
           else bridge spot within ±20% of snapshot;
           else snapshot, age ≤ 5 d; else StalePrice()

USD prices size launches, graduation targets and FDV unlocks. They never fill a trade.

Tokenomics

$KHOOK

$KHOOK is the protocol token. Hold it and you are exposed to every token that trades on k'hook. Not as a promise: as a mandatory on-chain split of the 1% base fee.

The $KHOOK pool

$KHOOK is itself a Uniswap v4 hooked token on k'hook: —, Master launchId —, paired with ETH. MasterLaunchHook runs Anti-MEV, Anti-Snipe (60s), Creator → Hook, Auto-Burn and Deepen LPs. Creator → Hook sends the 60% creator cut of the 1% into the hook pot. The hook pot is 80% Auto-Burn and 20% Deepen LPs, so fees taken on $KHOOK swaps burn $KHOOK too. Separately, 80% of protocol fees from every launch buy $KHOOK and burn it.

The $KHOOK poolFig. 30
Anti-MEVone swap per origin per block
Anti-Snipeopen-window tax, 60 s
Creator → Hookthe 60% creator cut into the pot
Auto-Burn80% of the pot buys $KHOOK and burns it
Deepen LPs20% of the pot deepens the book

Anti-MEV and Anti-Snipe (60s) guard the book. Creator → Hook plus Auto-Burn 80% and Deepen LPs 20% spend the pot into this token. The protocol buyback from every other launch burns $KHOOK too.

The $KHOOK pool packs no hook tax, so its pot is the 0.60% creator cut: 0.48% of $KHOOK volume buys and burns $KHOOK, and 0.12% deepens its book.

The thesis

Hold $KHOOK, collect all tokens.

The protocol token of the launchpad should receive every token the launchpad launches, without exception. This is not airdropped supply to pad bags or dodge dumps. Fees and volume fund it. More volume, more dollars routed to $KHOOK holders.

Every Master and graduated Classic swap pays a 1% quote fee. 10% of that 1% (0.10% of the trade) is mandatory: not a module, not a toggle, not a special case. It buys the launched memecoin, the ticker on that pool, and KhookDropVault epoch-pushes those tokens to live $KHOOK holders, pro-rata.

The thesisFig. 31
1Hold $KHOOKlive balance, pro rata, not a snapshot
2Any swapMaster or graduated Classic, 1% fee
3Buy that tickerKhookDropVault spends quote on the pool
4Epoch pushyou receive the other tokens, not more $KHOOK

It loops on every launch that prints volume.

LP and protocol sinks are excluded so they do not eat the drop. More $KHOOK, larger slice.

  • You do not receive $KHOOK from this flow. You receive the other tokens. The one exception is the $KHOOK pool's own 10%, which buys $KHOOK.
  • Hold 1 $KHOOK and you get a slice of every launch that prints volume.
  • Hold more $KHOOK and your slice of every drop is larger.
  • Weights are live balances, not a launch-day snapshot.
  • LP, factory and protocol sinks are excluded so they do not eat the drop.

Token

FieldValue
Ticker$KHOOK
StatusLive on Robinhood Chain
NetworkRobinhood Chain
Chain ID4663
Supply1,000,000,000
Decimals18
StandardUniswap v4 hooked Master
Token contract—
Master launchId—
PoolUniswap v4 · MasterLaunchHook · paired with ETH
ModulesAnti-MEV, Anti-Snipe 60s, Creator → Hook, Auto-Burn 80%, Deepen LPs 20%

Tokenomics

ItemDetail
RoleThe launchpad's own hooked token, launched on the Master rail like every other token. Modules: Anti-MEV, Anti-Snipe 60s, Creator → Hook, Auto-Burn 80%, Deepen LPs 20%. Fees taken on the $KHOOK pool burn $KHOOK.
Holder cutMandatory. 10% of every 1% base fee, on every hooked pool. Not a module. Not optional. You cannot launch without it.
Buyback80% of the protocol's 30% (24 bps of volume) routes to native-token buyback. ETH stays ETH. Stock Tokens → USDG on their canonical Stock/USDG pool first.
PayoutBatched each epoch (default 15 minutes, 48 holders per push). Never paid inside the swap itself.
drop    = V · 1% · 10%

Quote volume of a pool × base fee × holder share. Spent on that pool's token.

share_i = bal_i($KHOOK) / Σ bal($KHOOK)

After exclusions. The same weight applies to every launch token in the vault.

Not the Holder Airdrop module

$KHOOK drop (mandatory)Holder Airdrop (optional module)
Who gets paidLive $KHOOK holdersHolders of that launched token
What they getThe launched tokenQuote (ETH / USDG / Stock Token)
Funded by10% of the 1% baseA % of the hook-tax pot
ToggleNone, baked into the 1% basePacked at launch

How the drop actually runs

  • The hook credits KhookDropVault on each swap: 0.10% of quote, spent on that pool's token. The buy runs in afterSwap. A failed buy stays queued in pendingKhookDrop[poolId].
  • On a Classic curve the 10% buys the token on the curve in the same trade. After graduation it accrues in GraduatedFeeHook.pendingKhookDrop, and the keeper's sweepKhookDrop buys the token and credits the vault.
  • tryPush runs on a later swap once the epoch is ready. Max 48 $KHOOK holders per batch.
  • $KHOOK does not auto-list holders on transfer. A keeper syncs balances from Transfer logs / the indexer, then calls syncHolders + tryPush. Both are permissionless.
  • Each drop (one per launched token) is paid on the $KHOOK balances synced when that drop started: pot × min(synced balance then, balance now) / (total then). Drops of different tokens never share a snapshot, and a drop left half-done never affects another token's drops.
  • A drop larger than one batch runs over several calls. A holder who sells out or is excluded meanwhile keeps its list slot at a zero balance until every drop in flight finishes: nobody behind the cursor is skipped, and the leaver gets nothing more from those drops. The next tryPush with no drop in flight compacts those slots, up to 48 per call. KhookDropVault.deferredRemovalCount() counts them.
  • LP, factory, vault and protocol sinks are excluded so they do not eat the drop.
  • The protocol 80% buyback is separate: ProtocolRevenueDistributor → KhookBuyback.execute, which buys $KHOOK and burns it. Not inside the swap. execute is keeper-run, because the caller sets the minimum output.
  • USDG revenue reaches KhookBuyback as USDG. KhookBuyback.executeUsdg swaps it to ETH through FeeEthRail, then runs the same buy and burn. Operator-only, like execute: the caller sets both minimum outputs.
  • If no drop vault is set on the hook, the 10% goes to protocol instead.

Mandatory

The 10% $KHOOK slice is not optional and not a launch setting. Every hooked swap pays it.

Risk

  • Most launched tokens go to zero. A bag of airdropped memecoins can be worth nothing.
  • A thin $KHOOK float, or excluded sinks changing later, will change your share.
  • If the holder-sync keeper lags, the on-chain weight list can be stale until the next sync.
  • This is not a yield promise and not financial advice.

Reference

Integration

Everything on the site can be rebuilt from public chain data. The indexer is a convenience layer and can lag. Prefer the same-origin /api/indexer proxy on the k'hook site so CORS stays on the server.

Same-origin routeServes
/api/indexer/healthHead, lag, last poll error
/api/indexer/v1/tokensCatalog + markets[] + 24h windows
/api/indexer/v1/tokens/:address/trades · /candlesTrades and candles. Candles are 5m by default, 1m available

Indexer HTTP

HTTP
GET /health
GET /v1/protocol/stats
GET /v1/protocol/series?days=30
GET /v1/tokens?sort=top|trend|bonding|new&filter=all|master|classic|stocks|multi&limit=&offset=&q=&creator=
GET /v1/tokens/:address?poolId=
GET /v1/tokens/:address/trades?limit=50&offset=0&poolId=
GET /v1/tokens/:address/holders?limit=50&offset=0
GET /v1/tokens/:address/candles?limit=200&poolId=&interval=1m|5m|10m|15m|1h
GET /v1/feed?limit=50
GET /v1/wallets/:address/holdings?limit=100
GET /v1/nft/collections
RouteReturns
/health{ head, lagBlocks, lastPollError }
/v1/protocol/stats{ launches, volumeUsd24h, volumeUsdAll, feesUsdAll, khookDropUsdAll, khookBurned, floorTvlUsd, tokens24h }
/v1/protocol/seriesOne point per rolling 24 h window, oldest first: volume, fees, trades, launches, $KHOOK drops.
/v1/tokensPaged TokenSummary list. sort: top, trend, bonding, new. filter: all, master, classic, stocks, multi. q searches name, ticker or address. creator filters by creator.
/v1/tokens/:addressOne TokenSummary, scoped to poolId for multi-pair.
/v1/tokens/:address/tradesTrades, newest first.
/v1/tokens/:address/holdersHolder ranks.
/v1/tokens/:address/candlesMarket-cap candles.
/v1/feedLatest launches and trades across the protocol.
/v1/wallets/:address/holdingsA wallet's tokens with balance, USD value and average-cost PnL, its $KHOOK share, the $KHOOK drops it received, and its launch count. Claimable balances are chain state: read them from the vaults.
/v1/nft/collectionsNFT Strategy collections listed on NftSweeperRegistry, with vault, floor and NFTs held.
  • The token summary includes markets[], marketCount, bondingPhase, realQuote, graduationQuote, decoded modules, windows (5m / 1h / 6h / 24h) and devBuy*.
  • Candles default to 5m. Pass interval=1m, 10m, 15m or 1h. Empty buckets forward-fill the last close. The chart is mcap-based and scoped to poolId.
  • /health exposes head, lagBlocks, lastPollError. Block numbers are Robinhood Chain blocks. At about ten blocks per second, lagBlocks: 50 is about 5 s behind.
TypeScript
// TokenSummary (shape)
{
  address, launchId, rail: "master" | "classic", name, symbol, image, metadataURI, socials,
  creator, createdAt, customHook: boolean, hooks: string, bitmask: string, vestPacked: string,
  modules: string[],                 // decoded, e.g. ["ANTI_SNIPE", "BACKED_FLOOR", "AUTO_BURN"]
  quote: { address, symbol, decimals, kind: "eth" | "usdg" | "stock" },
  markets: [{ index, poolId, quote, bps, tickLower, tickUpper, liquidity }], marketCount,
  bondingPhase: boolean, realQuote, graduationQuote, bondedPct,          // Classic
  priceQuote, priceUsd, fdvUsd, liquidityUsd, holders,
  windows: { "5m": W, "1h": W, "6h": W, "24h": W }, // W = { volumeUsd, trades, buys, sells, changePct }
  floor: { reserve, floorPriceX18, premiumPct } | null,
  vest: { accrued, claimable, unlock: "time" | "fdv", nextRungUsd } | null,
  airdrop: { pot, released, nextEpochAt } | null,
  burned, deepenedQuote, devBuyQuoteIn, devBuyTokensOut
}

On-chain sources: TokenLaunched, PoolManager.Swap, bonding Bought / Sold / Graduated, StateView.getSlot0, LaunchToken.metadataURI. See Onchain events and Reading state.

Network

k'hook runs on Robinhood Chain. Your wallet must match the app chain (Robinhood Chain, 4663).

FieldValue
NetworkRobinhood Chain
Chain ID4663 (0x1237)
GasETH
RPChttps://rpc.mainnet.chain.robinhood.com
Explorerhttps://robinhoodchain.blockscout.com (opens in a new tab)
QuotesETH, USDG, Stock Tokens
Supply1,000,000,000 (both rails)
Master start FDV~$5,000
Classic graduate~4.2 ETH equivalent

Add the network

JSON
{
  "chainId": "0x1237",
  "chainName": "Robinhood Chain",
  "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 },
  "rpcUrls": ["https://rpc.mainnet.chain.robinhood.com"],
  "blockExplorerUrls": ["https://robinhoodchain.blockscout.com"]
}

Pass it to wallet_addEthereumChain, or add it by hand with the same values.

Chain behaviour that matters here

TopicOn Robinhood Chain
StackArbitrum Nitro. ETH pays gas.
BlocksAbout one every 0.1 s at the time of writing. RPC and explorer block numbers are Robinhood Chain blocks.
block.numberInside a contract it returns an L1 block estimate that advances in steps. k'hook reads ArbSys(0x64).arbBlockNumber() for per-block limits. See Anti-MEV.
Block hashesArbSys.arbBlockHash(n) for the last 256 Robinhood Chain blocks.
PREVRANDAOConstant (1). Never used as randomness.
TimestampsWhole seconds. About ten blocks share each second.
Gas usedReceipts include an L1 data-posting component on top of execution gas.
OraclesChainlink. 24 h heartbeat, 0.5% deviation. Stock Token feeds update 24/5.

Testnet

FieldValue
NetworkRobinhood Chain Testnet
Chain ID46630
RPChttps://rpc.testnet.chain.robinhood.com
Explorerhttps://explorer.testnet.chain.robinhood.com (opens in a new tab)

k'hook testnet deployments supply a mock USDG and mock price feeds. Use them for integration tests only.

Contracts

Addresses the app uses for this build, from the chain 4663 deployments file. They win over any copy you saved earlier. Vaults and the drop vault can be re-pointed on the hook, so read them live when it matters: floorVault(), feeEscrow(), buybackVault(), holderAirdropVault(), khookDropVault(). Old factories stay on-chain and are hidden from Explore.

Every address opens on the explorer at https://robinhoodchain.blockscout.com/address/<address>.

Canonical addresses at launch

ContractRoleAddress
LaunchFactoryActive Master launches—
LaunchFactoryQueryPaginated launch index—
BondingLaunchFactoryClassic rail—
MasterLaunchHookMaster pools: quote-only fees + modules—
GraduatedFeeHookGraduated Classic pools—
KhookRouterRequired for hooked swaps—
BalancedAggregatorPAIR-style USDG multi-market splits—
StockTokenRegistryCanonical Stock/USDG bridge pools—
ProtocolRevenueDistributor20% ops / 80% buyback—
FeeEthRailStock Token → USDG, USDG → ETH—
KhookBuybackKeeper execute / executeUsdg → buy and burn $KHOOK—
V4ClaimsRedeemerRedeem Holder Airdrop ERC-6909 claims—
LiquidityLockerHolds graduated Classic LP—
NftSweeperRegistryNFT Strategy registry and fee router—
NftSweepRaffleNFT Strategy raffles—

Vaults

Deployment-time values. The hook's getters win.

VaultHook getterAddress
FloorVaultfloorVault()—
FeeEscrowfeeEscrow()—
BuybackVaultbuybackVault()—
HolderAirdropVaultholderAirdropVault()—
KhookDropVaultkhookDropVault()—

Native token

TokenAddressLaunch
$KHOOK on Robinhood Chain—Master launchId —

Uniswap v4 on this chain

ContractAddressNote
PoolManager0x8366a39CC670B4001A1121B8F6A443A643e40951Every k'hook pool lives here.
StateView0xF3334192D15450CdD385c8B70e03f9A6bD9E673bgetSlot0, getLiquidity.
V4 Quoter0x8Dc178eFB8111BB0973Dd9d722ebeFF267c98F94Quote bridge legs live.
Universal Router0x8876789976dEcBfCbBbe364623C63652db8C0904Not used for hooked k'hook pools.

Quotes and oracles

AssetAddressNote
Stable quote: USDG0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168Global Dollar, 6 decimals.
WETH0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73For bridge pools that hold WETH.
ETH/USD: Chainlink0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A98 decimals. Accepted up to 25 h old.
Stock TokensStockTokenRegistry.stocks()The listed set.
Stock Token feedsLaunchFactory.quoteConfigs(stock)One Chainlink USD feed per stock.

Other

ContractAddressNote
Seaport 1.60x0000000000000068F116a894984e2DB1123eB395The only target NFT Strategy sweeps can call.
ArbSys0x0000000000000000000000000000000000000064arbBlockNumber(), arbBlockHash().

Onchain events

Index from the factory deploy block (—). Paginate getLogs: public RPCs time out on wide ranges. Robinhood Chain makes about ten blocks per second, roughly 864,000 blocks a day, so page by block range.

StreamLogs
LaunchTokenLaunched · MarketLaunched · Graduated
TradePoolManager.Swap · Bought / Sold
FlywheelKhookDropVault.Dropped · BuybackBurned
  • LaunchFactory.TokenLaunched: Master (or custom hook) launch.
  • LaunchFactory.MultiLaunchConfigured / MarketLaunched: multi-pair.
  • BondingLaunchFactory.TokenLaunched / Bought / Sold / Graduated.
  • PoolManager.Swap: Master and graduated Classic trades.
  • KhookDropVault.Credited / Dropped: $KHOOK holder drop.
  • KhookBuyback.BuybackBurned: protocol $KHOOK burn. UsdgConverted precedes it when the buyback spent USDG.
  • FloorVault.Deposited / Redeemed.
  • GraduatedFeeHook.FeesAccrued / Swept: Classic creator fees.
  • FeeEscrow.Claimed: creator pull.

Signatures

ABI types: PoolId is bytes32, Currency and IHooks are address.

Solidity
// LaunchFactory
event TokenLaunched(uint256 indexed launchId, address indexed token, address indexed creator,
    bytes32 poolId, address hooks, bool customHook, int24 tickLower, int24 tickUpper, uint128 liquidity);
event MultiLaunchConfigured(uint256 indexed launchId, uint8 marketCount, uint8 floorQuoteIndex, uint256 bitmask);
event MarketLaunched(uint256 indexed launchId, uint8 indexed marketIndex, bytes32 poolId, address quote,
    uint16 bps, int24 tickLower, int24 tickUpper, uint128 liquidity);
event LaunchConfigured(uint256 indexed launchId, uint256 bitmask, address quote, int24 tickSpacing, uint24 fee);
event DevBuyExecuted(uint256 indexed launchId, address indexed buyer, uint256 quoteIn, uint256 tokensOut);

// BondingLaunchFactory
event TokenLaunched(uint256 indexed launchId, address indexed token, address indexed creator,
    address quote, uint256 graduationQuote);
event Bought(uint256 indexed launchId, address indexed buyer, uint256 quoteIn, uint256 tokensOut, uint256 feeQuote);
event Sold(uint256 indexed launchId, address indexed seller, uint256 tokensIn, uint256 quoteOut, uint256 feeQuote);
event Graduated(uint256 indexed launchId, bytes32 indexed poolId, uint256 quoteLp, uint256 tokenLp, uint128 liquidity);

// PoolManager (Uniswap v4)
event Swap(bytes32 indexed id, address indexed sender, int128 amount0, int128 amount1,
    uint160 sqrtPriceX96, uint128 liquidity, int24 tick, uint24 fee);

// KhookDropVault
event Credited(address indexed token, uint256 amount, uint256 newReserve);
event Dropped(address indexed token, uint256 pot, uint256 distributed, uint256 holders, address caller);

// KhookBuyback
event BuybackBurned(uint256 ethIn, uint256 tokensBurned, address indexed caller);
event UsdgConverted(uint256 usdgIn, uint256 ethOut, address indexed caller); // executeUsdg: USDG → ETH, then the burn

// LaunchFactory and BondingLaunchFactory
event QuoteUsdPriceSynced(address indexed token, uint256 usdPriceX18, uint64 syncedAt); // syncedAt = the round's updatedAt

// FloorVault
event Deposited(address indexed token, address indexed quote, uint256 amount, uint256 newReserve);
event Redeemed(address indexed token, address indexed account, uint256 tokenAmount, uint256 quoteOut);

// GraduatedFeeHook
event FeesAccrued(bytes32 indexed poolId, address indexed currency, uint256 creatorAmount, uint256 protocolAmount);
event Swept(bytes32 indexed poolId, address indexed currency, uint256 creatorAmount, uint256 protocolAmount);

// FeeEscrow
event Claimed(address indexed account, address indexed currency, uint256 amount);

Also emitted by MasterLaunchHook:

EventMeaning
LaunchPrepared(bytes32 indexed poolId, address indexed creator, address indexed token, uint256 bitmask)A Master pool was configured.
FeesDistributed(bytes32 indexed poolId, uint256 creatorAmount, uint256 protocolAmount, uint256 floorAmount, uint256 buybackAmount, uint256 autoBurnAmount, uint256 deepenLpsAmount, uint256 holderAirdropAmount)One fee take, split.
KhookHolderDrop(bytes32 indexed poolId, uint256 quoteIn, uint256 tokensOut)The 10% bought the ticker for the drop vault.
AutoBurn(bytes32 indexed poolId, uint256 quoteIn, uint256 tokenBurned)Auto-Burn ran.
LpDeepened(bytes32 indexed poolId, uint256 quoteAmount)Deepen LPs minted. quoteAmount is the quote the mint consumed. What waits: pendingDeepenLps, pendingDeepenTokens.
FloorFill(bytes32 indexed poolId, uint256 tokenIn, uint256 quoteOut)The floor leg of a sell, filled at P_floor. quoteOut is net of the fee.

HolderAirdropVault.Airdropped(token, quote, pot, distributed, holders, caller) closes an airdrop epoch. BuybackVault.Credited / Claimed track vesting.

Reading PoolManager.Swap

  • sender is the router (KhookRouter, BalancedAggregator), not the wallet. Use the transaction's from for the trader.
  • amount0 / amount1 are the pool's own leg. The hook's fee is settled beside it: on a buy the trader paid that quote amount plus the fee, on a sell the trader received it minus the fee. FeesDistributed in the same transaction carries the split.
  • Fee logs can follow the Swap. For exact-input sells and exact-output buys, FeesDistributed (Master) or FeesAccrued (graduated Classic), and the vault deposits it triggers, are logged after the pool's Swap. Pair fees with swaps by transaction, not by log order.
  • Swaps whose sender is MasterLaunchHook are fee actions: Auto-Burn, the $KHOOK drop buy, Deepen LPs. They are not trades. They run after the fee take, so their logs come after it.
  • A floor-crossing sell logs FloorFill for its floor leg and a Swap for its market leg, each with its own FeesDistributed. A sell filled wholly at the floor logs FloorFill and a Swap with zero amounts.
  • A composite trade logs two swaps: the bridge pool, then the launch pool.

List Master launches (viem)

TypeScript
import { createPublicClient, defineChain, http, parseAbiItem } from "viem";

export const robinhood = defineChain({
  id: 4663,
  name: "Robinhood Chain",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrls: { default: { http: ["https://rpc.mainnet.chain.robinhood.com"] } },
  blockExplorers: { default: { name: "Blockscout", url: "https://robinhoodchain.blockscout.com" } },
});

export const client = createPublicClient({ chain: robinhood, transport: http() });

const tokenLaunched = parseAbiItem(
  "event TokenLaunched(uint256 indexed launchId, address indexed token, address indexed creator, bytes32 poolId, address hooks, bool customHook, int24 tickLower, int24 tickUpper, uint128 liquidity)",
);

const head = await client.getBlockNumber();
const launches = [];
for (let from = —n; from <= head; from += 50_000n) {
  const to = from + 49_999n < head ? from + 49_999n : head;
  launches.push(...(await client.getLogs({
    address: "—",
    event: tokenLaunched,
    fromBlock: from,
    toBlock: to,
  })));
}

The event carries the full signature above. A shorter signature hashes to a different topic and matches nothing.

Reading state

Each launch has a numeric launchId. From there: token, pool, creator, bitmask, quote asset.

IntegerHolds
launchIdToken, pool, creator, quote.
bitmaskModules + tax + caps.
vestPackedBuyback plan · airdrop plan.

Paginate launches

getLaunchPage lives on LaunchFactoryQuery. The per-launch mappings live on LaunchFactory. client is the Robinhood Chain client from Onchain events.

TypeScript
import { parseAbi } from "viem";

const queryAbi = parseAbi([
  "function getLaunchPage(uint256 startId, uint256 limit) view returns ((address token, address creator, address hooks, bool customHook, bytes32 poolId, int24 tickLower, int24 tickUpper, uint128 liquidity)[], uint256[] bitmasks, uint64[] timestamps, uint256 total)",
]);

const factoryAbi = parseAbi([
  "function launchQuote(uint256 launchId) view returns (address)",
  "function launchedAt(uint256 launchId) view returns (uint64)",
  "function launchVestPacked(uint256 launchId) view returns (uint256)",
  "function launchMarketCount(uint256 launchId) view returns (uint8)",
]);

const [page, bitmasks, timestamps, total] = await client.readContract({
  address: "—",
  abi: queryAbi,
  functionName: "getLaunchPage",
  args: [1n, 50n], // startId is 1-indexed
});

const quote = await client.readContract({
  address: "—",
  abi: factoryAbi,
  functionName: "launchQuote",
  args: [1n], // address(0) = ETH
});

getLaunchPage clamps the page: any limit, even type(uint256).max, returns ids startId to launchCount. A startId of 0 or past the end returns an empty page and total.

Unpack the bitmask for modules. vestPacked is a separate uint256 (low 128 = buyback plan, high 128 = airdrop plan). metadataURI holds image and socials. Charts and holder ranks need the indexer or your own Transfer scan.

Per pool, the hook holds the same words: MasterLaunchHook.configs(poolId) and MasterLaunchHook.vestPacked(poolId).

Module state

ViewReturns
MasterLaunchHook.pendingAutoBurn(poolId)Quote queued for Auto-Burn.
MasterLaunchHook.pendingKhookDrop(poolId)Quote queued for the $KHOOK drop buy.
MasterLaunchHook.pendingDeepenLps(poolId)Quote queued for Deepen LPs.
MasterLaunchHook.pendingDeepenTokens(poolId)Launched tokens a Deepen LPs mint could not use, carried into the next mint.
BuybackVault.confirmedFdvUsd(token)FDV in whole USD that held for 1 hour: what FDV unlocks read. highWaterFdvUsd returns the same value.
BuybackVault.fdvWindowStart(token), fdvWindowMinUsd(token)The open hold window: its start, and its lowest FDV so far.
HolderAirdropVault.confirmedFdvUsd(token)The same for the airdrop plan, with fdvWindowStart and fdvWindowMinUsd.
HolderAirdropVault.deferredRemovalCount(token)Holders whose removal waits for the payout in flight.
KhookDropVault.deferredRemovalCount()The same for $KHOOK holders.

While removals wait, holderList and holderCount on both vaults still include those holders, at a zero tracked balance.

Bitmask layout (BitmaskConfig)

BitsField
bit 0ANTI_SNIPE
bit 1BACKED_FLOOR
bit 2ANTI_MEV
bit 3MAX_TX
bit 4HOOK_TO_CREATOR
bit 5DYNAMIC_FEES
bit 6BUYBACK_VESTING
bits 7-22hookTaxBps
bits 23-38antiSnipeDurationSeconds
bits 39-54maxTxBps
bits 55-70hookToCreatorBps
bits 71-94floorAllocationBps
bits 95-110initialSnipeTaxBps
bit 111AUTO_BURN
bit 112DEEPEN_LPS
bits 113-128autoBurnBps
bits 129-144deepenLpsBps
bit 145HOLDER_AIRDROP
bits 146-161holderAirdropBps
bit 162CREATOR_SHARE_TO_HOOK
bits 163-194buybackVestingDurationSeconds
bits 195-210dynamicFeeMinTotalBps
bits 212-227dynamicFeeDepthSaturationBps
bits 228-259holderAirdropEpochSeconds
Bitmask layout (BitmaskConfig)Fig. 32
0
32
64
96
128
160
192
224
ANTI_SNIPEBACKED_FLOORANTI_MEVMAX_TXHOOK_TO_CREATORDYNAMIC_FEESBUYBACK_VESTINGAUTO_BURNDEEPEN_LPSHOLDER_AIRDROPCREATOR_SHARE_TO_HOOK
hookTaxBpsantiSnipeDurationSecondsmaxTxBpshookToCreatorBpsfloorAllocationBpsinitialSnipeTaxBpsautoBurnBpsdeepenLpsBpsholderAirdropBpsbuybackVestingDurationSecondsdynamicFeeMinTotalBpsdynamicFeeDepthSaturationBpsholderAirdropEpochSecondsbit 211, legacy DYNAMIC_FEE_RAMP_UP, ignored

Bit 0 first, 32 bits per row. Flags are 1 bit each (bright); fields span the runs in the same colour.

  • Bit 211 is not in the table. It is a legacy flag, and the ramp always rises with depth consumed.
  • The word ends at bit 255, so holderAirdropEpochSeconds keeps its low 28 bits. The 7-day maximum (604,800 s) fits.
  • A zero field with its flag set means the default: initialSnipeTaxBps 5,000; buybackVestingDurationSeconds 5 years; dynamicFeeMinTotalBps 100; dynamicFeeDepthSaturationBps 10,000; holderAirdropEpochSeconds 900.
  • antiSnipeDurationSeconds has no default. With Anti-Snipe on it must be 1–3,600, or the launch reverts (AntiSnipeWindowTooShort / AntiSnipeWindowTooLong).
  • NFT Strategy is not a bit. The word is full. A token runs NFT Strategy when bpsOf(token) on MasterLaunchHook.nftStrategy() returns 10,000.
TypeScript
const bit = (m: bigint, i: number) => ((m >> BigInt(i)) & 1n) === 1n;
const field = (m: bigint, lo: number, width: number) =>
  Number((m >> BigInt(lo)) & ((1n << BigInt(width)) - 1n));

export function decodeBitmask(m: bigint) {
  return {
    antiSnipe: bit(m, 0),
    backedFloor: bit(m, 1),
    antiMev: bit(m, 2),
    maxTx: bit(m, 3),
    hookToCreator: bit(m, 4),
    dynamicFees: bit(m, 5),
    buybackVesting: bit(m, 6),
    hookTaxBps: field(m, 7, 16),
    antiSnipeDurationSeconds: field(m, 23, 16),
    maxTxBps: field(m, 39, 16),
    hookToCreatorBps: field(m, 55, 16),
    floorAllocationBps: field(m, 71, 24),
    initialSnipeTaxBps: field(m, 95, 16),
    autoBurn: bit(m, 111),
    deepenLps: bit(m, 112),
    autoBurnBps: field(m, 113, 16),
    deepenLpsBps: field(m, 129, 16),
    holderAirdrop: bit(m, 145),
    holderAirdropBps: field(m, 146, 16),
    creatorShareToHook: bit(m, 162),
    buybackVestingDurationSeconds: field(m, 163, 32),
    dynamicFeeMinTotalBps: field(m, 195, 16),
    dynamicFeeDepthSaturationBps: field(m, 212, 16),
    holderAirdropEpochSeconds: field(m, 228, 32),
  };
}

vestPacked layout (McapVest)

vestPacked = buyback | (airdrop << 128). Each 128-bit plan:

BitsField
0-1kind: 0 time, 1 cliff, 2 steps
2-33durationSeconds
34-36cliffPreset
37-39stepCount (≤ 6)
40 + 11·istep i: preset (3 bits), then pct (8 bits)
Preset0123456
FDV$5M$10M$50M$100M$500M$1B$10B
  • Kind 0 (time) is a no-op here. The vault keeps its clock: the bitmask vest duration, or the airdrop epoch.
  • The buyback plan starts at preset 1 ($10M). The airdrop plan may use preset 0 ($5M).
  • Step presets must rise. Step percents must sum to 100.

Pricing

Master and graduated spot is sqrtPriceX96. Classic before graduation is virtual reserves. USD multiplies by the chain feed.

PricingFig. 33
StateView.getSlot0returns sqrtPriceX96P = (√P / 2⁹⁶)²quote per token× 1Bfixed supply× FXChainlink ETH/USD, the Stock Token's USD feed, or USDG/USDFDVa USD print

Classic on the curve uses virtual reserves instead of sqrtPriceX96.

Read pool price from StateView

client is the Robinhood Chain client from Onchain events.

TypeScript
import { parseAbi } from "viem";

const [sqrtPriceX96] = await client.readContract({
  address: "0xF3334192D15450CdD385c8B70e03f9A6bD9E673b", // StateView
  abi: parseAbi([
    "function getSlot0(bytes32 poolId) view returns (uint160 sqrtPriceX96, int24 tick, uint24 protocolFee, uint24 lpFee)",
  ]),
  functionName: "getSlot0",
  args: [poolId],
});

const ratio = Number(sqrtPriceX96) / 2 ** 96;
const priceQuotePerToken = tokenIsCurrency0 ? ratio * ratio : 1 / (ratio * ratio);

// quote wei per token wei → whole units (launched tokens have 18 decimals)
const quoteDecimals = 18; // ETH and Stock Tokens; 6 for USDG
const price = priceQuotePerToken * 10 ** (18 - quoteDecimals);

priceQuotePerToken is quote wei per token wei. Launched tokens, ETH and Stock Tokens all have 18 decimals, so for them it is also the whole-unit price. USDG has 6 decimals: multiply by 10^12.

USD

Ask the factory for the price k'hook itself uses:

TypeScript
const usdX18 = await client.readContract({
  address: "—",
  abi: parseAbi(["function quoteUsdPriceX18(address token) view returns (uint256)"]),
  functionName: "quoteUsdPriceX18",
  args: [quote], // address(0) = ETH
});

const fdvUsd = price * 1e9 * (Number(usdX18) / 1e18);

quoteUsdPriceX18 applies the full fallback chain and reverts StalePrice() when every path is stale. See Why Stock Tokens.

QuoteFX sourceMax age
ETHChainlink ETH/USD, 0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9, 8 decimals, 24 h heartbeat, 0.5% deviation25 h; then the last synced snapshot, up to 24 h after its round
USDGChainlink USDG/USD (USDG ≈ $1)25 h
Stock TokenIts Chainlink USD feed: multiplier-adjusted price per token, updates 24/55 days, skipped while oraclePaused(); then bridge spot within ±20% of the snapshot; then the snapshot
  • Floor: FloorVault.floorPriceX18(token).
  • UI liquidity is TVL in USD, not raw Uniswap L.
  • Never apply a Stock Token's uiMultiplier() to its feed. The feed already prices one token.
  • Read decimals() from each feed. Do not assume 8.

Risks

Tokens are user-created. k'hook does not vet tickers, teams or hook combinations.

Assume the worst print

RiskMeaning
ZeroMost tickers go to nothing.
CopycatsVerify the contract every time.
Thin bookThe printed price is not an exit.
  • You can lose everything. Prices are violent and many tokens go to zero.
  • Copycat names, logos and socials are normal. Check the contract every time.
  • Contracts may have bugs. Not every configuration is audited.
  • Custom hooks can honeypot, tax or block sells.
  • Low liquidity means the printed price is not an exit.
  • RPC, wallet and indexer outages show stale or empty UI.
  • Explore labels are heuristics. A badge is not a vet.

Stock Tokens

  • Restricted jurisdictions. Stock-quoted markets, the USDG routes into them, and payouts in Stock Tokens (creator fees, Holder Airdrop, floor redemptions on a Stock-quoted pool) all move Stock Tokens. Check that you are eligible before you trade, launch or claim.
  • Corporate-action oracle pauses. Stock Token feeds update 24/5 and pause during corporate actions, when the token's oraclePaused() is true. k'hook then prices from the bridge spot (within ±20% of the snapshot) or a snapshot up to 5 days old. Past that, new launches quoted in that stock revert StalePrice(), FDV-target unlocks stop advancing, and USD prints go stale.
  • Market closed, pool open. Pools trade 24/7 on their own curves, including while the stock's market is closed. Prices can gap when it reopens.
  • Issuer pause or blocklist. The Stock Token issuer can pause transfers or blocklist addresses. A pause freezes every k'hook market quoted in that Stock Token: swaps, composite routes, fee claims, floor redemptions and airdrop pushes that move it revert until it lifts. A blocklisted pool, vault or wallet cannot move that Stock Token at all.
  • Multiplier changes. After a split or similar action, wallets may show a different share-equivalent amount. Pool math uses raw token units.
  • Bridge pools. Composite fills depend on the canonical Stock/USDG pool's depth and fee. Delisting a stock from StockTokenRegistry stops new routing and new launches through it. Existing pools keep trading.

Chain and oracles

  • Robinhood Chain orders transactions through its sequencer. While it is down, swaps, claims and launches wait until it recovers.
  • Chainlink feeds size launches, graduation targets and FDV unlocks. A wrong or stale feed moves those numbers. It never fills a trade.
  • The NFT Strategy raffle draws from a block hash. The sequencer produces those blocks. It is not a VRF. Only the keeper requests a draw. Anyone can finalize it, which fixes the result.

Admin keys

Deployed contracts are not upgradeable. After deploy one owner address holds every Owned contract and the NFT Strategy registry. The mainnet checklist requires a multisig: check owner() on each contract. Ownership moves in one step.

The owner can set:

  • The launch fee (no upper bound), the treasury, the allowed quotes and their feeds and snapshots, custom-hook switches (off by default). Quote prices size every new launch's $5,000 FDV and the Classic 4.2 ETH-eq target, and they price the FDV observations behind FDV unlocks.
  • StockTokenRegistry listings, bridge keys and allowed bridge hooks, and the fee rail's ETH bridge.
  • The hook's Holder Airdrop vault, the drop vault on both hooks and the bonding factory, and the NFT Strategy registry. Tokens keep syncing their holders to the airdrop vault they launched with, but the hook sends every pool's airdrop share, pushes and FDV prints to the current one: re-pointing it moves existing launches' airdrop shares to a vault that lists none of their holders. With no drop vault set, or one that does not answer, the 10% goes to protocol. A registry that does not answer sends NFT Strategy pots to protocol. Pools keep trading either way.
  • An arb executor path on MasterLaunchHook, off by default. When switched on, swaps from that one executor pay the 1% base entirely to protocol: no creator or $KHOOK share, no hook tax, no snipe. They also skip Anti-MEV, Max Tx, floor fills and the modules, and are not FDV observations.
  • The distributor's ops treasury, fee rail, buyback wallet, native token and flywheel mode. The default mode buys and burns $KHOOK. A legacy mode deposits the 80% into a floor vault instead.
  • Operators on the vaults, the distributor, KhookBuyback and GraduatedFeeHook, and the NFT Strategy keeper. The owner passes every operator check itself.

Operators are custodial. On FeeEscrow, BuybackVault, FloorVault and HolderAirdropVault an operator can credit balances without depositing funds, and on the two FDV vaults it can post FDV observations. The owner, or an operator it appoints, can therefore withdraw funds that belong to creators, floor holders and airdrop recipients, and unlock FDV-gated plans. The deploy makes only the two hooks and the bonding factory operators there. KhookBuyback.sweep lets the owner move any asset the buyback holds, including the USDG buyback share.

The keeper wallet holds narrower roles:

  • Operator on KhookBuyback (execute, executeUsdg), GraduatedFeeHook (sweepKhookDrop) and ProtocolRevenueDistributor (the Stock Token → USDG rail, the only way Stock Token revenue leaves it: distribute refuses Stock Tokens). Each of these swaps with a minimum output the caller picks. A compromised keeper can sell protocol revenue, or the graduated pools' 10% $KHOOK-holder cut, at a bad price. As a distributor operator it can also post revenue notices without funds, which can shift protocol revenue between the ops and buyback pots.
  • NFT Strategy keeper: posts the floor cap itself and sweeps at or under it (Seaport only, one funding token per sweep). It publishes raffle snapshots, requests draws (only a keeper can), finalizes them and claims each NFT for its winner. The deploy gives every collection it lists a ceiling on the cap, 1 ETH per NFT (NftDeploy.DEFAULT_MAX_FLOOR_CAP), which the owner can raise or remove (setMaxFloorCap). A compromised keeper can post a cap up to the ceiling and sell its own NFTs to the vault: per sweep, at most the lower of the funding token's credit and the ceiling × NFTs bought. The registry owner appoints the keepers, itself included. It can cancel a snapshot before its draw is requested, and reset a draw nobody claimed for 3 days (resetDraw).
  • It is not an operator on FeeEscrow, BuybackVault, FloorVault or HolderAirdropVault. It cannot change a launch's modules or move user balances.

The owner cannot change a launch's bitmask or vestPacked, unlock its LP, or change the 1% base, the 60 / 10 / 30 split or the 10% steady-fee cap.

Privileged roles

Every privileged role, as mapped by the September 2026 audit of the factories, oracles, NFT Strategy and roles. The tables reflect its remediation (docs/PORT_LOG.md §10). "Owner" is PROTOCOL_OWNER: one address owns all 13 Owned contracts and the NFT Strategy registry. Ownership moves in one step (setOwner), with no timelock and no zero-address check. No contract is upgradeable. Every onlyOperator check also admits the owner.

Owner

ContractPowersCan it take user funds?Effect on existing launches
LaunchFactorysetLaunchFee (no upper bound), setTreasury, setQuote (allow, decimals, snapshot, feed), setEthUsdPrice, setEthUsdFeed, setSequencerUptimeFeed, the custom-hook switches and allowlist, setNftStrategyNo. It holds only dust.Its prices are the FDV source of every Master pool's Buyback Vesting and Holder Airdrop plans. A fake feed or price unlocks them after the 1-hour hold; disallowing the quote or breaking the feed makes the FDV prints 0, which freezes them. New launches: it can block them (fee), mis-size them, or allow arbitrary custom hooks, which can steal from traders in their pools.
BondingLaunchFactorysetLaunchFee, setTreasury, setQuote, setEthUsdPrice (and feed), setSequencerUptimeFeed, setKhookDropVaultNo. There is no path to curve reserves or to the locker's LP.Redirects the 10% fee-cut token buys of live curves. A drop vault that does not answer, or no longer lists the factory as operator, sends the 10% to protocol, and curves keep trading. Graduation targets are fixed at launch.
MasterLaunchHooksetFactory, setAirdropVault, setKhookDropVault, setNftStrategy, setArbExecutor, setArbActiveNo. Launch and Deepen LPs positions have no removal path.Redirects the 10% $KHOOK cut and the hook pot of every token the NFT Strategy registry claims (bpsOf = 10,000): a registry that claims every token takes every Master pool's hook pot. setAirdropVault moves existing launches' airdrop shares, pushes and FDV prints to the new vault, which lists none of their holders. A drop vault or NFT Strategy registry that does not answer sends those shares to protocol, and pools keep trading. A factory that does not answer (reverts, has no code, sends a reply the FDV math cannot use) leaves FDV plans unpriced: every swap prints an FDV of 0, so no plan unlocks while it lasts, and pools keep trading. A Holder Airdrop vault that only fails its push or its due-pot views is skipped too; one that reverts on the credits or FDV prints it receives still halts the pools that call it on every swap: those with FDV plans or Holder Airdrop. Can enable one arb address that pays only the 1% to protocol, with no hook tax, snipe tax, Anti-MEV, Max Tx or FDV observation. setFactory changes every pool's FDV price source.
GraduatedFeeHooksetFactory (new registrations), setKhookDropVault, setOperatorNo. The graduation LP stays in the locker for good.Redirects the 10% cut of graduated pools. A drop vault that does not answer sends it to protocol, and the pools keep trading.
FeeEscrowsetOperator; as operator, creditInternal (credits any account without funds) and credit (funded)Yes: creators' unclaimed fees.Revoking the hooks' or the bonding factory's operator role halts their swaps.
FloorVaultsetOperator; as operator, setQuote, depositInternal (unbacked), deposit (funded), drawForFloorYes: Backed Floor reserves.Can break Backed Floor fills and redemptions.
BuybackVaultsetOperator; as operator, configurePlan, observeFdv (any FDV), creditInternal (unbacked), credit (funded)Yes: creators' vesting balances.Can unlock or freeze any FDV plan.
HolderAirdropVaultsetOperator; as operator, setExcluded, configureEpoch, configurePlan, observeFdv, depositInternal (unbacked), deposit (funded)Yes: airdrop pots.Can exclude holders, and unlock or freeze plans.
KhookDropVaultsetOperator, setKhook, configureEpoch, sweep (only the balance above reserves); as operator, setExcluded, creditInternal (backed)Yes, indirectly: setKhook pointed at a token it holds diverts every $KHOOK-holder drop.Can exclude holders.
ProtocolRevenueDistributorsetOperator, setOpsTreasury, setNativeToken, setFlywheelMode, setFeeRail, setBuybackExecutorProtocol revenue only (not user funds), all redirectable.Revoking an operator halts that rail's swaps. The legacy DepositFloor mode reverts every distribute until the distributor is a FloorVault operator.
KhookBuybacksetOperator, configure (any ETH/x pool), sweep (any asset)Protocol funds: the USDG flywheel share, any other asset it holds, and the ETH pot through configure + execute.None.
FeeEthRailsetEthBridge (any USDG/ETH pool with an allowed hook)Protocol conversions only.None.
StockTokenRegistrylist, delist, setBridgeKey, setBridgeHookAllowedNo.Chooses the spot source used during feed outages and the protocol's conversion pools. Delisting reprices existing Stock-quoted launches as a crypto quote (25-hour maximum feed age), so their FDV prints are 0 over weekends.
NftSweeperRegistry (with SweepVault.setMaxFloorCap, NftSweepRaffle.cancelSnapshot and NftSweepRaffle.resetDraw)List and delist collections, setKeeper (no bound), setRaffle (once), setMaxFloorCap (0 removes the ceiling), cancel a snapshot while no draw is requested, resetDraw a draw nobody claimed for 3 daysYes, indirectly: it can appoint itself keeper and sell its own NFTs to a vault, per sweep at most the lower of the funding token's credit and the ceiling × NFTs bought. The deploy lists every collection with a 1 ETH per NFT ceiling (NftDeploy.DEFAULT_MAX_FLOOR_CAP), which the owner can raise or remove.Delisting only stops new launches. resetDraw sends a raffle back to the snapshot stage with a new challenge window. The keeper claims for winners right after the draw, so in practice it only meets a ticket nobody can claim.

Keeper

KEEPER_ADDRESS: operator on ProtocolRevenueDistributor, KhookBuyback and GraduatedFeeHook, and NFT Strategy keeper.

ContractPowersCan it take user funds?Effect on existing launches
ProtocolRevenueDistributornotifyInternal / notifyBuybackInternal (unbacked accounting credits), notify (funded), railStockToUsdg and the Stock Token branch of distributeToBuyback (it picks minUsdgOut; the only way out for Stock Token revenue)Protocol revenue only. It can sandwich its own conversions and shift the ops share into the buyback pot.None.
KhookBuybackexecute, executeUsdg (it picks minEthOut and minTokensOut)The protocol buyback pot, by sandwiching its own buys.None.
GraduatedFeeHooksweepKhookDrop (it picks minTokensOut), sweepWithConversion (an unused path)The 10% cut of graduated pools, by sandwiching its own buys.None.
SweepVault, NftSweepRaffle (NFT Strategy keeper)postFloorCap (up to the ceiling); sweep (it picks the listings, the amount and one funding token; allowlisted Seaport fulfilments only, NFTs always go to the vault); publishSnapshot (root, totalTickets, URI, and a proof that the last leaf ends at totalTickets); requestDraw (keeper only)Yes: per sweep, at most the lower of the funding token's credit and the ceiling × NFTs bought, paid for NFTs of the collection delivered to the vault, for example by selling its own at the ceiling.Decides the ticket list and when draws are requested. It can hold back a draw it dislikes and request again after 256 blocks, but anyone who finalizes it within that window fixes the result. Checks: the 15-minute challenge window, the owner's cancel, and the owner's resetDraw of a ticket nobody can claim, 3 days after the draw.

Others

RolePowersCan it take user funds?Effect on existing launches
AnyonefinalizeDraw, claim (the NFT always goes to the winner), harvest, burn (BURN outcome NFTs), the sync…Price calls, distribute (ETH, USDG and any currency but a listed Stock Token), flushBuyback, sweepQuote, graduateNo. distribute of a listed Stock Token reverts StockTokenNeedsRail: that revenue waits for the operator's conversion to USDG.None.
Deployer, after hand-offNo role. Every Owned contract and the registry move to PROTOCOL_OWNER, and the deployer gets no operator role. It stays the $KHOOK creator, which gives no power because the creator share goes to the hook pot.Only if TREASURY, OPS_WALLET, KEEPER_ADDRESS or PROTOCOL_OWNER is left unset: each defaults to the deployer.A mistyped owner is irreversible (one-step transfer).
CreatorClaims its own fees; chooses the NFT outcome before launchNo. LaunchToken has no admin functions, and its metadata is immutable.None.
Factories (as operators)LaunchFactory: prepareLaunch and pool initialisation on the Master hook, register on the NFT registry. BondingLaunchFactory: registerLaunch on the graduated hook, and FeeEscrow, distributor and drop-vault credits.No.None.

External parties

PartyPowersEffect
Robinhood Chain sequencerTransaction ordering (first come, first served) and the L2 block hashes behind rafflesCan bias raffles. No sequencer-uptime feed exists for the chain.
ChainlinkETH/USD, USDG/USD and Stock Token feedsLaunch sizing, graduation targets and FDV prints.
Stock Token issuerPause, blocklist, oraclePaused()Pause and blocklist freeze Stock-quoted curves, pools, graduations and claims. oraclePaused() switches pricing to the bridge spot (±20% band).

Terms

The full Terms and Privacy Policy are linked in the site footer. Short version: software only, no custody, no advice, no refunds.

Software onlyMeaning
No custodyThe site never holds keys.
No adviceNot a listing or a vet.
No refundsLaunch fee and gas stay spent.
  • Brand: k'hook.
  • k'hook is independent software deployed on Robinhood Chain. Not affiliated with Robinhood.
  • Stock Tokens are not available to U.S. persons and are restricted in other jurisdictions.
  • On-chain data is public. You are responsible for how you use it.
  • Deployed contracts are not upgradeable. New versions ship as new factory addresses. Owner-settable parameters are listed under Risks.
  • k'hook's contracts are an MIT-licensed port of hookit. The license and notice ship with the source. Differences from hookit lists every change.

Differences from hookit

k'hook runs hookit's contracts with Robinhood Chain plumbing and a set of fixes. Every other fee number, split, bitmask bit, formula, limit and event is hookit's.

The Log column cites sections of the port log, docs/PORT_LOG.md, or of the porting spec, docs/PORTING.md. Both ship with the source. Each port log entry names the files, the cause and the tests.

Chain plumbing

ChangeWhyLog
Robinhood Chain 4663 (testnet 46630) and its Uniswap v4 addresses replace Ink 57073.The chain.§2
StockTokenRegistry lists one canonical Stock/USDG v4 pool per Robinhood Stock Token, with allowlisted bridge hooks. The factories, router, aggregator, fee rail and distributor read it. hookit's Quotrons libraries are gone.Robinhood Chain has about 195 Stock Tokens trading in ordinary v4 pools, not one fixed venue.§2
Pricing reads Chainlink first: ETH/USD and USDG/USD up to 25 h old, Stock Tokens up to 5 days old and not oraclePaused(). Then the bridge spot within ±20% of the snapshot, then the snapshot. An optional sequencer-uptime feed can gate it. hookit: 1 h feeds, Quotron pool spot.Robinhood Chain feeds have a 24 h heartbeat. Stock feeds pause over weekends: up to about 96 h measured.§2, §8.1
Anyone can copy a live round into a quote's snapshot: syncQuoteUsdPrice(token) on both factories, dated at the round's updatedAt.Keeps the Stock Token fallback fresh without owner transactions.§8.2
Anti-MEV keys its lock on ArbSys.arbBlockNumber().Inside a contract block.number is an L1 estimate that many Robinhood Chain blocks share.§2
The NFT Strategy raffle draws from ArbSys.arbBlockHash. The NFT Strategy vaults are written from hookit's spec.PREVRANDAO is constant on this chain. hookit published only the interface.PORTING §5–6
$HKT → $KHOOK, HookitSwapRouter → KhookRouter, HktHolderDropVault → KhookDropVault, HkitBuyback → KhookBuyback, HOOKIT.* salts → KHOOK.*.Brand.§1
Launched token addresses end in …f, not …8.Tells k'hook launches apart from hookit's. Same mining cost.§8.1

Fixes

ChangeWhat was wrongLog
FDV unlocks count a level once it has held for 1 hour. A swap that cannot be priced counts as $0.One spot print unlocked a plan for good: a flash pump and dump freed a whole vest for the cost of the round trip.§8.2
Converting protocol Stock Token revenue to USDG is operator-only.The caller picks minUsdgOut: an open call could skew the bridge pool, convert at 0 and unwind.§8.4 U2
A revoked bridge hook fails closed: no routing, no price.Existing listings kept routing and pricing through it.§8.4 P1
Exact-input sells and exact-output buys pay their fee on the executed quote leg, in afterSwap. New hook flags, so new hook addresses: 0x…2ACC (Master), 0x…20CC (graduated).Priced at the pre-swap spot, a "1%" fee took about 3% of a large sell. With a 10% fee after a 100x pump it exceeded the whole output. Exact-output buys under-paid.§9.1 #1
KhookRouter reverts PartialFill() when an exact-input leg stops early.A limit-stopped swap paid the fee on input that never traded.§9.1 #1
The Anti-Snipe window must be 1–3,600 s.A 0 s window never decayed: a permanent buy tax up to 99%.§9.1 #2
Only the protocol's own positions are locked. Others can remove liquidity they add in the launch range.Anyone's liquidity in the exact launch range was locked for good.§9.1 #3
Classic sell returns the net quote paid.It returned the gross, fee included.§9.1 #4
The Classic dev-buy quote cap never admits more than 2.5% of supply.A dev buy exactly at the cap reverted.§9.1 #5
getLaunchPage clamps its bounds.A large limit overflowed and reverted.§9.1 #6
Deepen LPs carries what a mint cannot use (pendingDeepenTokens) into the next mint, and a mint spends only its own budget.About 8.6% of every budget was stranded, and a mint could pull other pots' claims.§9.1 #7
The ETH/USD snapshot is dated at its round's updatedAt.A late sync kept a price about 49 h old usable.§9.1 #8
KhookBuyback.executeUsdg swaps the USDG buyback share to ETH, then buys and burns $KHOOK.The USDG share sat idle until the owner swept it.§9.1 #9
A sell that crosses the floor trades at market down to the floor. Only the rest fills at P_floor.The whole sell filled at P_floor: one more token-wei could pay less.§9.1 #10
A floor fill larger than the PoolManager's token inventory reverts FloorFillExceedsInventory(). Split the sell.The token transfer underflowed with an opaque revert.§9.1 #11
Holders who leave during a multi-batch payout keep their slot until it ends.Swap-and-pop moved the last holder behind the cursor, unpaid for the epoch.§9.1 #12
Max Tx pools reject exact-output sells (MaxTxExactOutput).The spot estimate let about 11.1M tokens through a 10M cap.§9.1 #13
The Classic curve rounds new reserves up, in the curve's favour.Round trips extracted wei, and k shrank with every sell.§9.1 #14

Events

  • Every hookit event keeps its signature, apart from the renames.
  • New on the ported contracts: QuoteUsdPriceSynced, SequencerUptimeFeedSet, UsdgConverted. The contracts new in k'hook, StockTokenRegistry and the NFT Strategy vaults, bring their own.
  • FeesDistributed and FeesAccrued can now follow the pool's Swap. See Onchain events.

Unchanged

The 1% base and its 60 / 10 / 30 split. Hook tax 0–9%, with 1% + tax ≤ 10%. Snipe ≤ 99%. The bitmask and vestPacked layouts. 1B supply, the ~$5,000 start FDV, the 0.0005 ETH launch fee. The Classic curve: 80 / 20, graduation at 4.2 ETH-eq. The 2.5% dev-buy cap. 1–5 markets. 48-holder batches. 15-minute airdrop epochs, 60 s–7 days. Vests of 7 days–5 years.

hookit behaviours kept as they are, with their risks, are logged in PORT_LOG §5 and §8.4.

Preview dataRobinhood Chain