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.
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.
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.
| Category | Modules |
|---|---|
| Protection | Anti-Snipe · Anti-MEV · Max Tx · Backed Floor · Deepen LPs |
| Tokenomics | Auto-Burn · NFT Strategy · Buyback Vesting |
| Rewards | Holder Airdrop · Hook → Creator · Creator → Hook |
| Trading fees | Fixed 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.
| Master | Classic | |
|---|---|---|
| Pool | From block 0, in the launch transaction | After the curve fills |
| Modules | Programmable hooks: floor, burn, vesting, … | None. 1% base only |
| Price | Opens at ~$5,000 FDV | Bonds, then graduates at ~4.2 ETH-eq |
| Hook | MasterLaunchHook | GraduatedFeeHook |
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
Money flow
Buys are charged in beforeSwap; sells in afterSwap, on the executed quote leg.
Hook tax sinks are set per launch by the bitmask.
Contracts
| Contract | Job |
|---|---|
LaunchFactory | Master launches: launch, launchMulti, launchWithNftStrategy. Mints the token, initializes the pool(s) and locks LP in one transaction. |
LaunchFactoryQuery | Read-only paginated launch index (getLaunchPage). |
BondingLaunchFactory | Classic rail: bonding curve, then graduation into a v4 pool. |
LaunchToken | The fixed-supply, burnable ERC-20 every launch mints. Stores metadataURI. |
MasterLaunchHook | Shared v4 hook for Master pools: quote-only fees, locked LP, modules. |
GraduatedFeeHook | v4 hook for graduated Classic pools: 1% base only. |
LiquidityLocker | Holds graduated Classic LP. |
KhookRouter | Hooked swaps: one pool, or a bridge leg plus the launch leg in one unlock. |
BalancedAggregator | USDG splits across up to five multi-pair markets. |
StockTokenRegistry | The canonical Stock/USDG v4 bridge pool for each listed Stock Token. |
FloorVault | Backed Floor quote reserves and redemptions. |
FeeEscrow | Default home of creator fees. |
BuybackVault | Vested creator proceeds, time or FDV unlock. |
HolderAirdropVault | Holder Airdrop pots and epoch pushes. |
KhookDropVault | The mandatory 10% $KHOOK holder drop. |
V4ClaimsRedeemer | Turns ERC-6909 PoolManager claims into tokens. |
ProtocolRevenueDistributor | Splits the 30% protocol cut: 20% ops, 80% buyback. |
FeeEthRail | Converts protocol fee inventory: Stock Token → USDG, USDG → ETH. |
KhookBuyback | Spends buyback ETH on $KHOOK and burns it. |
NftSweeperRegistry, SweepVault, NftSweepRaffle | NFT 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.
| Area | On Robinhood Chain |
|---|---|
| Stock venue | Robinhood Stock Tokens against USDG. One canonical Stock/USDG v4 pool per stock, listed in StockTokenRegistry. |
| Prices | Chainlink feeds for ETH/USD, USDG/USD and every listed Stock Token. |
| Block counter | ArbSys(0x64).arbBlockNumber() for per-block limits. block.number is an L1 estimate on this chain. |
| NFT sweeps | Seaport 1.6 on Robinhood Chain. |
| Renames | HookitSwapRouter → 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.
| Step | Screen | What you decide |
|---|---|---|
| 1 / 6 | Token & pair | Name, 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 / 6 | Protection | Optional shields that freeze at launch: Anti-MEV, Anti-Snipe, Max Tx. Off by default. You cannot edit them after the tx. |
| 3 / 6 | Tokenomics | Where 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 / 6 | Trading fees | How 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 / 6 | Fee split | Split 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 / 6 | Review & launch | Read 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:
| Field | Value |
|---|---|
| Supply | 1,000,000,000 |
| Base fee | 1% · 60 / 10 / 30 |
| LP | Locked same tx |
- The same six screens back every Master launch. The bitmask and
vestPackedfreeze 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.
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.
GraduatedFeeHookkeeps 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).
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 revertsDuplicateQuote. - 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.
One unlock for every leg. $TICKER lands in the wallet.
| Example | |
|---|---|
| Buy | 100 USDG → 60% NFLX leg + 40% NVDA leg → tokens to your wallet. |
| Bridge | Each stock leg uses the canonical Stock/USDG pool from StockTokenRegistry.bridgeKey(stock), the same hop as the KhookRouter composite. |
| Sell | Reverse path: token → Stock Token → USDG, still one tx when routed through the aggregator. |
BalancedAggregator splits exact input across canonical launch legs in one unlock.
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
| Property | Value |
|---|---|
| What | ERC-20 tokens on Robinhood Chain. Each tracks one U.S.-listed stock or ETF. About 195 are live at the time of writing. |
| Decimals | 18 |
| Rebasing | No. ERC-8056 uiMultiplier() scales the amount wallets display. Raw balances never change. |
| Price feed | One Chainlink USD feed per listed stock. 8 decimals. Reports the multiplier-adjusted price of one token. Updates 24/5. |
| Pause flag | oraclePaused() on the token. Advisory. Set while the feed is paused, for example during a corporate action. |
| On k'hook | The live list is StockTokenRegistry.stocks(). A stock must be listed there before it can be a quote. |
USDG
| Property | Value |
|---|---|
| Token | Global Dollar (USDG), 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 |
| Decimals | 6 |
| Role | The asset Stock Tokens trade against. A launch quote, single or multi-pair. The settlement asset for composite routes and BalancedAggregator. |
| Price | Chainlink 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.
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 uninitializedlist(stock, key)checks that the key pairs exactly {stock, USDG} in sorted order, thatkey.hookspassesisAllowedBridgeHook, and that the pool is initialized.- The registry is routing data. Its
spotUsdX18is 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.
Chainlink pricing
USD prices size things. They never fill trades. Swaps always fill on the AMM curve.
| Where a USD price is used | When |
|---|---|
| Opening a Master pool at ~$5,000 FDV | At 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 Airdrop | On every swap, best effort |
| USD prints in the app | Continuously |
A Stock Token quote is priced by quoteUsdPriceX18(stock) in this order:
- The Chainlink feed, if
answer > 0,updatedAtis within 5 days (EQUITY_ORACLE_MAX_AGE), and the token'soraclePaused()is nottrue. - Else the bridge spot,
StockTokenRegistry.spotUsdX18(stock), if non-zero and within ±20% (STOCK_SPOT_MAX_DEVIATION_BPS= 2,000) of the stored snapshot. - Else the stored snapshot, if no older than 5 days.
- Else the call reverts
StalePrice().
| Feed | Max age | Fallback |
|---|---|---|
| ETH/USD | 25 h (CRYPTO_ORACLE_MAX_AGE) | last synced snapshot, while its round is at most 24 h old (USD_SNAPSHOT_MAX_AGE) |
| USDG/USD | 25 h | none |
| Stock Token / USD | 5 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'supdatedAt, 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'supdatedAt, 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 wallet never holds the Stock Token.
- Sells run the other way with
swapExactInCompositeSell: token → Stock Token → USDG. - The caller supplies the bridge
PoolKey.KhookRouteronly checksStockTokenRegistry.isAllowedBridgeHook(bridgeKey.hooks). The app passesbridgeKey(stock). minAmountOutguards the final output. Each leg takes its own sqrt price limit.- A wallet that already holds the Stock Token can call
swapExactInon 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
feefield of itsPoolKey. 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)andrailStockToUsdg(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 itsdistributestays permissionless. KhookBuyback.executeUsdgswaps the USDG share to ETH throughFeeEthRail, 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
| Term | Meaning |
|---|---|
| Price | Quote per token, from sqrtPriceX96 (pool) or virtual reserves (curve). |
| Market cap / FDV | Price × 1B supply, in USD via Chainlink ETH/USD, the Stock Token's Chainlink feed, or USDG/USD. |
| Liquidity | TVL in USD near spot. Thin books still move a lot per trade. |
| Slippage | If spot moves more than this % before inclusion, the swap reverts. |
| Price impact | How 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.
- wallet → generic router
- skips hook accounting, or reverts
- wallet → KhookRouter
- fees and modules run
| Function | Use |
|---|---|
swapExactIn | Single hooked pool, paying in the pool's quote currency. |
swapExactInComposite | Bridge leg (canonical Stock/USDG pool, or an ETH ↔ USDG pool) then the hooked launch leg, one unlock. |
swapExactInCompositeSell | Token → 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 revertsUnauthorizedBridgeHook. minAmountOutis the slippage guard. AsqrtPriceLimitX96of 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.
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_estimateGasreturns 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.origingets one swap per pool per block. Wait for a swap to land before sending the next one on the same pool. Quote with aneth_callthat does not use the trader astx.origin, so the lock cannot trip the simulation.
Graduation
Classic only. Master already has a pool.
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
BondingLaunchFactoryto 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.
knever 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 numberminQuoteOutchecks andSold.quoteOutlogs.- 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 intoFeeEscrow, 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
The 1% always splits 60 / 10 / 30. Hook tax never uses that split. It fills the pot, then modules.
| 1% base fee | Share | Where it goes |
|---|---|---|
| Creator | 60% | FeeEscrow, BuybackVault if vesting is on, or the hook pot if Creator → Hook is on. |
| $KHOOK | 10% | Buys the launched token and epoch-pushes it pro-rata to live $KHOOK holders. |
| Protocol | 30% | Then 20% ops / 80% native-token buyback. |
The three fee layers
| Layer | Rule |
|---|---|
| Base (1%) | Mandatory. Always 60% creator / 10% $KHOOK / 30% protocol. The 10% $KHOOK slice cannot be removed or rerouted at launch. |
| Hook tax | Optional 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-Snipe | Temporary 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.
| Swap | Fee basis | When |
|---|---|---|
| Buy, exact input | The quote you pay | beforeSwap, out of that amount. The pool swaps the rest. |
| Sell, exact output | The quote you receive | beforeSwap. The pool pays out your amount plus the fee. |
| Sell, exact input | The quote the pool pays for your tokens | afterSwap. You receive it minus the fee. |
| Buy, exact output | The quote the pool charges for your tokens | afterSwap. You pay it plus the fee. |
- exact-input buy
- exact-output sell
- fee on the specified quote
- exact-input sell
- exact-output buy
- fee on the quote leg that executed
- 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.
KhookRouterandBalancedAggregatorsend 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.
| Slice | Quote | Where it goes |
|---|---|---|
| Base 1% | 0.010 ETH | 0.006 creator · 0.001 $KHOOK drop · 0.003 protocol |
| Hook tax 2% | 0.020 ETH | 0.016 burn buyback (Auto-Burn) · 0.004 FloorVault |
| Trader pays | 1.000 ETH | Receives 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.
| Slice | Quote | Where it goes |
|---|---|---|
| Base 1% | 0.010 ETH | 0.006 vests (creator cut) · 0.001 $KHOOK drop · 0.003 protocol |
| Hook tax 5% | 0.050 ETH | 0.050 vests in BuybackVault (100% Hook → Creator) |
| Total vesting | 0.056 ETH | 5.6% of the buy. Claim after the time / FDV unlock. |
| Trader pays | 1.000 ETH | Receives 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 inafterSwap. 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.
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.
| Destination | When | How to collect |
|---|---|---|
FeeEscrow (default) | Neither Buyback Vesting nor Creator → Hook | MasterLaunchHook.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. |
BuybackVault | Buyback Vesting is on | Time 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 pot | Creator → Hook is on | The 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
| Module | What it does |
|---|---|
| Anti-Snipe | Decay 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-MEV | Same-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 Tx | Caps a single swap at 0.1%–2.5% of total supply. Fixed at launch. Oversized swaps revert. Exact-output sells are rejected. |
| Backed Floor | Quote vault + ratchet redeem price. Every swap can lift the floor, and the floor never moves down. More volume, higher floor. |
| Deepen LPs | A share of hook tax minted back into the launch LP range as extra liquidity. A deeper book for whales and traders. |
Tokenomics
| Module | What it does |
|---|---|
| Auto-Burn | A share of hook tax buys the token from its own pool and burns it after each swap. A failed nested buy stays queued. |
| NFT Strategy | ETH 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 Vesting | The 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
| Module | What it does |
|---|---|
| Holder Airdrop | Every 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 → Creator | A 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 → Hook | Routes 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
| Module | What it does |
|---|---|
| Fixed Fees | Flat 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 Fees | Hook 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:
| Revert | Cause |
|---|---|
HookTaxTooHigh | Hook tax above 900 bps (9%). |
TotalFeeTooHigh | Base + hook tax above 1,000 bps (10%). |
OpenFeeTooHigh | Base + hook tax + initial snipe tax above 10,000 bps. |
SnipeTaxTooHigh | Initial snipe tax above 9,900 bps. |
AntiSnipeWindowTooShort / AntiSnipeWindowTooLong | Anti-Snipe on with a window outside 1–3,600 s. |
MaxTxTooLow / MaxTxTooHigh | Max Tx outside 10–250 bps. |
FeeRouteIncomplete | The pot is funded and the shares do not sum to 10,000 bps. |
FeeRouteTooHigh | The shares sum above 10,000 bps. |
HookFundingRequired | Shares are set but there is no hook tax and Creator → Hook is off. |
CreatorShareConflict | Creator → Hook and Buyback Vesting together. |
BuybackVestingTooShort / BuybackVestingTooLong | Vest duration outside 7 days–5 years. |
HolderAirdropEpochTooShort / HolderAirdropEpochTooLong | Airdrop epoch outside 60 s–7 days. |
DynamicFeeMinTooLow / DynamicFeeRangeInvalid | Dynamic min total below 1%, or less than 0.10% under the max total. |
NftStrategyExclusive | NFT 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.
Buys only. After T only the 1% base and the hook tax remain.
Example: 1 ETH buy, 5 s window, 98% open tax.
| When | What happens |
|---|---|
| First second | +0.98 ETH snipe on top of the 1% base. The sniper pays ~1.99 ETH in. |
| After 5 s | Snipe is 0. The same 1 ETH buy pays only 0.01 ETH base. |
| Where the 0.98 goes | 60% creator · 10% $KHOOK drop · 30% protocol. |
Parameters
| Parameter | Value |
|---|---|
| Initial tax | Wizard default 98%. Slider 1%–99%. Contract fallback if unset: 50%. Max 9900 bps. |
| Window | 1–3600 seconds, enforced at launch: 0 reverts AntiSnipeWindowTooShort, above 3,600 reverts AntiSnipeWindowTooLong. Wizard default 5 seconds. |
| Cap | Base 1% + hook tax + snipe ≤ 100% at open. Steady fee (after decay) still 1% + hook tax ≤ 10%. |
| Exact-output buys | Rejected 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 buy | The creator's launch-time dev buy is exempt from the tax. |
Formula
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.
Blocks are Robinhood Chain L2 blocks (ArbSys.arbBlockNumber). The lock is per pool and per origin.
Example: Alice in one block.
| Robinhood Chain block | Swap | Result |
|---|---|---|
| 100 | Buy 1 ETH | Allowed. |
| 100 | Sell | Reverts SandwichBlocked. |
| 101 | Sell | Allowed. 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:
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).
Pick the cap at launch, from 0.10% to 2.50% of supply.
Example: 1B supply, 1% max tx = 10M tokens.
| Swap | Result |
|---|---|
| Buy 8M tokens | Goes through. |
| Buy 12M tokens | Reverts. One swap cannot eat more than the cap. |
What the cap measures
| Swap | Measured as |
|---|---|
| Buy, exact input | The quote after fees, converted at the pre-swap spot. Price impact only lowers the real fill, so the check never under-counts. |
| Buy, exact output | The tokens requested. |
| Sell, exact input | The tokens sold. |
| Sell, exact output | Rejected: 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,
KhookRouterandBalancedAggregatoronly 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.
P_floor = vault quote ÷ circulating supply. Redeeming burns tokens and pays quote; holders keep the new floor.
Formulas
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.
FloorVault.redeemFloor(token, amount). Burns the tokens, pays quote, rounds down. The remaining holders keep a floor that never decreases.
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.
One exact-input sell, filled in two legs.
| Spot before the sell | What happens |
|---|---|
| Above the floor, the sell does not reach it | A normal swap. |
| Above the floor, the sell would cross it | The pool buys the tokens that take the price down to P_floor, at market. The rest fills at P_floor. |
| At or below the floor | The 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, inafterSwap. - Logs:
FloorFill(poolId, tokenIn, quoteOut)for the floor leg only, withquoteOutnet of the fee, and a normalSwapfor the market leg. Each leg logs its ownFeesDistributed. - Exact-output sells keep hookit's rule: a sell that would cross fills whole at P_floor. The k'hook app and
KhookRoutersend 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.
Same trade size, less price movement after deepening.
Example: 2% hook tax, 100% to Deepen LPs.
| Volume | Depth added |
|---|---|
| 1 ETH buy | 0.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 inafterSwap. - 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 inpendingDeepenTokens[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
DeepenFailedand 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.
beforeRemoveLiquidityblocks 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 + pendingDeepenLpsis the whole budget. The token page shows both. Read the carried tokens withMasterLaunchHook.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.
Hook tax bought these tokens and burned them.
Example: 2% hook tax, 80% to Auto-Burn.
| Volume | Burned |
|---|---|
| 1 ETH buy | 0.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 inafterSwap. - 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.
Example: 1 ETH of hook fees, floor at 0.035 ETH.
| Step | What happens |
|---|---|
| Harvest | The 1 ETH moves into the collection's vault, credited to this token. |
| Cap | The keeper posts ~0.037 ETH (floor + 5%). A sweep never pays more than that per NFT bought. |
| Sweep | The cheapest listings under the cap: about 28 NFTs for 1 ETH. |
| Raffle | Each NFT is drawn among holders. Hold 1% of the tickets, get a 1% chance per draw. |
| Burn | Each 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
| # | Stage | What happens |
|---|---|---|
| 01 | Launch | The creator picks a collection and raffle or burn. Both are final. ETH pair, Anti-MEV on. LaunchFactory.launchWithNftStrategy(params, collection). |
| 02 | Trade | Every 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. |
| 03 | Harvest | Anyone calls harvest(token). The NFT share moves into the collection's vault. |
| 04 | Sweep | The 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.
| Exit | What happens |
|---|---|
| Raffle to holders | Drawn among the token's holders. It goes from the vault straight to the winner's wallet. |
| Burn the NFT | Anyone calls burn(). The NFT goes to the dead address. Gone for good. |
Dead address: 0x000000000000000000000000000000000000dEaD. Nobody holds its key.
Vault rules
| Rule | What it means |
|---|---|
| No withdraw | ETH only leaves the vault through a sweep. NFTs only leave through a burn to the dead address or a raffle claim. |
| Keeper-only sweep | Only 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 cap | Spend ≤ 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 isolation | Raffle credit only buys raffle NFTs and burn credit only buys burn NFTs. One token cannot spend another's ETH. |
| Attribution | Each 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 donations | The vault rejects plain ETH except the Seaport refund. NFTs sent to it by hand are not tracked. |
| Auto-Burn share | 0 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.
| # | Stage | What happens |
|---|---|---|
| 01 | Snapshot | Holders 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. |
| 02 | Challenge | 15 minutes for anyone to check the published list against its Merkle root. |
| 03 | Draw | The 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. |
| 04 | Claim | The 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.
requestDrawrecordsArbSys.arbBlockNumber()and the draw reads the hash of the block 5 later withArbSys.arbBlockHash(n). At about 0.1 s per block, that block lands roughly half a second later. PREVRANDAOis constant (1) on Robinhood Chain and is never used.arbBlockHashonly 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
Checked by the vault on its own balance before and after the call. Also spent ≤ the funding token's credit for that outcome.
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.
Tickets are whole tokens held at the snapshot.
Contracts
| Contract | Job |
|---|---|
NftSweeperRegistry | Registry and fee router. Lists collections, deploys one SweepVault per collection, registers launches and harvests fees. |
SweepVault | One per collection. Holds the ETH and the NFTs, enforces the rules above. |
NftSweepRaffle | Merkle 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.
Example: 1 ETH buy, 5% hook tax, 100% Hook → Creator.
| Slice | What 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 locked | 0.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 15 | Half 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
| Mode | Rule |
|---|---|
| Time vest | Linear unlock from 7 days to 5 years. Claim the unlocked slice on the token page. A duration of 0 means 5 years. |
| Until FDV | Cliff 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. |
| Hold | observeFdv 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. |
| Ratchet | The 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 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, alsohighWaterFdvUsd),fdvWindowStart(token)andfdvWindowMinUsd(token).FdvObservedis 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.
Quote is split to holders of that token, pro rata.
Example: 2% hook tax, 50% to airdrop, you hold 2% of supply.
| Volume | Payout |
|---|---|
| 1 ETH buy | 0.01 ETH into the vault this swap. |
| Your payout | 2% × 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
| Rule | Value |
|---|---|
| Time window | Default epoch 15 minutes. Min 60 seconds, max 7 days. The next swap after the epoch can push a batch (tryAutoAirdrop). |
| Until FDV | Keep 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. |
| Hold | Same 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 set | On-chain. LaunchToken.holderTracker = HolderAirdropVault; every transfer calls syncHolder. Not supplied by the indexer. |
| Payout | Uniswap 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) andpotOf(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
tryAutoAirdropwith no payout running compacts those slots, up to 48 per call.deferredRemovalCount(token)counts them, andholderList/holderCountinclude 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,KhookDropVaultand the zero address. The manualairdrop(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.
The quote pot for this epoch × the wallet's balance of the launched token over circulating supply (exclusions applied).
Redeem your claims
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.
Example: 1 ETH buy, 2% hook tax.
| Split | Result |
|---|---|
| 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
BuybackVaultinstead ofFeeEscrow. - 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).
Example: 1 ETH buy, no hook tax, Creator → Hook on.
| Volume | Result |
|---|---|
| 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.
A flat extra hook tax on every swap, quote only. 1 ETH in, 0.97 ETH of tokens out.
Example: 2% fixed hook tax.
| Volume | Result |
|---|---|
| 1 ETH buy | Pays 1 ETH. Receives 0.97 ETH worth of tokens (0.01 base + 0.02 hook tax). |
| Sell for 1 ETH | The pool pays 1 ETH for the tokens. The seller receives 0.97 ETH. Same 3%, on the quote out. |
| 10 × 1 ETH buys | 0.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.
c / σ is the trade's share of the in-range book.
Example: 10 ETH in-range depth, extra tax 1% → 9%.
| Trade | Result |
|---|---|
| Retail 0.2 ETH | Uses 2% of the book. Extra ≈ 1.16%. Pays ~0.002 ETH hook tax + 0.002 ETH base. |
| Whale 5 ETH | Uses 50% of the book. Extra = 5%. Pays 0.25 ETH hook tax + 0.05 ETH base. |
| Clip the whole book | Extra = 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
| Symbol | Meaning |
|---|---|
n | Quote notional of this swap: the quote you send on a buy, the quote the pool pays out on a sell. |
d | In-range quote depth in the trade direction, read before the swap. |
σ | The depth-saturation fraction set at launch (default 100% of in-range depth). |
τ_hook | Added 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.
Swap fee
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.
0 after the launch window T. Linear decay from the initial tax τ0.
Mandatory. Applied to the 1% base and to the snipe take. Hook tax never uses this split.
Dynamic hook tax
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.
σ is the depth-saturation fraction set at launch (default 100% of in-range depth).
No oracle. Empty depth stays at τ_min so a first buy does not 100% revert.
Uniswap spot
Quote per token if the launch token is currency0. Invert if it is currency1.
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
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.
Classic curve
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:
G is the graduation target (4.2 ETH-eq), S_curve = 800M, S_lp = 200M (BondingMath.virtualReserves).
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.
Or the same USD value in USDG / a Stock Token, fixed at launch. 20% of supply seeds full-range LP.
$KHOOK holder drop
Mandatory. Quote volume × base fee × holder share. Buys the launched token, not $KHOOK.
Live balances. LP and protocol sinks are excluded from the weight.
Protocol pot
Operating wallet.
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)
The per-block counter for Anti-MEV. block.number is an L1 estimate on this chain.
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.
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.
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
| Field | Value |
|---|---|
| Ticker | $KHOOK |
| Status | Live on Robinhood Chain |
| Network | Robinhood Chain |
| Chain ID | 4663 |
| Supply | 1,000,000,000 |
| Decimals | 18 |
| Standard | Uniswap v4 hooked Master |
| Token contract | — |
| Master launchId | — |
| Pool | Uniswap v4 · MasterLaunchHook · paired with ETH |
| Modules | Anti-MEV, Anti-Snipe 60s, Creator → Hook, Auto-Burn 80%, Deepen LPs 20% |
Tokenomics
| Item | Detail |
|---|---|
| Role | The 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 cut | Mandatory. 10% of every 1% base fee, on every hooked pool. Not a module. Not optional. You cannot launch without it. |
| Buyback | 80% 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. |
| Payout | Batched each epoch (default 15 minutes, 48 holders per push). Never paid inside the swap itself. |
Quote volume of a pool × base fee × holder share. Spent on that pool's token.
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 paid | Live $KHOOK holders | Holders of that launched token |
| What they get | The launched token | Quote (ETH / USDG / Stock Token) |
| Funded by | 10% of the 1% base | A % of the hook-tax pot |
| Toggle | None, baked into the 1% base | Packed at launch |
How the drop actually runs
- The hook credits
KhookDropVaulton each swap: 0.10% of quote, spent on that pool's token. The buy runs inafterSwap. A failed buy stays queued inpendingKhookDrop[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'ssweepKhookDropbuys the token and credits the vault. tryPushruns 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
Transferlogs / the indexer, then callssyncHolders+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
tryPushwith 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.executeis keeper-run, because the caller sets the minimum output. - USDG revenue reaches
KhookBuybackas USDG.KhookBuyback.executeUsdgswaps it to ETH throughFeeEthRail, then runs the same buy and burn. Operator-only, likeexecute: 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 route | Serves |
|---|---|
/api/indexer/health | Head, lag, last poll error |
/api/indexer/v1/tokens | Catalog + markets[] + 24h windows |
/api/indexer/v1/tokens/:address/trades · /candles | Trades and candles. Candles are 5m by default, 1m available |
Indexer 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| Route | Returns |
|---|---|
/health | { head, lagBlocks, lastPollError } |
/v1/protocol/stats | { launches, volumeUsd24h, volumeUsdAll, feesUsdAll, khookDropUsdAll, khookBurned, floorTvlUsd, tokens24h } |
/v1/protocol/series | One point per rolling 24 h window, oldest first: volume, fees, trades, launches, $KHOOK drops. |
/v1/tokens | Paged 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/:address | One TokenSummary, scoped to poolId for multi-pair. |
/v1/tokens/:address/trades | Trades, newest first. |
/v1/tokens/:address/holders | Holder ranks. |
/v1/tokens/:address/candles | Market-cap candles. |
/v1/feed | Latest launches and trades across the protocol. |
/v1/wallets/:address/holdings | A 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/collections | NFT Strategy collections listed on NftSweeperRegistry, with vault, floor and NFTs held. |
- The token summary includes
markets[],marketCount,bondingPhase,realQuote,graduationQuote, decodedmodules,windows(5m / 1h / 6h / 24h) anddevBuy*. - Candles default to 5m. Pass
interval=1m,10m,15mor1h. Empty buckets forward-fill the last close. The chart is mcap-based and scoped topoolId. /healthexposeshead,lagBlocks,lastPollError. Block numbers are Robinhood Chain blocks. At about ten blocks per second,lagBlocks: 50is about 5 s behind.
// 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).
| Field | Value |
|---|---|
| Network | Robinhood Chain |
| Chain ID | 4663 (0x1237) |
| Gas | ETH |
| RPC | https://rpc.mainnet.chain.robinhood.com |
| Explorer | https://robinhoodchain.blockscout.com (opens in a new tab) |
| Quotes | ETH, USDG, Stock Tokens |
| Supply | 1,000,000,000 (both rails) |
| Master start FDV | ~$5,000 |
| Classic graduate | ~4.2 ETH equivalent |
Add the network
{
"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
| Topic | On Robinhood Chain |
|---|---|
| Stack | Arbitrum Nitro. ETH pays gas. |
| Blocks | About one every 0.1 s at the time of writing. RPC and explorer block numbers are Robinhood Chain blocks. |
block.number | Inside 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 hashes | ArbSys.arbBlockHash(n) for the last 256 Robinhood Chain blocks. |
PREVRANDAO | Constant (1). Never used as randomness. |
| Timestamps | Whole seconds. About ten blocks share each second. |
| Gas used | Receipts include an L1 data-posting component on top of execution gas. |
| Oracles | Chainlink. 24 h heartbeat, 0.5% deviation. Stock Token feeds update 24/5. |
Testnet
| Field | Value |
|---|---|
| Network | Robinhood Chain Testnet |
| Chain ID | 46630 |
| RPC | https://rpc.testnet.chain.robinhood.com |
| Explorer | https://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
| Contract | Role | Address |
|---|---|---|
LaunchFactory | Active Master launches | — |
LaunchFactoryQuery | Paginated launch index | — |
BondingLaunchFactory | Classic rail | — |
MasterLaunchHook | Master pools: quote-only fees + modules | — |
GraduatedFeeHook | Graduated Classic pools | — |
KhookRouter | Required for hooked swaps | — |
BalancedAggregator | PAIR-style USDG multi-market splits | — |
StockTokenRegistry | Canonical Stock/USDG bridge pools | — |
ProtocolRevenueDistributor | 20% ops / 80% buyback | — |
FeeEthRail | Stock Token → USDG, USDG → ETH | — |
KhookBuyback | Keeper execute / executeUsdg → buy and burn $KHOOK | — |
V4ClaimsRedeemer | Redeem Holder Airdrop ERC-6909 claims | — |
LiquidityLocker | Holds graduated Classic LP | — |
NftSweeperRegistry | NFT Strategy registry and fee router | — |
NftSweepRaffle | NFT Strategy raffles | — |
Vaults
Deployment-time values. The hook's getters win.
| Vault | Hook getter | Address |
|---|---|---|
FloorVault | floorVault() | — |
FeeEscrow | feeEscrow() | — |
BuybackVault | buybackVault() | — |
HolderAirdropVault | holderAirdropVault() | — |
KhookDropVault | khookDropVault() | — |
Native token
| Token | Address | Launch |
|---|---|---|
| $KHOOK on Robinhood Chain | — | Master launchId — |
Uniswap v4 on this chain
| Contract | Address | Note |
|---|---|---|
| PoolManager | 0x8366a39CC670B4001A1121B8F6A443A643e40951 | Every k'hook pool lives here. |
| StateView | 0xF3334192D15450CdD385c8B70e03f9A6bD9E673b | getSlot0, getLiquidity. |
| V4 Quoter | 0x8Dc178eFB8111BB0973Dd9d722ebeFF267c98F94 | Quote bridge legs live. |
| Universal Router | 0x8876789976dEcBfCbBbe364623C63652db8C0904 | Not used for hooked k'hook pools. |
Quotes and oracles
| Asset | Address | Note |
|---|---|---|
| Stable quote: USDG | 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 | Global Dollar, 6 decimals. |
| WETH | 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73 | For bridge pools that hold WETH. |
| ETH/USD: Chainlink | 0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9 | 8 decimals. Accepted up to 25 h old. |
| Stock Tokens | StockTokenRegistry.stocks() | The listed set. |
| Stock Token feeds | LaunchFactory.quoteConfigs(stock) | One Chainlink USD feed per stock. |
Other
| Contract | Address | Note |
|---|---|---|
| Seaport 1.6 | 0x0000000000000068F116a894984e2DB1123eB395 | The only target NFT Strategy sweeps can call. |
| ArbSys | 0x0000000000000000000000000000000000000064 | arbBlockNumber(), 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.
| Stream | Logs |
|---|---|
| Launch | TokenLaunched · MarketLaunched · Graduated |
| Trade | PoolManager.Swap · Bought / Sold |
| Flywheel | KhookDropVault.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.UsdgConvertedprecedes 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.
// 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:
| Event | Meaning |
|---|---|
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
senderis the router (KhookRouter,BalancedAggregator), not the wallet. Use the transaction'sfromfor the trader.amount0/amount1are 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.FeesDistributedin the same transaction carries the split.- Fee logs can follow the
Swap. For exact-input sells and exact-output buys,FeesDistributed(Master) orFeesAccrued(graduated Classic), and the vault deposits it triggers, are logged after the pool'sSwap. Pair fees with swaps by transaction, not by log order. - Swaps whose
senderisMasterLaunchHookare 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
FloorFillfor its floor leg and aSwapfor its market leg, each with its ownFeesDistributed. A sell filled wholly at the floor logsFloorFilland aSwapwith zero amounts. - A composite trade logs two swaps: the bridge pool, then the launch pool.
List Master launches (viem)
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.
| Integer | Holds |
|---|---|
launchId | Token, pool, creator, quote. |
bitmask | Modules + tax + caps. |
vestPacked | Buyback 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.
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
| View | Returns |
|---|---|
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)
| Bits | Field |
|---|---|
| bit 0 | ANTI_SNIPE |
| bit 1 | BACKED_FLOOR |
| bit 2 | ANTI_MEV |
| bit 3 | MAX_TX |
| bit 4 | HOOK_TO_CREATOR |
| bit 5 | DYNAMIC_FEES |
| bit 6 | BUYBACK_VESTING |
| bits 7-22 | hookTaxBps |
| bits 23-38 | antiSnipeDurationSeconds |
| bits 39-54 | maxTxBps |
| bits 55-70 | hookToCreatorBps |
| bits 71-94 | floorAllocationBps |
| bits 95-110 | initialSnipeTaxBps |
| bit 111 | AUTO_BURN |
| bit 112 | DEEPEN_LPS |
| bits 113-128 | autoBurnBps |
| bits 129-144 | deepenLpsBps |
| bit 145 | HOLDER_AIRDROP |
| bits 146-161 | holderAirdropBps |
| bit 162 | CREATOR_SHARE_TO_HOOK |
| bits 163-194 | buybackVestingDurationSeconds |
| bits 195-210 | dynamicFeeMinTotalBps |
| bits 212-227 | dynamicFeeDepthSaturationBps |
| bits 228-259 | holderAirdropEpochSeconds |
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
holderAirdropEpochSecondskeeps its low 28 bits. The 7-day maximum (604,800 s) fits. - A zero field with its flag set means the default:
initialSnipeTaxBps5,000;buybackVestingDurationSeconds5 years;dynamicFeeMinTotalBps100;dynamicFeeDepthSaturationBps10,000;holderAirdropEpochSeconds900. antiSnipeDurationSecondshas 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)onMasterLaunchHook.nftStrategy()returns 10,000.
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:
| Bits | Field |
|---|---|
| 0-1 | kind: 0 time, 1 cliff, 2 steps |
| 2-33 | durationSeconds |
| 34-36 | cliffPreset |
| 37-39 | stepCount (≤ 6) |
| 40 + 11·i | step i: preset (3 bits), then pct (8 bits) |
| Preset | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 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.
Classic on the curve uses virtual reserves instead of sqrtPriceX96.
Read pool price from StateView
client is the Robinhood Chain client from Onchain events.
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:
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.
| Quote | FX source | Max age |
|---|---|---|
| ETH | Chainlink ETH/USD, 0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9, 8 decimals, 24 h heartbeat, 0.5% deviation | 25 h; then the last synced snapshot, up to 24 h after its round |
| USDG | Chainlink USDG/USD (USDG ≈ $1) | 25 h |
| Stock Token | Its Chainlink USD feed: multiplier-adjusted price per token, updates 24/5 | 5 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
| Risk | Meaning |
|---|---|
| Zero | Most tickers go to nothing. |
| Copycats | Verify the contract every time. |
| Thin book | The 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()istrue. 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 revertStalePrice(), 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
StockTokenRegistrystops 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.
StockTokenRegistrylistings, 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,
KhookBuybackandGraduatedFeeHook, 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) andProtocolRevenueDistributor(the Stock Token → USDG rail, the only way Stock Token revenue leaves it:distributerefuses 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,FloorVaultorHolderAirdropVault. 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
| Contract | Powers | Can it take user funds? | Effect on existing launches |
|---|---|---|---|
LaunchFactory | setLaunchFee (no upper bound), setTreasury, setQuote (allow, decimals, snapshot, feed), setEthUsdPrice, setEthUsdFeed, setSequencerUptimeFeed, the custom-hook switches and allowlist, setNftStrategy | No. 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. |
BondingLaunchFactory | setLaunchFee, setTreasury, setQuote, setEthUsdPrice (and feed), setSequencerUptimeFeed, setKhookDropVault | No. 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. |
MasterLaunchHook | setFactory, setAirdropVault, setKhookDropVault, setNftStrategy, setArbExecutor, setArbActive | No. 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. |
GraduatedFeeHook | setFactory (new registrations), setKhookDropVault, setOperator | No. 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. |
FeeEscrow | setOperator; 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. |
FloorVault | setOperator; as operator, setQuote, depositInternal (unbacked), deposit (funded), drawForFloor | Yes: Backed Floor reserves. | Can break Backed Floor fills and redemptions. |
BuybackVault | setOperator; as operator, configurePlan, observeFdv (any FDV), creditInternal (unbacked), credit (funded) | Yes: creators' vesting balances. | Can unlock or freeze any FDV plan. |
HolderAirdropVault | setOperator; as operator, setExcluded, configureEpoch, configurePlan, observeFdv, depositInternal (unbacked), deposit (funded) | Yes: airdrop pots. | Can exclude holders, and unlock or freeze plans. |
KhookDropVault | setOperator, 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. |
ProtocolRevenueDistributor | setOperator, setOpsTreasury, setNativeToken, setFlywheelMode, setFeeRail, setBuybackExecutor | Protocol 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. |
KhookBuyback | setOperator, 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. |
FeeEthRail | setEthBridge (any USDG/ETH pool with an allowed hook) | Protocol conversions only. | None. |
StockTokenRegistry | list, delist, setBridgeKey, setBridgeHookAllowed | No. | 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 days | Yes, 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.
| Contract | Powers | Can it take user funds? | Effect on existing launches |
|---|---|---|---|
ProtocolRevenueDistributor | notifyInternal / 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. |
KhookBuyback | execute, executeUsdg (it picks minEthOut and minTokensOut) | The protocol buyback pot, by sandwiching its own buys. | None. |
GraduatedFeeHook | sweepKhookDrop (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
| Role | Powers | Can it take user funds? | Effect on existing launches |
|---|---|---|---|
| Anyone | finalizeDraw, 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, graduate | No. distribute of a listed Stock Token reverts StockTokenNeedsRail: that revenue waits for the operator's conversion to USDG. | None. |
| Deployer, after hand-off | No 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). |
| Creator | Claims its own fees; chooses the NFT outcome before launch | No. 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
| Party | Powers | Effect |
|---|---|---|
| Robinhood Chain sequencer | Transaction ordering (first come, first served) and the L2 block hashes behind raffles | Can bias raffles. No sequencer-uptime feed exists for the chain. |
| Chainlink | ETH/USD, USDG/USD and Stock Token feeds | Launch sizing, graduation targets and FDV prints. |
| Stock Token issuer | Pause, 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 only | Meaning |
|---|---|
| No custody | The site never holds keys. |
| No advice | Not a listing or a vet. |
| No refunds | Launch 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
| Change | Why | Log |
|---|---|---|
| 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
| Change | What was wrong | Log |
|---|---|---|
| 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,StockTokenRegistryand the NFT Strategy vaults, bring their own. FeesDistributedandFeesAccruedcan now follow the pool'sSwap. 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.