Launchpad Math
Bonding-curve and fee formulas behind the GIWA token launchpad
This page derives every formula behind the Launchpad architecture - the constant-product bonding curve, the two distinct fee mechanisms, and the max-buy cap. See the Launchpad overview for the plain-language version of these same guarantees.
Bonding Curve
Each pool prices trades against a constant-product curve seeded with virtual reserves - non-withdrawable reserves that exist only for pricing math, not real liquidity. This keeps the starting price low and the curve smooth without needing a withdrawable seed, and without the gas cost or audit surface of a Bancor-style power curve.
Let be the pool's virtual ETH reserve (VIRTUAL_ETH_RESERVE, a fixed constant) and its real ETH reserve (realEthReserve, starts at zero, grows with every buy). Let be the virtual token reserve (virtualTokenReserve) and the real token reserve (realTokenReserve) - the tokens actually available to be bought. The curve prices against the effective reserves and :
virtualTokenReserve is snapshotted equal to curveSupply at pool creation, and realTokenReserve also starts at curveSupply - so at creation, , , giving:
A buy of gross ETH, after the applicable fee (see below) is deducted, nets into the effective ETH reserve, and returns:
tokens out - the standard constant-product swap formula, with and the pre-trade effective reserves. Sells run the same formula in reverse (tokens in, ETH out), and are only valid pre-graduation - once a pool graduates, trading moves to LaunchpadAmmPair directly.
realTokenReserve can never exceed curveSupply - it only decreases on a buy and increases (back up, never past its starting value) on a sell. This is enforced as an invariant, fuzz-tested across thousands of randomized buy/sell sequences.
Virtual Reserves, the Finite Depletion Boundary, and totalNetEthRaised
A subtlety falls directly out of the curve math above, and it's worth spelling out because it shapes both the dynamic fee and graduation trigger below - an earlier version of this page explained it via an "asymptote" that made VIRTUAL_ETH_RESERVE unreachable by construction. That reasoning was wrong. Here's the corrected derivation.
virtualTokenReserve is snapshotted to a fixed value (, curveSupply) at pool creation and never tracks realTokenReserve as the latter depletes. Because alone already equals , the effective token reserve is bounded below by even as (realTokenReserve) depletes all the way to - only ever ranges over the finite interval
itself never approaches zero. That means reaching exactly (the curve's entire real token supply bought out) is a finite, exactly reachable boundary - not an asymptote requiring unbounded capital - unlike a standard two-real-sided constant-product AMM (neither side virtually floored), where draining one real side to zero really would require infinite input.
At that boundary (, so ):
so the real ETH reserve reaches VIRTUAL_ETH_RESERVE exactly - at a finite point, not asymptotically.
Why VIRTUAL_ETH_RESERVE Is 2× MAX_RAISE, Not 1×
Generalize with for some ratio . At the moment totalNetEthRaised (and, absent any sells, too) first reaches MAX_RAISE:
so the real tokens still sitting in the curve at that moment are:
At - a previous fix that set VIRTUAL_ETH_RESERVE equal to MAX_RAISE - this is exactly : an ordinary, sell-free graduation would drain the curve of real tokens at the exact moment it triggers, leaving ~nothing to seed the post-graduation AMM (see Graduation) with - not as a rare edge case, but as the deterministic outcome of every normal, no-sells launch.
At - the current, corrected value - it's
a full third of curveSupply remains as real, sellable liquidity at ordinary graduation. That's why VIRTUAL_ETH_RESERVE is 2 ether, twice MAX_RAISE (1 ether), rather than equal to it. Buyers can still keep buying past this point - nothing stops them short of the buy-headroom cap at MAX_RAISE - this derivation only guarantees the default, no-sells outcome leaves real liquidity behind rather than draining the curve exactly at graduation.
Doubling VIRTUAL_ETH_RESERVE also doubles the curve's starting marginal price, - immaterial at a billion-token curveSupply, where either value keeps the curve smooth and the starting price low.
Why totalNetEthRaised Still Exists
None of the derivation above implies realEthReserve has some unreachable ceiling that graduation needs to work around - it doesn't; reaches VIRTUAL_ETH_RESERVE at a perfectly finite, reachable point, as shown above. The actual reason graduation and the dynamic fee are measured against a separate totalNetEthRaised field, rather than realEthReserve directly, is sell-resistance, not reachability.
PoolState tracks totalNetEthRaised as a monotonically non-decreasing counter, incremented by the net (post-fee) ETH of every buy and never decremented by a sell - whereas realEthReserve moves in both directions: up on a buy, down on a sell. A pool that raises close to MAX_RAISE, sees heavy selling drive realEthReserve back down, and then has to re-raise from a lower point, still gets full credit for its cumulative trading activity under totalNetEthRaised. Measuring graduation off realEthReserve directly would let a well-timed sell indefinitely delay - or even reset - graduation. realEthReserve continues to serve only the constant-product pricing math, exactly as the formula above requires.
Anti-Snipe Decaying Fee
Buys landing within the pool's first ANTI_SNIPE_DECAY_BLOCKS blocks pay a fee that starts high and decays linearly, block by block, to the pool's current baseline fee:
where is the number of blocks since the pool's creation block, = ANTI_SNIPE_DECAY_BLOCKS (15), = ANTI_SNIPE_FEE_START_BPS (8,000 bps, 80%), and is the pool's current dynamic baseline fee (below) - the anti-snipe premium always decays toward whatever the ongoing fee happens to be, not to a fixed floor.
This is a deliberate response to GIWA being a flat-gas OP-Stack chain: there's no priority-fee auction to cap (unlike Ethereum L1), so the fee taxes block-inclusion order itself rather than gas price. Whoever wins the race to land in the earliest blocks pays for it, regardless of how much gas they spent to get there.
While inside this window, every buy is additionally capped (see below), and any fee collected routes entirely to the treasury - the anti-snipe premium is a deterrent, not a creator revenue line.
Dynamic Market-Cap-Scaled Fee
Outside the anti-snipe window, every buy and sell pays a baseline fee that scales with how much of the raise target has been reached so far:
where = totalNetEthRaised (the monotonic counter above, not the instantaneous curve reserve), = DYNAMIC_FEE_MAX_BPS (500 bps, 5%), and = DYNAMIC_FEE_MIN_BPS (100 bps, 1%). A brand-new pool with nothing raised yet pays the full 5%; a pool that has fully reached MAX_RAISE (and is about to graduate) pays the floor of 1%.
This is the PRD's "Project Ascend" pattern: reward sustained growth with a cheaper fee, and keep new/thin pools - the ones most exposed to opportunistic extraction - paying a higher one. Once a pool graduates, this mechanism stops applying entirely; the AMM pair instead runs a flat POST_GRADUATION_AMM_FEE_BPS (30 bps, 0.3%) swap fee, the same for every graduated token.
Whichever of the two fees applies (anti-snipe or dynamic baseline), it's split between the treasury and the pool's creator - see the creator fee-share formula below.
Max-Buy Cap
While the anti-snipe window is active, a single buy cannot claim more than a fixed share of what's left in the curve:
with MAX_BUY_CAP_BPS = 300 (3%) and = realTokenReserve at the moment of the buy. A buy that would demand more than this reverts outright rather than silently clamping - the caller has to split it into multiple transactions, each subject to the same 3% ceiling, spreading out concentration risk even for a bot willing to spend more gas. Outside the anti-snipe window, this cap no longer applies; buys are limited only by however much curve supply actually remains.
Worked Example: Sniping vs. Waiting
Take a freshly created pool where the creator sets no initial allocation, so the full default supply becomes the curve's supply: tokens (ignoring the standard 18-decimal scaling for readability). At creation, ether and , so the effective pre-trade reserves are ether and tokens.
The Anti-Snipe Fee, Block by Block
Nobody has bought yet, so totalNetEthRaised is 0 and the dynamic baseline fee sits at its ceiling, . Plugging that into the anti-snipe formula above for a few block offsets:
| Blocks since creation () | Fee paid |
|---|---|
| 0 (same block as creation) | 80% |
| 3 | 65% |
| 7 | 45% |
| 10 | 30% |
| 14 | 10% |
| 15+ (window closed) | 5% |
With these constants the decay happens to land on exact 5-percentage-point steps each block - not a coincidence worth relying on for other constant values, but a convenient way to see the linearity directly: 80, 75, 70, ... down to the 5% baseline at block 15.
Same Gross Spend, Two Very Different Outcomes
Two buyers each send 0.05 ETH gross against this same freshly created pool - one lands in the creation block (), the other waits until block 20, after the anti-snipe window has closed. Assume no other trades happen in between, to isolate the fee's effect.
Buyer A, block 0: fee = 80% (from the table above). Net ETH into the curve: ETH.
(Well under the max-buy cap - 3% of the 1,000,000,000-token curve supply, or 30,000,000 tokens - so it's the fee, not the cap, doing the work here.)
Buyer B, block 20: the anti-snipe window has closed, so this buy pays only the 5% dynamic baseline. Net ETH into the curve: ETH.
For the identical 0.05 ETH spend, Buyer B receives ≈4.66× more tokens than Buyer A. The curve didn't move between the two buys in this example - the entire difference is 75 of Buyer A's 80 percentage points of fee going straight to the treasury as an anti-snipe premium, with nothing to show for it on the buyer's side. This is the mechanism working as intended: racing to land in the creation block is the worst time to buy, not the best.
This example assumes 0% creator allocation and no trades between the two buys, to keep the arithmetic isolated to the fee's effect alone. In a live pool, real trading between blocks pushes totalNetEthRaised up and the dynamic baseline fee down, so Buyer B's actual fee by block 20 would typically be even lower than the 5% ceiling used here.
Creator Fee-Share
A creator can configure a cut of the baseline trading fee (never the anti-snipe fee) to accrue to themselves per pool:
with creatorFeeShareBps bounded by CREATOR_FEE_SHARE_MAX_BPS (5,000 bps, 50%) at pool creation. The remainder of the fee (feeAmount - creatorCut) always accrues to the treasury. This accrual is pulled via claimRevenue(poolId).
Fee-share is accrue-and-claim, not auto-paid per trade: crediting a creator on every single buy/sell would compound gas costs with the anti-snipe and dynamic fee math already running on the hot trading path, for a benefit (immediate payout) creators don't actually need.