utils.gno
4.47 Kb · 176 lines
1package v1
2
3import (
4 "math"
5 "strconv"
6 "strings"
7
8 "gno.land/p/gnoswap/deps/grc721"
9 i256 "gno.land/p/gnoswap/int256"
10 u256 "gno.land/p/gnoswap/uint256"
11 ufmt "gno.land/p/nt/ufmt/v0"
12)
13
14// poolPathDivide splits a pool path into token addresses and fee tier.
15func poolPathDivide(poolPath string) (string, string, string) {
16 res := strings.Split(poolPath, ":")
17 if len(res) != 3 {
18 panic(errInvalidPoolPath)
19 }
20
21 pToken0, pToken1, fee := res[0], res[1], res[2]
22 return pToken0, pToken1, fee
23}
24
25// positionIdFrom converts a uint64 position ID to grc721.TokenID.
26func positionIdFrom(positionId uint64) grc721.TokenID {
27 return grc721.TokenID(strconv.FormatUint(positionId, 10))
28}
29
30// contains checks if a string exists in a slice.
31func contains(slice []string, item string) bool {
32 // We can use strings.EqualFold here, but this function should be case-sensitive.
33 // So, it is better to compare strings directly.
34 for _, element := range slice {
35 if element == item {
36 return true
37 }
38 }
39 return false
40}
41
42// formatUint formats an unsigned integer to string.
43func formatUint(v any) string {
44 switch v := v.(type) {
45 case uint8:
46 return strconv.FormatUint(uint64(v), 10)
47 case uint32:
48 return strconv.FormatUint(uint64(v), 10)
49 case uint64:
50 return strconv.FormatUint(v, 10)
51 default:
52 panic(ufmt.Sprintf("invalid type for Unsigned: %T", v))
53 }
54}
55
56// formatAnyInt formats a signed integer to string.
57func formatAnyInt(v any) string {
58 switch v := v.(type) {
59 case int32:
60 return strconv.FormatInt(int64(v), 10)
61 case int64:
62 return strconv.FormatInt(v, 10)
63 case int:
64 return strconv.Itoa(v)
65 default:
66 panic(ufmt.Sprintf("invalid type for Signed: %T", v))
67 }
68}
69
70// formatBool formats a boolean to string.
71func formatBool(v bool) string {
72 return strconv.FormatBool(v)
73}
74
75// safeConvertToInt64 safely converts a *u256.Uint value to an int64, ensuring no overflow.
76//
77// This function attempts to convert the given *u256.Uint value to an int64. If the value exceeds
78// the maximum allowable range for int64 (`2^63 - 1`), it triggers a panic with a descriptive error message.
79//
80// Parameters:
81// - value (*u256.Uint): The unsigned 256-bit integer to be converted.
82//
83// Returns:
84// - int64: The converted value if it falls within the int64 range.
85//
86// Panics:
87// - If the `value` exceeds the range of int64, the function will panic with an error indicating
88// the overflow and the original value.
89func safeConvertToInt64(value *u256.Uint) int64 {
90 const INT64_MAX = 9223372036854775807
91 res, overflow := value.Uint64WithOverflow()
92 if overflow || res > uint64(INT64_MAX) {
93 panic(ufmt.Sprintf(
94 "amount(%s) overflows int64 range (max: 9223372036854775807)",
95 value.ToString(),
96 ))
97 }
98 return int64(res)
99}
100
101// safeMulInt64 performs safe multiplication of int64 values, panicking on overflow or underflow
102func safeMulInt64(a, b int64) int64 {
103 if a == 0 || b == 0 {
104 return 0
105 }
106 if a > 0 && b > 0 {
107 if a > math.MaxInt64/b {
108 panic("int64 multiplication overflow")
109 }
110 } else if a < 0 && b < 0 {
111 if a < math.MaxInt64/b {
112 panic("int64 multiplication overflow")
113 }
114 } else if a > 0 && b < 0 {
115 if b < math.MinInt64/a {
116 panic("int64 multiplication underflow")
117 }
118 } else { // a < 0 && b > 0
119 if a < math.MinInt64/b {
120 panic("int64 multiplication underflow")
121 }
122 }
123 return a * b
124}
125
126// safeAddInt64 performs safe addition of int64 values, panicking on overflow or underflow
127func safeAddInt64(a, b int64) int64 {
128 if a > 0 && b > math.MaxInt64-a {
129 panic("int64 addition overflow")
130 }
131 if a < 0 && b < math.MinInt64-a {
132 panic("int64 addition underflow")
133 }
134 return a + b
135}
136
137// safeSubInt64 performs safe subtraction of int64 values, panicking on overflow or underflow
138func safeSubInt64(a, b int64) int64 {
139 if b > 0 && a < math.MinInt64+b {
140 panic("int64 subtraction underflow")
141 }
142 if b < 0 && a > math.MaxInt64+b {
143 panic("int64 subtraction overflow")
144 }
145 return a - b
146}
147
148// safeUint64ToInt64 safely converts a uint64 value to int64, panicking on overflow.
149func safeUint64ToInt64(value uint64) int64 {
150 if value > uint64(math.MaxInt64) {
151 panic(ufmt.Sprintf(
152 "amount(%d) overflows int64 range (max: 9223372036854775807)",
153 value,
154 ))
155 }
156 return int64(value)
157}
158
159func safeMulDivInt64(a, b, c int64) int64 {
160 if a == 0 || b == 0 {
161 return 0
162 }
163
164 // calculate amount to swap for this route
165 result, overflow := i256.Zero().MulOverflow(i256.NewInt(a), i256.NewInt(b))
166 if overflow {
167 panic(errOverflow)
168 }
169
170 result = i256.Zero().Div(result, i256.NewInt(c))
171 if !result.IsInt64() {
172 panic(errOverflow)
173 }
174
175 return result.Int64()
176}