The price curve
The network's position counts the dollars that entered it, in {{unitUsd}} units. MLX per unit starts at {{genesisRate}} and halves at every doubling ({{doublingUsd}}), so the network price starts at {{genesisPrice}} and doubles each time. The protocol buys and sells MLX along this curve.
All of it is in lib/chain/curve.ts. The ledger's swap and buy_node handlers in lib/chain/ledger.ts apply it, and lib/chain/walletpay.ts plans a seat paid from the wallet.
Supply
The supply is fixed at 10,000,000,000 MLX (TOTAL_SUPPLY), divisible to 6 decimals (DECIMALS). On the ledger, amounts are integers in base units, written as strings. All MLX was created at genesis in the five protocol accounts shown in the overview. The curve creates no MLX. Spot buys are filled from treasury.mlx.
Position
The position u is stats.units on the ledger: how many $100 units have entered the network.
| Event | Position |
|---|---|
| A seat is bought | moves forward by 50% of the seat's units (all of them before 29 Oct 2026, seatCurveUnits) |
| A seat is granted (Builder program) | doesn't move |
A spot buy of D dollars | moves forward by D / unit |
| A spot sale | moves back by the units that would have minted that MLX, never below 0 |
| A seat paid partly with MLX | moves back by the sale, then forward by the seat |
The current position, price and halving progress are in /api/curve:
https://mlx.app/api/curveRate and price
D_k = length of doubling k (DOUBLINGS, doublingLength)
b_k = D_0 + … + D_(k−1) where doubling k starts (halvingAt)
k = the doubling u is in (epochOf)
rate(u) = G · 2^−(k + (u − b_k) / D_k) MLX per unit at position u
priceAt(u) = unit / rate(u) dollars per MLX
unit = $100 (UNIT_USD)
G = 10,000 MLX per unit (GENESIS_RATE)Doublings lengthen (curve v2, 29 Oct 2026): 200,000 ($20 million), then 300,000 ($30 million), then 400,000 ($40 million), then 500,000 ($50 million) for every doubling after. The rate halves once per doubling, smoothly, not in steps, and the price is continuous at every boundary. The network price starts at $0.01 and doubles every doubling. The first doubling is the same as before v2, and the network had not left it, so earlier transactions replay unchanged.
The integral
A span of units [u, u + m) is worth the exact integral of the rate over it (grant):
within doubling k:
grant(u, m) = (G · 2^−k · D_k / ln 2) · (2^(−(u − b_k) / D_k) − 2^(−(u + m − b_k) / D_k))A span that crosses a boundary is summed doubling by doubling.
The integral is additive, so grant(u, a) + grant(u + a, b) = grant(u, a + b): buying in one piece or many gets the same MLX. One pass along the whole curve is worth at most G · H / ln 2 MLX (CURVE_TOTAL, also curveTotal in /api/curve). Because sales move the position back, a stretch of the curve can be paid again after a sale.
Dedicated seats bought before SEAT_REWARD_END_AT were paid grant(u, units) up front. Seats bought since are paid nothing up front. They still move the position, and so the price. See Dedicated seats.
Spot buys and sells
The protocol is the counterparty. It fills every spot order on the curve, from treasury.mlx (the swap transaction).
Buy with D dollars of USDC (or legacy USDT) at position u:
m = D / unit
MLX = grant(u, m) / (1 + buyPremium) (buyQuote)
u → u + mSell X MLX at position u:
K = G · 2^−k · D_k / ln 2 within doubling k
a = b_k − D_k · log2(2^(−(u − b_k) / D_k) + X / K) the position where the curve would have paid exactly X
(a sale that reaches b_k continues into doubling k − 1; never below 0)
USDC = unit · (u − a) · (1 − sellDiscount) (sellQuote)
u → aPast position 0 the curve has nothing left to unwind, so a sale is paid only for the units that are there.
The defaults are a buy premium of 3% and a sell discount of 20% (BUY_PREMIUM, SELL_DISCOUNT). The live values can differ: they are set by the operator and published in /api/stats as market. Read them there, never from this page.
The ledger refuses a fill when:
- the amount is under its minimum (
SPOT_MIN_UNITSinlib/chain/spot.ts); - the treasury doesn't hold enough MLX for a buy, or enough USDC for a sale;
- the output is below the
minOutthe wallet signed (its slippage guard); - a sale asks for more than the wallet's unlocked MLX. Locked MLX can't be sold.
Outputs are rounded down to whole base units. Spot-bought MLX is never locked.
To get the exact quote the ledger would fill right now, with its minOut:
https://mlx.app/api/market/quote| Parameter | Type | Notes |
|---|---|---|
side | buy or sell | required |
amount | integer string | what goes in, in base units: USDC (or USDT) for a buy, MLX for a sale |
stable | USDC or USDT | the coin a buy pays with; USDC when left out |
account | wallet name | optional: also checks that wallet's balance |
See Market.
Paying from the wallet
buy_node with pay: "WALLET" pays for a seat from the whole wallet (planWalletPay in lib/chain/walletpay.ts):
- USDC first.
- Then USDT, if any is left from before.
- Then the fewest unlocked MLX that sell for the rest at the spot sell price (
mlxForUsd).
The sale and the seat settle in one step. The MLX goes to treasury.mlx, and the dollars it fetches go straight to the seat, so no sell-side liquidity is drawn. The position moves back by the sale's units, then forward by the seat's units. The seat's record carries sold: { mlx, usd }.
The wallet runs the same plan in the browser and signs maxMlx: its quote plus a small margin (maxMlxFor). If the price moved and the plan needs more MLX than that, the ledger refuses with "The MLX price moved beyond your limit".
Reading it
| What | Where |
|---|---|
| Position, price, next halving, seat rates | GET /api/curve |
Live spread (market), position (stats.units), treasury liquidity | GET /api/stats |
| An exact quote | GET /api/market/quote |
| Supply and allocation | GET /api/supply |