1// Package safemath is checked, non-negative int64 arithmetic for launchpad amounts.2package safemath34import "math/bits"56const (7 MaxInt64 int64 = 1<<63 - 18 BPSDenominator int64 = 10_0009)1011func mustNonNegative(v int64) {12 if v < 0 {13 panic("launchpad/safemath: negative value")14 }15}1617func Add(a, b int64) int64 {18 mustNonNegative(a)19 mustNonNegative(b)20 if a > MaxInt64-b {21 panic("launchpad/safemath: overflow")22 }23 return a + b24}2526func Sub(a, b int64) int64 {27 mustNonNegative(a)28 mustNonNegative(b)29 if b > a {30 panic("launchpad/safemath: underflow")31 }32 return a - b33}3435func Mul(a, b int64) int64 {36 mustNonNegative(a)37 mustNonNegative(b)38 if a != 0 && b > MaxInt64/a {39 panic("launchpad/safemath: overflow")40 }41 return a * b42}4344// MulDiv returns floor(a*b/d) using a 128-bit intermediate.45func MulDiv(a, b, d int64) int64 {46 q, _ := mulDivRem(a, b, d)47 return q48}4950// MulDivUp returns ceil(a*b/d) using a 128-bit intermediate.51func MulDivUp(a, b, d int64) int64 {52 q, rem := mulDivRem(a, b, d)53 if rem {54 if q == MaxInt64 {55 panic("launchpad/safemath: overflow")56 }57 q++58 }59 return q60}6162func mulDivRem(a, b, d int64) (int64, bool) {63 mustNonNegative(a)64 mustNonNegative(b)65 if d <= 0 {66 panic("launchpad/safemath: division by zero")67 }68 hi, lo := bits.Mul64(uint64(a), uint64(b))69 if hi >= uint64(d) {70 panic("launchpad/safemath: overflow")71 }72 q, r := bits.Div64(hi, lo, uint64(d))73 if q > uint64(MaxInt64) {74 panic("launchpad/safemath: overflow")75 }76 return int64(q), r != 077}7879// BPS returns floor(amount*bps/10000) for 0 <= bps <= 10000.80func BPS(amount, bps int64) int64 {81 if bps < 0 || bps > BPSDenominator {82 panic("launchpad/safemath: basis points out of range")83 }84 return MulDiv(amount, bps, BPSDenominator)85}8687func Min(a, b int64) int64 {88 if a < b {89 return a90 }91 return b92}93Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.