Search Apps Documentation Source Content File Folder Download Copy Actions Download 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}