1// Package curve is a linear, one-way bonding curve for issuing a token against a2// reserve: price rises linearly with the position on the curve, and the cost of3// minting is the exact integral, computed in 128-bit so it never overflows and4// never issues a coin for less than its backing.5//6// # Why a reciprocal slope7//8// The marginal price is p(s) = s/D — a RECIPROCAL denominator D, not a numerator9// slope. That is not cosmetic. The cost of moving from s0 to s1 is the integral10// (s1²−s0²)/(2D). With a numerator slope k the product k·(s1²−s0²) can exceed11// 2^128 for a realistic k at a large supply, and the single 128-bit multiply12// overflows. As 1/D the numerator is only s1²−s0², at most cap² which for a cap13// near 9.2e14 is about 2^100 — always inside 128 bits — and D sits safely in the14// divisor. D is chosen from economics: larger D is a gentler curve.15//16// # No coin is ever minted below its backing17//18// Two rounding rules, and one belt-and-suspenders check, guarantee it:19//20// - Cost rounds UP. The buyer pays at least the integral, so backing (the sum21// of integrals) never exceeds treasury (the sum charged).22// - Minted rounds DOWN. It floors the number of coins a payment buys — but it23// does not trust the square root. It uses isqrt only for a CANDIDATE, then24// corrects ±1 against the canonical Cost, so an off-by-one in the root can25// never over-issue. This re-check is mandatory, not optional.26//27// # A value, not an object28//29// A Curve is immutable configuration (the slope denominator and the position30// cap); it holds no mutable state and is never a heap object. The CURVE POSITION31// — how far up the curve issuance has walked — lives in the consuming realm as a32// monotonic counter it passes in as `from`. Burning or redeeming the token must33// NOT move that counter back: the curve prices the next mint off total-ever-34// minted, and walking it backward would let the same region be bought twice.35package curve3637import (38 "math/bits"39 "math/overflow"40)4142const maxInt64 = int64(9223372036854775807)4344// maxCap bounds the position cap so cap² ≤ 2^100 and every 128-bit operand here45// stays well inside 2^126 (where isqrt128's search bound is exact). 2^50 ≈ 1.1e1546// comfortably covers a token's ~9.2e14 supply ceiling.47const maxCap = int64(1) << 504849// Curve is a linear one-way bonding curve. Build it with New.50type Curve struct {51 d int64 // reciprocal slope: marginal price p(s) = s/d52 cap int64 // the highest position issuance may reach53}5455// New builds a curve with reciprocal slope d and position cap. A larger d is a56// gentler price rise. cap bounds the position so cap² stays inside 128 bits and57// the token's own supply ceiling is respected.58func New(d, cap int64) Curve {59 if d < 1 || d > maxInt64/2 {60 panic("curve: d must be in [1, MaxInt64/2] so 2d does not overflow")61 }62 if cap < 1 || cap > maxCap {63 panic("curve: cap must be in [1, 2^50]")64 }65 return Curve{d: d, cap: cap}66}6768// D and Cap expose the construction parameters.69func (c Curve) D() int64 { return c.d }70func (c Curve) Cap() int64 { return c.cap }7172// Cost is the coin a buyer must pay to move the position from `from` to73// `from+delta`, the integral of the price over that span, ROUNDED UP. ok is false74// when the move would pass the cap or the cost would not fit in an int64 (only at75// absurd positions). Minting zero costs zero.76func (c Curve) Cost(from, delta int64) (coin int64, ok bool) {77 if from < 0 || delta < 0 || from > c.cap {78 return 0, false79 }80 s1, add := overflow.Add64(from, delta)81 if !add || s1 > c.cap {82 return 0, false83 }84 // diff = s1² − s0², an exact 128-bit value (s1 ≥ s0 so it never borrows past 0).85 sh1, sl1 := bits.Mul64(uint64(s1), uint64(s1))86 sh0, sl0 := bits.Mul64(uint64(from), uint64(from))87 lo, borrow := bits.Sub64(sl1, sl0, 0)88 hi, _ := bits.Sub64(sh1, sh0, borrow)8990 m := uint64(2 * c.d)91 // Ceil-divide the 128-bit diff by m: (diff + m − 1) / m.92 lo2, carry := bits.Add64(lo, m-1, 0)93 hi2 := hi + carry94 if hi2 >= m {95 // The quotient would not fit int64 (and bits.Div64 REQUIRES hi < m). This IS96 // reachable well below the position cap — for the court's d=1e9 it fires around97 // s1≈1.9e14, far under cap≈9.2e14 — but only at positions whose fill cost exceeds98 // MaxInt64 µGNOT, i.e. more GNOT than can exist, so no funded Buy reaches it.99 // Do NOT delete this as "dead": Minted relies on ok=false meaning "unaffordable",100 // and without the guard bits.Div64 would violate its hi<m precondition (over-issue).101 return 0, false102 }103 q, _ := bits.Div64(hi2, lo2, m)104 if q > uint64(maxInt64) {105 // Same story one step later: the cost is a valid 128-bit value but exceeds int64,106 // so it is unaffordable (MaxInt64 µGNOT is more than the whole supply's worth).107 return 0, false108 }109 return int64(q), true110}111112// Minted is the largest whole number of coins `coin` can buy starting at position113// `from`, and the coin actually spent on them (≤ coin; the caller keeps or refunds114// the remainder). It floors: it finds a candidate with a 128-bit integer square115// root, then corrects ±1 against the canonical Cost, so issued coin is never worth116// more than what was paid, and it is zero when even one coin costs more than117// `coin`.118func (c Curve) Minted(from, coin int64) (delta, spent int64) {119 if from < 0 || from >= c.cap || coin <= 0 {120 return 0, 0121 }122 // Short-circuit a payment large enough to buy the whole remaining curve. This123 // bounds the isqrt operand below to at most cap² (so isqrt128's search bound is124 // exact) and handles the huge-coin case explicitly instead of relying on the125 // later cap clamp. When filling to the cap costs more than an int64 can hold126 // (a very steep curve), full is !ok and coin (≤ MaxInt64) is necessarily below127 // it, so we fall through — and then s1 < cap keeps the operand under cap² too.128 if full, ok := c.Cost(from, c.cap-from); ok && coin >= full {129 return c.cap - from, full130 }131 // operand = from² + 2·d·coin, a 128-bit value; s1 = floor(sqrt(operand)).132 fh, fl := bits.Mul64(uint64(from), uint64(from))133 ph, pl := bits.Mul64(uint64(2*c.d), uint64(coin))134 lo, carry := bits.Add64(fl, pl, 0)135 hi := fh + ph + carry136 r := isqrt128(hi, lo)137138 // UNREACHABLE AND LOAD-BEARING, which is not a contradiction — the same standing139 // as the hi2 >= m guard above, and it is worth being explicit because no test can140 // pin it. Nothing reaches it while the domain check at the top of this function141 // stands: on fall-through coin < full, so the operand is at most cap²−1 and r is142 // at most cap−1. There is NO margin in that bound (r does reach exactly cap−1), and143 // the clamp is the second line, not a redundant one. Delete BOTH and, on a curve144 // New will happily build, Minted(1, -1) returns 9223372036854775807 units for a145 // spend of 0 — measured, not argued: uint64(-1) makes the operand exceed isqrt128's146 // exact range, r comes back as its search bound 2^63, int64(r) is MinInt64, and147 // s1 - from WRAPS to MaxInt64, which the delta <= 0 exit below then waves through148 // as a positive mint.149 var s1 int64150 if r > uint64(c.cap) {151 s1 = c.cap // clamp before the correction so Cost never sees an over-cap span152 } else {153 s1 = int64(r)154 }155156 // Step DOWN while the rounded-up cost of reaching s1 exceeds the payment.157 for s1 > from {158 cst, ok := c.Cost(from, s1-from)159 if ok && cst <= coin {160 break161 }162 s1--163 }164 // Step UP while one more coin still fits (and stays under the cap).165 for s1 < c.cap {166 cst, ok := c.Cost(from, s1+1-from)167 if !ok || cst > coin {168 break169 }170 s1++171 }172 delta = s1 - from173 if delta <= 0 {174 return 0, 0175 }176 spent, _ = c.Cost(from, delta) // round-up cost of exactly what was minted177 return delta, spent178}179180// Price is the marginal price at position s (coin per unit), floor(s/d). Backing181// is the reserve behind one unit at position s, exactly half the marginal price —182// the reason every buyer pays about twice the backing of the coin they buy.183func (c Curve) Price(s int64) int64 { return s / c.d }184func (c Curve) Backing(s int64) int64 { return s / (2 * c.d) }185186// isqrt128 returns floor(sqrt(x)) for the 128-bit unsigned value x = hi:lo, by187// binary search on the ≤64-bit result — each step squares a candidate with a188// 128-bit multiply and compares. Division-free and deterministic.189func isqrt128(hi, lo uint64) uint64 {190 var ans, lo_ uint64191 hi_ := uint64(1) << 63 // search bound: covers every result up to sqrt(2^126)=2^63 (our operands stay < 2^100)192 for lo_ <= hi_ {193 mid := lo_ + (hi_-lo_)/2194 mh, ml := bits.Mul64(mid, mid)195 if mh < hi || (mh == hi && ml <= lo) { // mid² ≤ x196 ans = mid197 if mid == ^uint64(0) {198 break199 }200 lo_ = mid + 1201 } else {202 if mid == 0 {203 break204 }205 hi_ = mid - 1206 }207 }208 return ans209}210Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.