Skip to content

Curve arithmetic and trading

Source: curve.move, launch.move, and fees.move. Use integer arithmetic; floating-point previews lose atomic-unit accuracy.

Let D = 10_000, M = meme_reserve, V = virtual_quote, Q = real_quote_reserve, T = graduation_target, fq = quote_fee_bps, fm = meme_fee_bps, and s = sell_burn_bps. Rates below mean their integer BPS values. The curve prices against (V + Q) * M, with output rounded down; fees and burn round up. Rounding can increase the product. V is never deposited or withdrawn.

spot_price_atoms = (V + Q) / M
spot_price_whole = spot_price_atoms * 10^meme_decimals / 10^quote_decimals
progress = Q / T

These display values are rational ratios: retain numerator and denominator or use decimal formatting. Do not perform truncating integer division before decimal scaling. Multiplying whole-token price by the current whole-token supply gives a current-supply valuation. Multiplying by the original billion-token supply gives an original-supply valuation; disposal at migration can make these differ. Neither is an executable quote.

For q quote atoms supplied, first cap gross input:

R = T - Q
if q - ceil(q * fq / D) <= R:
g = q
else:
g = ceil(R * D / (D - fq))
refund = q - g
quote_fee = ceil(g * fq / D)
n = g - quote_fee
gross_meme = floor(M * n / (V + Q + n))
meme_fee = ceil(gross_meme * fm / D)
net_meme = gross_meme - meme_fee

An accepted trade changes Q to Q + n and M to M - gross_meme. A target-reaching buy sets MigrationReady. The cap reaches the remaining net quote amount exactly; the virtual reserve does not count.

launch::buy(launch, package_version, runtime_config, quote_coin, min_meme_out) returns (Coin<Meme>, Coin<Quote>): net output and excess-input refund. Consume both, including zero coins. Only Live permits buys. A nonterminal zero-output buy aborts with EZeroTradeOutput. A terminal zero-output buy succeeds only if min_meme_out is zero; a positive minimum aborts with ESlippageExceeded.

For m input token atoms:

meme_fee = ceil(m * fm / D)
burn = ceil((m - meme_fee) * s / D)
x = m - meme_fee - burn
gross_quote = floor((V + Q) * x / (M + x))
quote_fee = ceil(gross_quote * fq / D)
net_quote = gross_quote - quote_fee

An accepted sell changes M to M + x, Q to Q - gross_quote, and adds burn to pending_burn. It must be funded by the real quote balance; virtual reserves provide no payout liquidity. A balance failure reverts the transaction.

launch::sell(launch, package_version, runtime_config, meme_coin, min_quote_out) returns one Coin<Quote>. It requires Live and public_start_ms to be set. Zero net output aborts; output below the minimum aborts. Sell burn is separate from both asset fees and is disposed of only at migration.

Each trade-fee asset splits using live RuntimeConfig.protocol_fee_share_bps, p:

protocol = ceil(fee * p / D)
creator = fee - protocol

Fees accrue in the launch. Each launch’s fq and fm are immutable snapshots, each bounded at 1,000 BPS; Blast can change p from 0 to 10,000 BPS without a delay for later trades. A named partner takes its cut of Blast’s balances at payout time, not an extra fee during the trade.

For example, with M=1_000_000, V=100_000, Q=0, T=100_000, fq=fm=100, a buy supplying 10_000 quote atoms uses them all: quote fee 100, net quote 9_900, gross tokens 90_081, token fee 901, net tokens 89_180. This example uses atoms and is not a configured launch or a price promise.

join_opening_round accepts a non-zero Coin<Quote> before public_start_ms + opening_round_ms; repeated bids accumulate under OpeningRoundBidKey(sender). The creator can join before sharing. No ordinary trade or withdrawal is available in OpeningRound.

At or after the end, anyone calls settle_opening_round once. It changes the state to Live and runs the pot through the buy arithmetic with minimum output zero. If zero tokens would be delivered without reaching the target, it retains the whole pot for refund; a target-reaching pot can be charged despite zero token output. Settlement may immediately produce MigrationReady.

deliver_opening_round(launch, package_version, bidder) removes that address’s bid and pays it directly. For remaining balances B_m, B_q, remaining bid total B, and this bid b, delivery pays floor(B_m*b/B) and floor(B_q*b/B), then subtracts the bid and payouts. The last delivery takes the remainder. Delivery works in every later lifecycle, including Migrated.

The pricing walkthrough derives the constant-product equation step by step. The builder applies these atomic-unit rules to configurable plans, trade examples and LP-fee routing; its rates are examples, not live policy.