Protocol

Curve maths

The exact arithmetic of the bonding curve: reserves, price, quotes, fees and rounding, as implemented in BondingCurve.sol.

Every number the app shows for a curve is computed the same way the contract computes it. The app's app/lib/curve.ts is a bigint mirror of these formulas; the simulator and the trade panel use it, and test_quotesMatchExecution in the fork tests checks that quotes equal executed amounts.

Units

QuantityUnit
USDG amounts (usdgIn, usdgRaised, virtualUsdg, fees)6-decimal integers (1 USDG = 1e6)
Token amounts (tokensSold, virtualTokens, curveSupply)18-decimal integers
price()USDG per whole token, scaled by 1e18 (1e18 = 1 USDG). Computed as u * 1e30 / t
bpsparts per 10,000 (BPS = 10_000)

Reserves

The curve is a constant-product AMM whose USDG side starts with a virtual balance so the first token has a non-zero price:

supplyOnCurve = curveSupply − teamAllocation                     // set once in initialize()
virtualUsdg   = graduationUsdg × (virtualTokens − supplyOnCurve) / supplyOnCurve

u = virtualUsdg  + usdgRaised          // USDG reserve
t = virtualTokens − tokensSold         // token reserve
k = u × t
price = u / t                          // reported as u × 1e30 / t

Deriving virtualUsdg from the graduation raise means that selling exactly supplyOnCurve tokens always raises exactly graduationUsdg, whatever team allocation the creator chose.

With the defaults (virtualTokens = 1,073,000,000e18, curveSupply = 800,000,000e18, no team, graduationUsdg = 12,400e6): virtualUsdg = 12,400 × 273 / 800 = 4,231.5 USDG.

Buy

quoteBuy(usdgIn) and buy(usdgIn, minTokensOut, to):

fee       = usdgIn × tradeFeeBps / BPS
net       = usdgIn − fee
tokensOut = t − ceil(k / (u + net))                      // constant product, rounded against the buyer
remaining = supplyOnCurve − tokensSold

if tokensOut ≥ remaining:                                 // the buy would overshoot the curve
    tokensOut = remaining
    usdgUsed  = ceil(k / (t − remaining)) − u             // exact USDG to buy out the curve
    usdgUsed  = min(usdgUsed, net)                        // rounding guard
    fee       = usdgUsed × tradeFeeBps / (BPS − tradeFeeBps)   // fee re-based on what was used
else:
    usdgUsed  = net

The buyer transfers usdgUsed + fee; anything above that stays in the buyer's wallet (nothing is pulled and refunded). buy reverts with Slippage if tokensOut < minTokensOut. When tokensSold == supplyOnCurve after the buy, the same transaction graduates the curve.

Sell

quoteSell(tokensIn) and sell(tokensIn, minUsdgOut, to):

gross   = u − ceil(k / (t + tokensIn))                   // rounded against the seller
fee     = gross × tradeFeeBps / BPS
usdgOut = gross − fee

usdgRaised decreases by gross (so the curve's own accounting stays exact) and the fee is paid from the gross. tokensIn > tokensSold reverts with Slippage.

Fees

toCreator = fee × creatorShareBps / BPS      → transferred to creator immediately, added to creatorFeesEarned
toTreasury = fee − toCreator                 → transferred to treasury

No fee is ever held by the curve.

Batch settlement

The batch is settled as one buy of batchUsdg:

fee = batchUsdg × tradeFeeBps / BPS
(tokensOut, usdgUsed) = _quoteBuy(batchUsdg − fee)
if usdgUsed < batchUsdg − fee:   fee = usdgUsed × tradeFeeBps / (BPS − tradeFeeBps)   // batch alone sold out the curve
batchRefund      = batchUsdg − usdgUsed − fee
clearingPrice    = usdgUsed × 1e30 / tokensOut            // emitted in BatchSettled
claim(buyer)     = tokensOut × commit / batchUsdg,  refund × commit / batchUsdg

Worked example (defaults, empty curve)

BuyFeeNetTokens outAvg pricePrice after
100 USDG1.0099.00≈ 24.5M≈ 0.0000040≈ 0.0000041
1,000 USDG10.00990.00≈ 203.4M≈ 0.0000049≈ 0.0000060
5,000 USDG50.004,950.00≈ 578.5M≈ 0.0000086≈ 0.0000186
12,525.25 USDG125.2512,400.00800M (sells out)0.0000155graduates

Figures rounded; the simulator prints the exact bigint results on the live parameters.

Progress

progressBps() = tokensSold × BPS / supplyOnCurve. The app shows it as a percentage and switches tabs at 60% ("Graduating").