Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

safemath.gno

1.77 Kb · 92 lines
 1// Package safemath is checked, non-negative int64 arithmetic for launchpad amounts.
 2package safemath
 3
 4import "math/bits"
 5
 6const (
 7	MaxInt64       int64 = 1<<63 - 1
 8	BPSDenominator int64 = 10_000
 9)
10
11func mustNonNegative(v int64) {
12	if v < 0 {
13		panic("launchpad/safemath: negative value")
14	}
15}
16
17func 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 + b
24}
25
26func Sub(a, b int64) int64 {
27	mustNonNegative(a)
28	mustNonNegative(b)
29	if b > a {
30		panic("launchpad/safemath: underflow")
31	}
32	return a - b
33}
34
35func 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 * b
42}
43
44// 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 q
48}
49
50// 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 q
60}
61
62func 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 != 0
77}
78
79// 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}
86
87func Min(a, b int64) int64 {
88	if a < b {
89		return a
90	}
91	return b
92}