Everything the contracts actually do, and every number they enforce. If something here disagrees with the code, the code is right — start at contracts/src/libraries/PoolpadSchedule.sol.
A token launcher built around its own Uniswap v4 hook. A launch is a single transaction: the factory deploys an ERC-20 with a fixed supply of 1,000,000,000, opens a v4 pool paired against native ETH, deposits the whole supply as a single-sided position, and attaches a hook that prices every subsequent swap.
There is no bonding curve and no graduation. The pool a token launches into is the pool it trades in forever. There is also no ETH seed requirement — the position is entirely token-side, so the creator brings nothing but gas.
Calling createToken does all of this atomically, in this order:
1 deploy PoolpadToken fixed 1e9 supply, minted to the factory
2 hook.poolpadRegister(...) arms the policy before the pool exists
3 feeLocker.registerLaunch() records creator + which hook may bill this token
4 poolManager.unlock()
├ initialize(key, sqrtP) opens at tick 239_520, the top of the range
├ modifyLiquidity(+L) the entire supply, single-sided
├ settle() pays the pool its token side
├ swap() the optional dev buy, tax free
└ transfer(dust → 0xdEaD) rounding remainder, so the factory holds nothingThe LP fee is zero deliberately. Fees there would accrue to a position nobody can ever collect from, destroying value silently on every trade. The hook's tax is the only fee in the system.
The creator picks one base rate between 1% and 10%. The hook then reads a per-token trade counter on every swap and cycles that base rate against a fixed table, rather than charging one number on everything.
The counters are global per token and shared by every wallet — a buy from one address advances the same counter as a buy from another. They never reset. Tables below show a 5% base rate.
| buy | Rate | Paid to |
|---|---|---|
| 1 | 5% base | Creator |
| 2 | 5% base | Creator |
| 3 | 5% | Creator |
| 4 | 4% | Creator |
| 5 | 3% | Creator |
| 6 | 2% | Creator |
| sell | Rate | Paid to |
|---|---|---|
| 1 | 5% base | Creator |
| 2 | 5% base | Creator |
| 3 | 6% | Creator |
| 4 | 7% | Treasury |
| 5 | 5% | Treasury |
| 6 | 4% | Creator |
| 7 | 3% | Creator |
| 8 | 2% | Creator |
Two flat rates override the cycle. They are checked in this order, before the schedule:
Neither override consumes a position in the honest cycle. If they did, the first real buyer would land on whatever tier the bots happened to leave behind.
The whitelist is checked against both the calling contract and tx.origin. Traders reach a pool through a router, so a whitelist keyed only on the caller would exempt everybody or nobody; tx.origin is the one identity in a snipe that cannot be borrowed. A smart-contract wallet whitelists its own address.
Uniswap v4 keys a position to the address that created it, so a position cannot be minted to a burn address the way a v3 NFT can. Robinhood Chain also has no v4 periphery, so there is no position NFT in the first place.
The lock is therefore structural rather than ceremonial. The factory owns the position and contains exactly one modifyLiquidity call site, whose liquidity delta is a positive value derived from constants. There is no negative-delta path, no admin function, no upgrade hook and no arbitrary-call function anywhere in the contract. The launch emits LiquidityLockedForever with the position key so the position can be read back from the pool manager directly.
| Flow | When | Rate | Destination |
|---|---|---|---|
| Buy cycle | every buy outside the snipe window | base, 5%, 4%, 3%, 2% | Creator |
| Sell cycle 1–3, 6–8 | every sell after the cooldown | base, 6%, 4%, 3%, 2% | Creator |
| Sell cycle 4–5 | every 8-trade cycle | 7% and 5% | Treasury |
| Sell cooldown | first 5 sells | 30% | Creator |
| Anti-snipe | first 5s, not whitelisted | 60% | Treasury |
| Launch fee | — | 0 | — |
| LP share retained | — | 0 | — |
All of it is collected and paid in ETH, on both sides of the trade, whichever way the pool is ordered. A creator never receives their own token as revenue, so claiming cannot move their own price. Withdraw any time with PoolpadFeeLocker.claimFees(token) — it is permissionless to call and always pays the recorded creator, so a third party can cover the gas.
The locker holds ERC-6909 claims rather than ETH. On a buy, the trader's ETH is not settled when the hook runs, so taking real ETH there reverts against an empty pool manager. Minting claims resolves the hook's balance without moving anything, and they are redeemed for ETH in the claimant's own transaction. It also means no router is required to settle before swapping.
A creator can launch against a hook other than the default one. What makes that safe is not a review process — it is that Uniswap derives a hook's powers from its own address. The low 14 bits are the permission manifest, and the factory refuses any hook whose bits are not exactly:
0x00CC = BEFORE_SWAP | AFTER_SWAP
| BEFORE_SWAP_RETURNS_DELTA | AFTER_SWAP_RETURNS_DELTA
no liquidity flags · no initialize flags · no donate flagsA hook carrying any liquidity permission cannot be attached at all, so a custom hook can price swaps and nothing else. The worst a hostile one can do is charge badly — and that is visible in previewRate before anybody trades.
Hook Studio generates hooks that extend an audited base contract holding all the v4 accounting, so a generated file contains only its rate policy and its rates are compiled in as constants. Every build is really compiled, really tested against a real pool manager, and scanned for selfdestruct, delegatecall, inline assembly, contract creation, disallowed imports and any state-changing function outside the hook interface.
Nothing here needs to be taken on trust. The hook's permissions are in its address; the locked position is readable from the pool manager; the schedule is one short file.
# the hook can only price swaps — the low 14 bits say so
python3 -c "print(hex(int('0x69bE04D99A0141D6C87c2E5Be8c4F8Bb62CDc0cC', 16) & 0x3fff))"
# -> 0xcc
# the launch position exists and is owned by the factory
cast call 0x8366a39CC670B4001A1121B8F6A443A643e40951 \
"getPositionLiquidity(bytes32,bytes32)(uint128)" <poolId> <positionKey>
# the whole suite, including tests against the live v4 singleton
cd contracts && forge testPoolpad is unaudited. It has a test suite, some of which runs against the real Uniswap v4 singleton on Robinhood Chain, but no external party has reviewed it.