Launch a pool
launchPool in one transaction — or the three standalone steps, your choice.
One entry does the whole thing: launchPool initializes the pool on the PoolManager, declares the pot's roles and creates the LP program with its seed liquidity — atomically, in one transaction. The three standalone steps still exist for pools that want them separately (or want no program at all).
The one-transaction launch
The caller becomes the pot admin — exactly as if they had called PoolManager.initialize themselves — then the initPot and addLiquidityAdvanced bodies run with the same validation, events and funding rules as the standalone entries. It reverts if the pool already exists.
launchPool takes the FULL ProgramConfig — the same struct addLiquidityAdvanced takes. Set it here and the machine is complete from the first trade: fees compound, the pot self-funds from the buyback share, the burn burns — no second transaction, no window where the pool trades with the split at zero. A zeroed config is a plain LP position that keeps everything for you until the operator edits it later.
Setting up the settings — the config, field by field
Ten fields, validated at write-time, editable later by the operator (unless you surrender the roles). Shares are WAD numbers: 1e18 = 100%.
| field | what it does at launch |
|---|---|
buybackShareWad | the flywheel's fuel line — this slice of secondary-side fees lands in the pot every harvest, so pumping and shielding never depend on donations |
burnShareWad | main-side fees sent down the burn cascade — must be 0 when main is native |
compoundShareWad | both sides — the share that becomes position liquidity again (the autocompound engine) |
potCompoundShareWad / potBurnShareWad | the buyback split: how what the pot BUYS is carved between the LP carry, the burn cascade, and the pot's recipient |
publicHarvest | open the manual harvest to keepers and the community, or keep it owner/operator-only |
secondaryRecipient / mainRecipient | each side's remainder needs a live recipient whenever the shares sum below 100% |
minMain / minSecondary | the auto-harvest trigger — type(uint256).max on both = disarmed, harvests are manual only |
The write-time laws: each side's shares must fit in its own gross (compound + buyback ≤ 100%, compound + burn ≤ 100%, potCompound + potBurn ≤ 100%), a native main rejects burn shares, and every leg that can carry value needs a live recipient. A config that validates at launch keeps validating forever — and the swaps never depend on it: a recipient that starts refusing later just parks its money. Full lever-by-lever depth in Manage your program, proven presets included.
One transaction is also cheaper — and atomic
| path | execution gas | all-in (incl. 21k base per tx) |
|---|---|---|
| launchPool — one transaction | 530,298 | 551,298 |
| the three-step path (3 transactions) | 514,909 | 577,909 |
The launch orchestration costs ~15k extra execution gas but saves two transaction base costs — ~27k cheaper all-in. More importantly it is atomic: a failed step rolls the whole launch back (no pool, no half-configured pot left behind), where the three-step path can strand a pool between transactions with its roles undeclared.
The PoolManager skips hook callbacks when the hook itself is the caller, so beforeInitialize never runs during a launch — and a successful initialize proves the pool was fresh, so the admin slot is provably virgin. launchPool records its own caller as the admin: exactly what the callback would have recorded had the launcher initialized the pool directly. Audited as the LA1–LA10 suite, including the no-spoof corner.
The checklist
address(0), which always sorts as currency0. Pick a non-zero fee tier and a tick spacing, set hooks = 0xb216…60C8. A zero-fee pool would never pump.sqrtPriceX96 is the launch price in V4's Q64.96 square-root format. For a fresh token this IS the market's starting point; for an existing token match the live market or arbitrage will do it for you (at your LP's expense).main must be one of the key's two currencies — the other becomes secondary automatically. A native main must name a live recipient.ProgramConfig (the section above, field by field): the buyback share that self-funds the pot, the compound share, the burn share, the buyback split, the recipients, the auto-harvest trigger. Launching configured means the flywheel turns from the first trade — a zeroed config is just a plain LP until the operator edits it.msg.value and the unused excess is refunded — the attached value is a hard cap.The three-step manual path
Stop after step 2. The pot, the pump and the shield work standalone — the LP program is optional. It can be created later at any time (still admin-only, still one per pool).
After launch
FAQ
What does launchPool do in one transaction?+
Creates the V4 pool with the hook attached, initializes the pot, creates the LP program with YOUR ProgramConfig, and seeds the first liquidity — configured from block one.
Should I use plain addLiquidity or the advanced path?+
Prefer addLiquidityAdvanced (or launchPool with a config): it writes your split rules atomically with the program. Plain addLiquidity is the bare shortcut — zeroed shares, you as owner/operator.
What are the plain addLiquidity defaults?+
The caller becomes owner AND operator (so everything stays editable later), all shares start at zero, and the pot recipient defaults toward burn. Nothing is locked by accident.
Why did the launch revert with BadConfig?+
A side's shares sum above 100%, a burn share on a native main, a value-carrying side without a live recipient, or a malformed liquidity request. All validation is at write-time by design.
Can a pool have more than one LP program?+
No — one program per pool, created once (PotAlreadyReady on a second attempt). Later deposits go through addProgramLiquidity, which tops up the existing position.