utils.gno
4.91 Kb ยท 206 lines
1package v1
2
3import (
4 "math"
5 "strconv"
6 "strings"
7
8 "gno.land/p/demo/tokens/grc721"
9 i256 "gno.land/p/gnoswap/int256"
10 u256 "gno.land/p/gnoswap/uint256"
11 "gno.land/p/nt/ufmt"
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 various types to grc721.TokenID.
26func positionIdFrom(positionId any) grc721.TokenID {
27 if positionId == nil {
28 panic(makeErrorWithDetails(
29 errDataNotFound,
30 "positionId is nil",
31 ))
32 }
33
34 switch positionId.(type) {
35 case string:
36 return grc721.TokenID(positionId.(string))
37 case int:
38 return grc721.TokenID(strconv.Itoa(positionId.(int)))
39 case uint64:
40 return grc721.TokenID(strconv.Itoa(int(positionId.(uint64))))
41 case grc721.TokenID:
42 return positionId.(grc721.TokenID)
43 default:
44 panic(makeErrorWithDetails(
45 errInvalidInput,
46 ufmt.Sprintf("unsupported positionId type(%T)", positionId),
47 ))
48 }
49}
50
51// max returns the larger of two int64 values.
52func max(x, y int64) int64 {
53 if x > y {
54 return x
55 }
56 return y
57}
58
59// min returns the smaller of two uint64 values.
60func min(x, y uint64) uint64 {
61 if x < y {
62 return x
63 }
64 return y
65}
66
67// contains checks if a string exists in a slice.
68func contains(slice []string, item string) bool {
69 // We can use strings.EqualFold here, but this function should be case-sensitive.
70 // So, it is better to compare strings directly.
71 for _, element := range slice {
72 if element == item {
73 return true
74 }
75 }
76 return false
77}
78
79// formatUint formats an unsigned integer to string.
80func formatUint(v any) string {
81 switch v := v.(type) {
82 case uint8:
83 return strconv.FormatUint(uint64(v), 10)
84 case uint32:
85 return strconv.FormatUint(uint64(v), 10)
86 case uint64:
87 return strconv.FormatUint(v, 10)
88 default:
89 panic(ufmt.Sprintf("invalid type for Unsigned: %T", v))
90 }
91}
92
93// formatAnyInt formats a signed integer to string.
94func formatAnyInt(v any) string {
95 switch v := v.(type) {
96 case int32:
97 return strconv.FormatInt(int64(v), 10)
98 case int64:
99 return strconv.FormatInt(v, 10)
100 case int:
101 return strconv.Itoa(v)
102 default:
103 panic(ufmt.Sprintf("invalid type for Signed: %T", v))
104 }
105}
106
107// formatBool formats a boolean to string.
108func formatBool(v bool) string {
109 return strconv.FormatBool(v)
110}
111
112// safeConvertToInt64 safely converts a *u256.Uint value to an int64, ensuring no overflow.
113//
114// This function attempts to convert the given *u256.Uint value to an int64. If the value exceeds
115// the maximum allowable range for int64 (`2^63 - 1`), it triggers a panic with a descriptive error message.
116//
117// Parameters:
118// - value (*u256.Uint): The unsigned 256-bit integer to be converted.
119//
120// Returns:
121// - int64: The converted value if it falls within the int64 range.
122//
123// Panics:
124// - If the `value` exceeds the range of int64, the function will panic with an error indicating
125// the overflow and the original value.
126func safeConvertToInt64(value *u256.Uint) int64 {
127 const INT64_MAX = 9223372036854775807
128 res, overflow := value.Uint64WithOverflow()
129 if overflow || res > uint64(INT64_MAX) {
130 panic(ufmt.Sprintf(
131 "amount(%s) overflows int64 range (max: 9223372036854775807)",
132 value.ToString(),
133 ))
134 }
135 return int64(res)
136}
137
138// safeMulInt64 performs safe multiplication of int64 values, panicking on overflow or underflow
139func safeMulInt64(a, b int64) int64 {
140 if a == 0 || b == 0 {
141 return 0
142 }
143 if a > 0 && b > 0 {
144 if a > math.MaxInt64/b {
145 panic("int64 multiplication overflow")
146 }
147 } else if a < 0 && b < 0 {
148 if a < math.MaxInt64/b {
149 panic("int64 multiplication overflow")
150 }
151 } else if a > 0 && b < 0 {
152 if b < math.MinInt64/a {
153 panic("int64 multiplication underflow")
154 }
155 } else { // a < 0 && b > 0
156 if a < math.MinInt64/b {
157 panic("int64 multiplication underflow")
158 }
159 }
160 return a * b
161}
162
163// safeAddInt64 performs safe addition of int64 values, panicking on overflow or underflow
164func safeAddInt64(a, b int64) int64 {
165 if a > 0 && b > math.MaxInt64-a {
166 panic("int64 addition overflow")
167 }
168 if a < 0 && b < math.MinInt64-a {
169 panic("int64 addition underflow")
170 }
171 return a + b
172}
173
174// safeSubInt64 performs safe subtraction of int64 values, panicking on overflow or underflow
175func safeSubInt64(a, b int64) int64 {
176 if b > 0 && a < math.MinInt64+b {
177 panic("int64 subtraction underflow")
178 }
179 if b < 0 && a > math.MaxInt64+b {
180 panic("int64 subtraction overflow")
181 }
182 return a - b
183}
184
185func safeMulDivInt64(a, b, c int64) int64 {
186 if c == 0 {
187 panic("division by zero in safeMulDivInt64")
188 }
189
190 if a == 0 || b == 0 {
191 return 0
192 }
193
194 // calculate amount to swap for this route
195 result, overflow := i256.Zero().MulOverflow(i256.NewInt(a), i256.NewInt(b))
196 if overflow {
197 panic(errOverflow)
198 }
199
200 result = i256.Zero().Div(result, i256.NewInt(c))
201 if !result.IsInt64() {
202 panic(errOverflow)
203 }
204
205 return result.Int64()
206}