the bonding curve
closed-form forward and inverse curves. eth in mints sato; sato in burns and pays eth out. fixed-point arithmetic, no oracle.
sato is minted along an exponential bonding curve parameterized by two constants: the asymptote K = 21,000,000 sato and the scale S = 500 eth. cumulative eth spent into the curve is the single state variable; everything else derives from it.
forward curve
the cumulative supply minted after eth total eth has been spent is:
q(eth) = K * (1 - e^(-eth / S))
at eth = 0, supply is 0. at eth = S, supply is K · (1 − 1/e) ≈ 63.2% of K. as eth → ∞, supply approaches K but never reaches it analytically. in solidity it saturates: when eth / S ≥ 50, e^(−eth/S) < 2 × 10⁻²², which is below the prb-mathUD60x18 precision floor of 1e-18, so the contract returns exactly K_SUPPLY.
inverse curve
given a target supply q, the cumulative eth required to have minted it is:
eth(q) = -S * ln(1 - q / K)
= S * ln( K / (K - q) )this is what the contract evaluates whenever it needs to know “how much eth has the curve absorbed if its position is q?” — for instance, when computing the eth owed to a seller.
sell formula
a seller burns satoIn tokens and receives eth. the curve position before the sell is q; after, it is q − satoIn. the eth paid out is the difference between the two inverse-curve evaluations, which simplifies to a clean log:
ethOut(q, satoIn) =
S * ln( (K - q + satoIn) / (K - q) )the same formula handles both small and large sells. nothing forks on size. the only failure modes are domain errors: selling more than currently circulates (SellExceedsSupply) or trying to sell when the denominator K − q has rounded to zero (InverseDomainError) — both impossible in practice within the saturation bounds.
marginal price
the price of the next infinitesimal sato at curve position eth is the derivative of the inverse curve:
marginalPrice(eth) = deth / dq
= S * e^(eth / S) / K
= ETH per SATO at curve position ethat eth = 0, the marginal price is S/K ≈ 2.38 × 10⁻⁵ eth/sato— the cheapest sato ever exist. as the curve moves forward, the price grows exponentially with each additional eth absorbed. by eth = S, price is e ≈ 2.72× the opening; by eth = 5S, 148×; by eth = 10S, 22,000×.
key properties
- monotonic
- supply is strictly non-decreasing in eth. every buy moves the curve strictly forward; sells move it strictly backward.
- path-independent
- two buyers who together spend the same total eth get the same total sato, regardless of the order or sizing of their buys. splitting a buy across blocks costs the same as buying in one shot (outside the entropy window).
- reversible
- burning sato along the inverse curve always returns exactly the eth that would put the curve back at its prior position. the system never accidentally accumulates eth from rounding; fees are tracked separately.
- saturating
- arithmetic precision (
1e-18) sets a hard floor long beforeKis mathematically reached. in practice the curve treats itself as exhausted aroundeth/S = 50, well past any plausible inflow.
implementation notes
all math runs through prb-math's UD60x18 fixed-point type for exp and ln. four functions in Curve.sol cover everything the hook needs:
totalMinted(eth)— the forward curve. used to settle buys.mintFor(ethBefore, eth)— the delta of the forward curve across one buy. clamps to zero on the sub-wei rounding edge.burnFor(currentTotal, satoIn)— the inverse log formula above. used to settle sells.marginalPrice(eth)— never called by the swap path, exposed for off-chain queries and tooling.
this page describes deployed code. nothing here is a promise — it is a description of what the contract does and what it doesn't.
