Skip to content
← writing

Bonding curves, derived

crypto
defi
bonding-curves
amm
mechanism-design

A token launchpad looks like a casino and is actually a calculus exercise. The price is a function of supply. The cost of your buy is the area under that function between where you started and where you stopped. That's the whole magic trick. Let me integrate it.

I built arenacoins, a pump.fun-style launchpad that mints a GameToken per game on B3. Prebonding grid, a live launchpad table, a trades ticker, a bonding curve that graduates into a real AMM pool when it hits threshold. Same flow pump.fun runs, adapted for games instead of memes. And every explainer I read while building it did the same thing: wave at "the curve goes up as people buy" and call it a day. That's not an explanation. That's a caption. The mechanism is a closed-form integral, and the difference between curve shapes is a difference in who gets paid for showing up early, which is the entire game.

So let's derive it properly. p(s) up.

A price is a function, not a vibe

A bonding curve is a smart contract that is the sole counterparty to every trade. It quotes a deterministic spot price p(s) where s is the current circulating supply. There's no order book, no maker, no counterparty risk in the usual sense. The contract is the market until it graduates.

Here's the part people skip: spot price is a marginal price. It tells you what the next infinitesimal unit costs, not what your whole buy costs. If you're buying from supply a up to supply b, the total cost is the area under the curve across that range:

Cost(a → b) = ∫ from a to b of p(s) ds

That's it. That's the entire launchpad. Everything else, slippage, whale tax, sniper advantage, is a property of what shape you plug into p(s).

One more definition worth having up front: the average fill price you actually pay is

average price = Cost(a → b) / (b − a)

For any curve where price strictly increases with supply, average price is always greater than the spot price at a, the price you saw before you clicked buy. That gap is slippage. You are, mechanically, paying for the act of moving the price yourself.

Linear: the friendly case

Start with p(s) = m · s. Straight line through the origin, slope m.

Cost(a → b) = ∫ from a to b of m·s ds = (m/2)·(b² − a²)

Divide by (b − a) and the b² − a² factors nicely into (b − a)(b + a), which cancels the denominator and leaves:

average price = (m/2)·(a + b)

Which is exactly the spot price at the midpoint of your buy. That's a genuinely clean result: on a line, you pay the price that sits halfway between where you started and where you ended. No surprises, no runaway tax on size, roughly proportional slippage. Selling b back down to a returns the same area (minus a fee if the protocol takes one), so the curve is symmetric in both directions. This is the curve you'd design if you wanted things to feel fair and didn't care about incentivizing anyone to show up first.

Nobody uses this curve for a launchpad. Keep reading to find out why.

Exponential: the early-mover machine

Now p(s) = p₀ · e^(k·s). Same setup, different shape.

Cost(a → b) = ∫ from a to b of p₀·e^(k·s) ds = (p₀/k)·(e^(k·b) − e^(k·a))

The thing to notice is what happens to the ratio of prices at two points spaced Δ apart: p(s + Δ) / p(s) = e^(k·Δ), a constant, independent of s. On a line, moving Δ further out adds a fixed amount. On an exponential, moving Δ further out multiplies by a fixed factor. That's penny-doubling. With k large enough, almost all the cheap supply is packed into the first sliver of the curve, and the millionth token costs orders of magnitude more than the first, not because anything happened, just because of where it sits on s.

That's the mathematical statement of "early-mover advantage." It isn't a vibe you get from watching a chart go up fast. It's e^(k·Δ), and k is a dial the deployer chooses. Turn it up and you're explicitly building a machine that pays the front of the line and taxes everyone else. Linear feels fair. Exponential pays whoever clicks first.

Constant-product: what pump.fun actually runs

Here's where most explainers get it wrong, including the "step function" meme that gets repeated a lot. pump.fun's curve isn't a literal k·s² price ladder in production. It's a constant-product AMM, x·y = k, the same invariant Uniswap v2 runs, except the reserves are virtual. There's no real liquidity sitting behind x and y at launch, they're seeded numbers chosen so the curve starts at a specific initial price and behaves like a real pool from token zero. Virtual reserves are the trick that lets a bonding curve be an AMM instead of a hand-rolled pricing function.

Let x be the virtual token reserve, y the virtual quote reserve (SOL, in pump.fun's case), with invariant x·y = k held constant.

Spot price is the marginal exchange rate, the derivative of the invariant:

p = dy/dx = y/x = k/x²

A buyer removing Δx tokens from the pool has to add enough quote currency Δy to keep the invariant fixed:

(x − Δx)·(y + Δy) = k = x·y

Solve for Δy:

Δy = x·y/(x − Δx) − y = y · Δx/(x − Δx)

The average fill price is Δy/Δx = y/(x − Δx), compared against the spot price y/x before the trade. Divide the two and subtract 1, and the slippage falls out clean:

slippage = (average price / spot price) − 1 = x/(x − Δx) − 1 = Δx/(x − Δx)

Watch what happens as Δx approaches x: the denominator goes to zero and slippage runs to infinity. That's the single most important fact about constant-product curves and it's the one that explains why launches are sniper-friendly. Buying 10% of a curve doesn't cost 10 times what buying 1% costs, it costs far more, because the marginal price is running away from you the entire time you're filling. Cost is superlinear in size. The contract is telling you, in closed form, exactly why the whale in the first block pays a premium and the sniper in the first millisecond pays almost nothing.

Graduation: when the curve becomes a market

A bonding curve doesn't run forever. It graduates. Mechanically: the contract tracks cumulative real quote raised, and once that crosses a threshold R*, pump.fun's is roughly 69k in market cap, about 85 SOL of real reserve, drifting with SOL's price, the regime flips. The accumulated reserve plus the remaining token supply gets deposited into a standard AMM pool (PumpSwap, in pump.fun's case), and the LP tokens from that deposit are burned. Burning the LP is the detail that matters: it means nobody, including the deployer, can pull the migration liquidity out from under buyers. It's a fairness guarantee bolted onto the exit, not the entry.

Before graduation you're integrating a one-sided function against a single, known contract, everyone is trading against the same deterministic curve, and the curve is fully front-runnable because its future price is computable in advance. After graduation you're in a two-sided pool with arbitrageurs on both sides and the price discovery process changes entirely. Graduation is the exact point where R* is crossed on the reserve axis, and it's the discontinuity where "sole seller with a formula" becomes "market with counterparties."

The launch is a game, and the curve picks the winner

Put the three curves side by side and define early-mover advantage as the ratio of average fill price late in the curve versus early in the curve, for equal-size buys.

Linear: bounded, roughly b/a. A late buyer pays proportionally more, but the ratio doesn't explode.

Exponential: unbounded, roughly e^(k·Δ). Choose k and you choose exactly how much you want to reward the first buyer over the millionth. There's no cap.

Constant-product: bounded, but heavily front-loaded because of the superlinear slippage term, x/(x − Δx).

None of this is decorative. Curve shape is a mechanism-design decision that directly determines the incentive to snipe. A steep early curve is a standing bounty for whoever has the fastest RPC and the least scruples about front-running the mempool. It's math doing exactly what the deployer told it to do, not a moral failing of the traders. If you want a launch that isn't a bot race, you either flatten the early curve or you add a fair mechanism before the curve even opens, a prebonding phase where everyone gets the same entry conditions regardless of latency. It's the lever that actually moves who gets paid, not a UI flourish.

Here's the constant-product math ported to code you can actually ship, virtual reserves and all:

// pure functions, no state, over (virtualTokenReserve, virtualQuoteReserve)
uint256 constant R_STAR = 69_000e18; // approx market cap threshold, drifts with SOL price
 
function getBuyPrice(uint256 x, uint256 y, uint256 dx) public pure returns (uint256 dy) {
    require(dx < x, "buy exceeds curve supply");
    // dy = y * dx / (x - dx)
    dy = (y * dx) / (x - dx);
}
 
function getSellPrice(uint256 x, uint256 y, uint256 dx) public pure returns (uint256 dy) {
    // inverse direction: dy = y * dx / (x + dx)
    dy = (y * dx) / (x + dx);
}
 
function maybeGraduate(uint256 realQuoteRaised) internal {
    if (realQuoteRaised >= R_STAR) {
        migrateToAmmAndBurnLp();
    }
}

And the linear/exponential closed forms, for contrast, as plain functions:

function linearCost(m: number, a: number, b: number): number {
  return (m / 2) * (b ** 2 - a ** 2);
}
 
function exponentialCost(p0: number, k: number, a: number, b: number): number {
  return (p0 / k) * (Math.exp(k * b) - Math.exp(k * a));
}

Three curve families, three closed-form integrals, one difference between them: who gets paid for showing up first.

The honest part

The exact numbers on pump.fun's graduation threshold, the virtual reserve seed values, the precise R* target, are partly reverse-engineered from on-chain data by people smarter than me at reading transaction logs, not published as a spec. The 69k market cap / 85 SOL figure is a real approximation, not gospel, and it moves with SOL's price since the threshold is denominated in SOL, not USD. If you're building against it, verify from current on-chain state, don't hardcode last month's number.

The "k·s² step function" framing shows up in a lot of explainers because it's easier to draw. It's a simplification of a simplification. The production curve is constant-product over virtual reserves, full stop, and the slippage behavior only makes sense once you derive it from that invariant, not from a made-up step ladder.

And the sniper/front-running claim is a statement about incentive surface, not an accusation that every launch is rigged. A steep early curve creates a bounty. Whether anyone claims that bounty is a separate question from whether the bounty exists.

Why I built arenacoins on this math

arenacoins mints a GameToken per game on B3, and the whole flow is the graduation flow above with one addition: a prebonding grid before the curve even opens, so early allocation isn't purely a latency race. That's a curve-shape decision as much as the p(s) you pick, it's mechanism design applied to the part of the launch that happens before block one. The curve is the rules of the game, not decoration, and you should pick it on purpose instead of copying the last project's contract and hoping the meme carries it.

If you launch something on a curve you derived yourself, not copy-pasted, show me.

Sources: