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
| What | Why 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.
| Component | Status |
| Your token and hook | Immutable. Nobody can alter them, us included. |
| The factory | Immutable. New behaviour ships as a new address. |
| The revenue splitter | Immutable. The 50/50 cannot be repointed. |
| The keeper's gas tank | Capped and permissionless. It has no withdraw function and no owner. |
| This website | Fully mutable, and not load bearing. Every number here is read from the chain in your browser. |
| Your logo, description and links | Editable 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.
| Callback | What 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.
| preset | seconds submitted | explorer 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.
| symbol | name | decimals | address |
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.
| call | selector | what 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.
| call | selector | what 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.