documentation

How this works.

Behaviour the contracts enforce, not policy we promise. Where a number is a choice, the choice is named and its limits given; where something is cosmetic, it says so.

How this differs

Four things, each of which changes what a launch can be rather than how it is sold.

Rewards coins are not new and neither is a launchpad that makes them. Taking a tax and paying it to holders is a solved problem with a dozen implementations. So the question worth answering is not whether this pays holders, but what it can pay them, and what has to stay running for it to keep doing so.

All four answers below come from the same place: every launch here deploys its own Uniswap v4 hook, and the hook runs inside the swap rather than alongside it. That section is worth reading first if any of this sounds like it needs a server.

The reward has nothing to do with the pair

Everywhere else these are the same decision. A coin paired against ETH pays ETH, because the fee arrives as ETH and that is the end of it, and the only real choice is which pair you launch into.

Here they are two decisions. The tax is taken on the pair side and then converted, so a coin that trades against USDG can pay its holders NVDA, and a coin paired against TSLA can pay ETH. Twenty-three assets on each side, chosen independently: two hubs, twenty tokenized equities, and ANTHROPICx1L.

That is the part with no equivalent: a memecoin whose holders are quietly accumulating Nvidia every time somebody trades it. Not a promise to buy stock later, and not an index wrapper. The swap that charges the fee is the swap that buys the share.

No off-chain keeper, and nothing to keep running

This is the one worth being specific about, because almost every rewards token ever shipped has depended on a server, and that server is where they die. A wallet somewhere runs a bot that calls distribute(). When it runs out of gas, or the key is lost, or whoever was paying for it stops, rewards stop. The contract is fine. The payouts are not.

There is no such wallet here. Distribution happens inside the swap: the hook runs as part of the trade that produced the fee, walking a cursor through holders and crediting them from the same transaction. Traders pay that gas as part of trading, which is why it needs nobody's budget.

The one job that genuinely cannot happen inside a swap, keeping the price oracle warm enough to convert safely, is paid for by the launchpad's own revenue through LaunchpadKeeper, and anyone at all can trigger it and be reimbursed from that. So there is no privileged operator, no subscription, and no component whose failure quietly stops the payouts. Turn off every machine we own and every launch keeps paying.

Real liquidity from the first block

There is no bonding curve and no graduation to survive. The entire supply is posted as one concentrated Uniswap v4 position at launch, so the pool is a real pool immediately and there is never a migration. Nothing has to fill before trading is genuine, and there is no threshold at which the rules change.

The opening position is permanent on every launch without exception, and the liquidity leg of the tax is added to it. The hook has no removal path for the opening position at all, so nobody can withdraw it, the creator included and us included. That is a property of the bytecode rather than a promise in a document.

One narrow exception exists and it is named rather than buried: on Etherwood itself, launch #001, the liquidity the tax builds can be withdrawn by the deploying address, because that liquidity is what funds the next pool. Every other launch, including every launch you make, has no such address and no such path. The Etherwood section gives the detail.

The cut shrinks as your tax grows

Etherwood takes one percentage point of the trade, not a percentage of your fee, so it is a fixed point that becomes a smaller share of the total the higher you set the tax. At a 2% launch the cut is half of it; at 20% it is a twentieth. A 1% launch is the one exception, paying a third of the point rather than the whole fee.

That revenue is split where it lands, by LaunchpadRevenue, and the split itself cannot be redirected: the share is a constant in the bytecode and both destinations are fixed at deployment with no setter for either. A slice of up to 5% is taken first to keep the price oracle warm, and stops entirely once that tank is full. What remains divides in half.

One half is paid to Etherwood holders in ETH. The contract delivers it to Etherwood's own hook, which pays it out exactly the way a trade does, so it reaches holders without anybody claiming anything.

The other half goes to a buyback wallet named at deployment, and this is the part worth being exact about rather than marketing. The contract moves the ETH; it does not do the buying. That wallet buys Etherwood off the market and burns it, and that is a person acting, not a property of the bytecode. What the bytecode does guarantee is that the ETH cannot go anywhere else, and that the amount sent is visible on chain forever.

None of the above is enforced by this website. Every claim on this page is a property of contracts that are already deployed and cannot be altered, which is the next section.

What can change, and what cannot

The honest version, including the parts that are not fixed.

"Immutable" gets used loosely enough to be worthless, so here is the actual division. Everything in the first table is set when your launch transaction is mined and has no function anywhere that can alter it afterwards. Not a function guarded by an owner: no function.

Fixed forever, at launch

WhatWhy it cannot move
Total tax Stored immutable in the hook. There is no setter in the bytecode.
The four-way split Rewards, liquidity, creator and the Etherwood cut are all fixed at construction.
Pair currency and reward asset Both are constructor arguments and both are baked into the pool key.
Total supply Minted once, at launch. There is no mint function, so the number can only fall, by burning.
The opening liquidity position Permanent. No withdraw path exists for it, for anybody, including the creator and including us. It is posted by the factory, and the hook's removal gate admits only the hook, so even the factory cannot take it back.
Liquidity the tax builds Permanent on your launch: the liquidityOwner immutable is the zero address, and with no owner the hook refuses its own removals too. Non-zero on exactly one launch, #001, where it is fixed at that address forever.
The anti-sniper window Its end is fixed at deployment. It can expire; it cannot be extended, restarted or re-enabled.
Name and symbol Written once into token storage.
Opening valuation Consumed at launch to place the position, and meaningless afterwards.

Editable, by one address

The creator payout address can change the logo, the description and the links, and can hand the creator role to another address. That is the complete list. It exists because a dead image link should be fixable, and it reaches nothing that touches money, supply or the fee.

The creator fee itself cannot be raised, lowered or redirected by the creator: only the address it is paid to moves, and only by whoever currently holds the role.

What we can change, and what that means for you

We cannot touch a launch that already exists. There is no upgrade path, no proxy and no admin on any deployed token, hook or pool. A launch is finished the moment it is mined.

What we can do is deploy a new factory. The factory is immutable too, so a change to how future launches work means a new address, published alongside the old one, with everything already launched continuing to run on the old code exactly as before. A new version can never reach backwards.

ComponentStatus
Your token and hookImmutable. Nobody can alter them, us included.
The factoryImmutable. New behaviour ships as a new address.
The revenue splitterImmutable. The 50/50 cannot be repointed.
The keeper's gas tankCapped and permissionless. It has no withdraw function and no owner.
This websiteFully mutable, and not load bearing. Every number here is read from the chain in your browser.
Your logo, description and linksEditable by the creator address, and by nobody else.

The honest caveat: the asset list is a property of which pools exist, not of the contracts. If a tokenized equity's pool is drained by its issuer, a launch rewarding that asset has nowhere to convert. That is a fact about the underlying market, and no contract here can promise otherwise.

A launch

Two contracts and a pool, none of which anybody can change afterwards.

The token is an ERC-20 whose holders accrue some other asset as people trade it. The hook is a Uniswap v4 hook that taxes each swap on the pair side, splits the tax four ways and pushes the holder share out. The pool is an ordinary v4 pool whose entire supply is posted as one concentrated position at launch.

There is no bonding curve and no launch phase to survive. The position is real liquidity from the first block, which is also why nothing ever migrates: there is nowhere to migrate to.

The supply is the liquidity

The opening position is single-sided. The launch posts the entire supply and zero pair currency: the range sits on the far side of the opening price, so when trading opens the position is 100% launch token and holds none of the asset it trades against. Buyers' own currency becomes the reserve as the price walks into the range.

So there is no liquidity to bring, no seed to match and no minimum to raise. A launch costs gas, plus whatever the launcher chooses to spend on their own first buy, which is a buy and not a deposit.

Nobody can change it

No owner, no admin key, no pause, and no function that reprices the fee or unlocks the liquidity. The single editable thing is the metadata, held by the creator role, which has no power over funds and can be handed on or renounced outright. That is what lets a community take a project over without anybody holding admin power.

  • The tax is taken in the pair currency inside the hook, so a holder's token balance is never touched and no transfer tax exists.
  • Liquidity is permanent. The hook's beforeRemoveLiquidity refuses every removal, including the launcher's and including its own.
  • Rewards are pushed automatically. There is nothing to stake and no claim to remember, though claim() is there for a wallet that needs it.
  • A holder must hold at least a hundred-thousandth of supply to earn, which is what stops dust wallets from diluting the rotation.

The hook

Every feature on this page is a Uniswap v4 hook callback. There is no other machinery.

Uniswap v4 lets a pool name a contract that the pool manager calls at fixed points in a swap's lifecycle. That contract is a hook, and it can take a share of the amounts moving through and return a delta the pool honours. That single capability is the whole of this project. The tax, the reward payouts, the liquidity growth, the anti-sniper window and the permanence of the pool are not five systems: they are callbacks on one contract, running inside trades somebody else is paying for.

This matters beyond architecture trivia. A hook runs in the swap, under the pool manager's lock, which is why rewards can be pushed with no keeper and why the fee cannot be sidestepped by routing around a front end. Anything the pool does, the hook saw.

The five callbacks a launch turns on

A v4 hook does not declare its permissions in storage. They are encoded in the low bits of its own address, so the pool manager reads from the address which callbacks to make, and a hook cannot acquire a new one later without being a different contract at a different address. These five are what a launch mines for.

CallbackWhat it does here
beforeInitialize Checks the pool being opened is the one this hook was built for, at the price it was built for. One hook serves one pool and refuses every other.
beforeSwap Takes the tax, in the pair currency, when the pair amount is already known. Returns it as a delta the pool credits to the hook, so the trader bears the fee and the AMM prices what is left.
afterSwap Takes the tax on the other kind of swap, where the pair amount had to be solved for, then does the upkeep: pushing rewards to holders, converting the reward leg, and growing the liquidity leg. All after the trader's price is settled, so none of it can change their quote.
beforeRemoveLiquidity Refuses. This is how the liquidity is permanent: not a timelock, not a burn address, a callback that reverts. Removing liquidity from a v4 pool is impossible if the hook declines it.
beforeDonate / others Not enabled. The flags are absent from the address, so the pool manager never calls them at all.

Two further flags, BEFORE_SWAP_RETURNS_DELTA and AFTER_SWAP_RETURNS_DELTA, are what let those two callbacks move value rather than merely observe it. Without them a hook can watch a swap and do nothing about it, which is most of what hooks in the wild are for.

Your launch mines its own hook address

Because permissions live in the address, a launch cannot use a shared hook. Every launch deploys its own hook, and the launch has to find a CREATE2 salt whose resulting address carries exactly those five bits. Your browser does that search before it submits anything, and the hook verifies in its own constructor that the address it landed at carries the flags it requires, refusing to exist otherwise.

The salt depends on the complete constructor arguments, so your tax, your split, your pair, your reward asset and your window are all committed to by the hook's address. Two launches with different terms cannot collide, and a hook cannot be redeployed with different terms to the same address.

What it means that the hook holds the position

A v4 position is keyed to whoever called modifyLiquidity. Your hook is the address that posts the liquidity the tax builds, so your hook owns it, and the hook is a contract with no owner and no removal path. The opening position belongs to the factory, which also has no removal path. Permanence here is not a policy applied to the liquidity; it is a consequence of who holds it and what that holder is able to do.

Two addresses are worth keeping apart while reading the rest of this page: the token, which is the ERC-20 people hold, and the hook, which is the v4 contract that taxes trades and pays them. Read surfaces are split across both, and the integration section lists which calls go where.

Name, logo and links

Stored on the token itself. There is no database here to be removed from.

A launch carries its own name, symbol, logo, description and five links, in token storage. One eth_call to metadata() gets all of it, which is why this site can be rebuilt by a stranger, and so can a rival to it. A launchpad whose token list lives on its own server is a launchpad that can delist.

Limits the contract enforces

name
64 bytes
symbol
16 characters, A to Z and 0 to 9
each metadata string
256 bytes

Bytes, not characters: the contract counts bytes, so an accented description is longer than it looks. The cap exists because metadata is written to token storage and encoded into the hook's constructor arguments.

The logo

256 bytes is a URI, not an image, so the image itself cannot go on chain. The launch form takes a file, checks it is an image under a megabyte, pins it to IPFS and stores the resulting ipfs://<cid>, about sixty bytes, pointing at content nobody can substitute later.

Pasting a URL is equally valid and is what the form falls back to when no pinning endpoint is configured. A logo hosted somewhere ordinary can be changed or taken down by whoever hosts it; a CID cannot. Neither is enforced, and both are visible on chain.

Editable, by exactly one address

The creator role may rewrite the metadata and nothing else. Every change emits MetadataChanged and records the block, so an interface can warn a buyer that a launch's website moved yesterday. The role can be transferred, or burned to the zero address, after which the metadata is frozen too.

The fee schedule

The launcher picks the total. The launchpad's cut comes out of it, not on top of it.

The total tax a trader pays is 1% to 20%, in whole percentage points. The launchpad's cut is taken out of that total, so the number a launch advertises is the number a trader actually pays.

The cut is one percentage point, with one exception: on a 1% launch a flat point would be the entire fee, so a 1% launch pays a third of what it collects instead.

Every total a launch may charge. Generated in your browser by lib/fees.js, which mirrors src/LaunchpadFees.sol.
total tax launchpad cut yours to divide cut as a share of the tax

Why whole points, and not 1.5%

Because the cut has a step in it at 2%, and at finer granularity that step is a trap. A 1.99% launch would keep 1.33% after the 33% cut, while a 2.00% launch keeps only 1.00% after the flat point: every total between 2% and 2.34% would leave the launcher worse off than charging less.

Whole points remove the dead zone outright, because 1% is then the only total below the floor and what a launcher keeps rises monotonically: 0.67, 1, 2, 3 … 19.

What a launch costs

Gas, and nothing else. There is no listing fee, no launch fee and no subscription, and there structurally cannot be one: LaunchFactory._open requires msg.value to equal the launcher's own opening buy exactly, or zero when there is none, so any figure added on top would revert.

Dividing your share

Three legs, chosen by the launcher, which must exhaust the share exactly.

What a trader pays splits four ways. The launcher chooses three of them and the fourth is the schedule's:

rewards
pushed to holders in the launch's reward asset
liquidity
added to the permanent position, withdrawable by nobody
creator
claimable by whoever launched it
cut
the launchpad's, per the table above

Any leg may be zero

Including liquidity: liquidityBps = 0 is valid, and the form offers it as no LP tax in one click. So is the creator leg, and so are rewards. What is not valid is a remainder: the three must add up to the launcher's share to the last basis point, because anything left over would be a fee taken from traders that belongs to nobody, stranded in the hook, with the trader still having paid it.

The form guarantees this by never letting you set liquidity at all. It is displayed as whatever rewards and the creator leg leave, so the three exhaust the share by construction rather than by validation.

The split is set at launch and cannot be changed afterwards, by anybody, including us.

Rewards in any asset

The pair and the reward are chosen independently.

A coin trading against USDG can pay its holders NVDA; a coin trading against ETH can pay its holders USDG. Whenever the two differ something has to swap, and the venue for that swap is pinned in the contract rather than chosen at runtime. "Whichever pool is deepest" is how you end up trading through a pool somebody spun up to be found.

Accrual is one storage write per trade no matter how many holders there are. Delivery is a real transfer, which is where the reward asset's nature starts to matter:

  • Native ETH hands control to the recipient, so automatic delivery gets the bare 2,300-gas stipend. A wallet with an expensive receive collects with claim() instead, which has no gas cap and no minimum.
  • An ERC-20 hands control to the token, not to the recipient, so it gets a real gas budget and payouts to ordinary contracts work.
  • The tokenized equities are permissioned. The issuer can pause them or block an address, and a transfer to a blocked holder reverts. Every automatic payout is therefore a low-level call whose failure is caught and unwound: one blocked holder costs the rotation a skipped slot rather than reverting the trade it is running inside.

The rotation

Payouts follow a cursor that persists between trades, so a holder who never transacts is still reached. There is a minimum gap between automatic payouts to the same wallet, or the cursor would re-pay whoever sits nearest it every few trades instead of going round.

A buyer earns from the block after their purchase, not from inside it. That is what stops a trader borrowing the pool's tokens inside one transaction, becoming almost all of the share count, and having their own fee divided in their favour.

Opening valuation

Choosing a market cap is choosing a tick, and only every 200th tick exists.

The opening valuation is not a number stored anywhere. It is implied by the opening tick together with the supply, because the tick fixes how many tokens one unit of the pair currency buys.

A position's bounds have to be multiples of the pool's tick spacing, and the opening price sits exactly on one of those bounds so that the position is purely launch token. So not every valuation is reachable: the achievable set is a geometric grid whose step is 1.0001 ** spacing, about 2% at a spacing of 200. The form shows the valuation you will actually get rather than the one you typed.

Two ways to get this catastrophically wrong

Neither of which is left to the person filling in the form:

  • It is denominated in the pair currency, not in dollars. Four ETH and four USDG are not the same launch.
  • It goes on chain in raw units. USDG has 6 decimals and everything else here has 18, a factor of 1012, so the form converts once and shows you the integer it is about to encode.

Which side of the pool the launch token lands on is decided by address ordering rather than by choice, and pool price is always amount1/amount0. Reading the same tick with the token on the wrong side does not give a slightly wrong valuation, it gives the reciprocal. At roughly 25,000 tokens per ETH, a $10k launch read the wrong way round is a six-trillion-dollar one.

Checked on chain

The price is computed by the page you launch from and verified by the factory, which recomputes the tick your valuation implies once the token exists and its side of the pool is known. It reverts unless the price it was handed is exactly the boundary price of that tick, not merely a price that rounds to the same tick, because anywhere inside a tick the opening position is in range rather than against its edge, which makes it demand pair currency the launch does not supply.

So a wrong opening price is a launch that does not happen, never a launch that opens somewhere nobody chose.

The anti-sniper window

Per-wallet limits for a set length of time. Selling is never limited.

For a chosen length of time after launch, up to an hour, two limits apply: a maximum balance per wallet and a maximum size per buy, both as a share of supply. Selling is never limited, during the window or after it, by anything. After the window the limits are gone for good, and there is no address that can re-enable them.

It is counted in seconds, and here is why that matters

The window is measured with TIMESTAMP, so it is plain seconds of real time and 30 seconds means 30 seconds. At this chain's 0.1 second blocks that is about 300 blocks on the explorer, and both numbers are true at once.

It reads on block.number instead, which sounds equivalent and is not. This is an Arbitrum Orbit rollup, where the NUMBER opcode reports the settlement chain's height rather than the local one. Sampled against a live node, it advances once per 12.9 seconds while the chain's own head advances every 0.099, a factor of about 130. A window of "300" would have meant 30 seconds to anyone reading an explorer and would have delivered 64 minutes of enforced wallet caps.

What the launch form's window presets submit. Generated in your browser by lib/blocktime.js. The seconds column is what goes on chain; the block column is the same duration in the 0.1 second blocks an explorer counts.
presetseconds submittedexplorer blocks

The ceiling is low deliberately: a longer window is a transfer freeze rather than protection.

Nobody can extend it

Including the creator. It is not a flag that gets switched off: the token stores the timestamp the window ends at, computed in its constructor, and there is no function anywhere that moves it. The three figures a front end needs are all immutable reads on the token (protectionUntil(), maxWallet() and maxBuy()), so anybody can check the claim rather than take it.

Both limits, or neither

If there is a window at all, both limits have to be meaningful: at least 0.1% of supply and at most 5% of it. Below the floor the window is a trading halt; above the ceiling it limits nothing worth limiting, and a front end that says "protection enabled" should be telling the truth. A window of zero seconds is allowed and turns protection off entirely.

The other half is your first buy

Executed inside the launch transaction. Without it the first outside buyer is simply whoever is fastest; with it the launcher sets the opening trade themselves. A window with no first buy protects the sniper's position as diligently as anybody else's.

Pressing launch

An address is mined in your browser before your wallet is asked for anything.

Uniswap v4 does not store a hook's permissions. It reads them out of the low fourteen bits of the hook's own address, on every call, and only consults the callbacks whose bit is set. A hook that must be asked before a swap therefore has to live at an address whose bit is set, and the only way to arrange that is to deploy by CREATE2 and try salts until one lands.

About one salt in 16,384 carries the right bits, and rather more than half of those also put the launch token on the side of the pool the price was computed for, so a search is tens of thousands of hashes and takes a moment. It runs in a Web Worker so the page keeps moving. Doing the same search on chain would cost every launcher a fortune in gas for work a laptop does instantly.

The salt is bound to your address

The factory does not use the salt it is given: it deploys with keccak256(abi.encode(msg.sender, salt)). Everything that decides a hook's address is visible in a pending transaction, so without that binding anyone could read a launch out of the mempool and deploy the identical hook first, leaving the real launch to revert on an occupied address, or replay it with their own opening buy and take the best entry while the creator role still pointed at the victim. A mined salt is worth nothing to anybody else.

And then the check that makes it safe

Before anything is signed, the page calls the factory's own predict(params, salt, price, launcher) and refuses to continue unless it returns exactly the address that was mined. The browser needs a copy of the hook's compiled creation code to mine at all, and a copy can go stale; this is what makes a stale copy a launch that will not send and says so, rather than a launch that goes somewhere unintended.

Graduation

Cosmetic. A progress line, and nothing else.

It is measured against a paired-liquidity threshold, it latches one way so a launch which has reached it can never un-graduate, and it changes nothing mechanically: no fee changes, no liquidity migrates, no limits lift, nothing moves. Crossing it and not crossing it are the same launch with a different badge.

The threshold is not a number this site sets. It is the launch's own opening valuation, chosen by its launcher and stored on the hook, so it scales by construction: both sides of the comparison are raw units of the same pair currency, which is why a 4 ETH launch and a 25,000 USDG one can share the definition.

It is not a quality signal. A launch can cross the line because one wallet traded a lot, and plenty of coins worth nothing at all will graduate.

Nothing migrates at graduation, and there is nothing to migrate. A launch's liquidity is a real v4 position from its first block rather than a bonding curve waiting to be converted, so there is no handover to get wrong, no second pool, and no window during which the price is somebody's contract rather than a market. That is the difference worth caring about, and it is true at block one rather than at a threshold.

The asset list

Fixed in the contract: native ETH, USDG, twenty tokenized equities, and ANTHROPICx1L.

A pair currency and a reward asset have to come from this list, which the factory enforces. It is not configurable, and the two choices are independent.

The list is measured, not assembled from tickers people recognise, and the measuring is why it is short. There are 194 tokenized equities on this chain and 177 of the ones not listed here have a pool against both hubs, so a longer list would have been easy to write. Almost none of those pools are venues. Only 29 assets on the whole chain hold five thousand dollars of depth within one percent of the price on either leg, and a pool thinner than that does not refuse a conversion, it fills it at a price nobody would accept.

So the list is every asset that clears that bar by a wide margin, and each one's fee tier is pinned to the deepest pool it has. GOOG is absent because it has no funded venue at all; GOOGL is the Alphabet ticker that trades here. Every entry is then proved rather than trusted: a fork test walks all 506 conversions the list allows against live chain state, and a second one launches a coin for all 529 pair and reward combinations and buys and sells each one.

ANTHROPICx1L is on the list and is not an equity. It is a permissioned 1x long on a private company, and by pool count it is the most heavily traded token on this chain that is not one of the two hubs, which is the only reason it earns a place next to the index funds. Mechanically it is identical to the rest: same interface, eighteen decimals, a funded pool, an entry in the same table.

The allow list, from lib/assets.js and config.js, which mirror src/LaunchpadAssets.sol.
symbolnamedecimalsaddress

Every asset here reaches both hubs, so any pair and reward combination is at most two hops. Four of them get there the long way. AMD and PLTR have an ETH pool about a thousandth the depth of every other equity's, COIN's holds nothing at all, and ANTHROPICx1L's is deep but charges 8%, which a two-leg conversion would pay twice. All four have a healthy USDG pool, so for those four the route to ether runs through USDG instead of through their own ETH pool, and a pairing between one of them and another equity crosses USDG rather than ether.

Which four is a constant in the contract, not a setting. There is deliberately no function that repoints a route, because whoever could repoint one could point it at a pool they owned and take every reward that crossed it. If these venues change, the answer is a new factory at a new address, and coins already launched are not moved onto it.

Do not read this list as an endorsement of holding tokenized equities, or of the issuer's right to freeze them, which is real.

Etherwood

Launch #001, built from the same hook as everything after it.

A 4% tax on every trade, paired against ETH, paying its holders ETH. Of that 4%, 2% is shared out to holders and 2% becomes permanent liquidity. There is no creator leg.

The one launch that pays no cut

That exemption reads like a carve-out and is the opposite of one. Etherwood pays nothing because at the moment it launches there is nobody to pay: the revenue splitter has not yet been wired to a hook, and the hook it would be wired to is the one this launch is creating.

What stops it being a back door is that the factory grants it positionally. The exemption applies to the launch with index zero and to no other, so it was consumed by the first launch the factory ever performed and cannot be handed out again. There is no flag to set and no address to favour, and which launch took it is visible on chain forever.

It is also what lets a 4% total split evenly. Charged the flat point, the same total would leave three points to divide, and three does not halve.

The small print

  • Supply is 100,000 ETHERWOOD, minted once, with no mint function afterwards.
  • A wallet must hold 1 ETHERWOOD, which is 0.001% of supply, to be eligible for rewards. That floor is not decoration: it puts a floor under the divisor the reward accumulator divides by.
  • Rewards are pushed out during other people's trades, with a minimum gap per wallet so the queue rotates instead of re-paying whoever is nearest the cursor.
  • The opening position cannot be withdrawn by anyone, here or on any other launch. The hook rejects removals rather than relying on a lock that expires.
  • No owner, no admin key, no transfer tax, no blacklist.

The one place liquidity is not permanent

Etherwood is also the only launch whose tax-built liquidity can be withdrawn, and since the opposite is promised everywhere else on this page it is worth being exact about what that covers and what it does not.

Two percent of every trade is converted into liquidity. On Etherwood that liquidity is withdrawable by the deploying address, because it is the funding for the next pool this project seeds. It is not a treasury and it is not the pool's floor: the opening position, the whole supply posted at launch, stays exactly as permanent as it is on every other launch, and no amount of withdrawing touches it.

That separation is structural rather than enforced by a check. A v4 position belongs to whichever address called modifyLiquidity. The factory posts the opening position, so the factory owns it; the hook posts the tax-built liquidity, so the hook owns it. Two distinct positions at the same ticks, and the hook's removal gate admits only the hook. The factory has no removal path to use, which is why the opening position is out of reach even for us.

  • The withdrawable amount is readable on chain at any time from taxLiquidity() on the hook, and the withdrawing address from liquidityOwner().
  • That address is an immutable, set at construction from the launcher. It cannot be changed, and because it is part of the hook's constructor arguments it is part of what the hook's own address commits to.
  • The factory sets it from the genesis flag, not from a launch parameter. There is no field a launcher can fill in to request one, which is why launch #001 is the only launch that has one and no later launch can obtain one.
  • On your launch liquidityOwner() returns the zero address, and the hook treats that as nobody: the gate closes against the hook as well, so there is no caller at all that can remove liquidity.

Integration

Everything a front end needs is carried by the launch itself.

Addresses

Reading a launch

The token is the interesting contract. Metadata lives on it rather than in a registry, so one eth_call gets you the logo, the description and every link, and there is no indexer between you and the truth.

Selectors this site uses, computed from the signatures in src/RewardToken.sol.
callselectorwhat it answers

metadata() returns the whole struct in one read: (logo, description, website, twitter, telegram, discord, github), seven strings, any of which may be empty. Empty means empty: a link nobody set must not become a dead href in your interface either.

Reading a launch's hook

The hook holds the fee legs as immutables and is the address a launch's graduation line is read from, so a front end that never asks us anything still gets the split a trader actually pays. The token names its own hook through depositor().

Whether our factory deployed that hook is a separate question with its own answer: isLaunch(address) on the factory. Ask it. LaunchHook is a public contract with a public constructor, so anybody can mine an address with the right permission bits and deploy a byte-identical hook that pays no cut and minted its whole supply to itself. Bytecode, hook flags and interface all match; membership in that mapping does not.

The hook's read surface, from the signatures in src/LaunchHook.sol.
callselectorwhat it answers

Walking the whole list

launchCount() and launches(uint256) on the factory, which is exactly what /explore/ does. launches holds hooks, so a listing is two hops: the hook names its token, the token carries the metadata.

Events

Enough to build a ledger without a backend. Reward accrual, delivery and every metadata change are all observable.

RewardReceived(uint256)
a trade funded the reward pool
RewardPaid(address indexed, uint256)
a holder was paid
MetadataChanged(address indexed)
the creator edited the links
CreatorTransferred(address indexed, address indexed)
the creator role moved, or was burned to the zero address
Launched(address indexed hook, address indexed token, address creator, uint256 index, bool genesis)
a launch happened

Launching from your own code

One call and three arguments: the LaunchParams struct encoded as a single ABI tuple, the mined salt, and the opening price.


          

Selector ·. Five of the struct's fields are adjacent uint16s, which is exactly why they are in a struct rather than a positional argument list: transposing two of them compiles perfectly and launches something you did not ask for.

The two loose arguments are conveniences and not trust. The salt has to produce a hook address carrying the v4 permission bits, which the hook checks on itself, and it is bound to msg.sender before it is used. The price has to be exactly the boundary price of the tick your valuation implies, which the factory recomputes. Both are verifiable in advance: predict() returns the address a given launcher and salt will produce, and it is the same code path the launch itself takes.

msg.value must equal initialBuy exactly on a native-ETH pair, and zero on every other, because an opening buy against an ERC-20 is pulled from an allowance instead. The factory is ownerless, so anything sent to it by mistake stays there forever.