utils.gno
6.52 Kb · 212 lines
1package v1
2
3import (
4 "math"
5 "strconv"
6
7 i256 "gno.land/p/gnoswap/int256"
8 u256 "gno.land/p/gnoswap/uint256"
9 ufmt "gno.land/p/nt/ufmt/v0"
10)
11
12const (
13 MAX_UINT64 string = "18446744073709551615"
14 MAX_INT64 string = "9223372036854775807"
15 MAX_INT128 string = "170141183460469231731687303715884105727"
16 MAX_UINT128 string = "340282366920938463463374607431768211455"
17 MAX_INT256 string = "57896044618658097711785492504343953926634992332820282019728792003956564819967"
18
19 INT64_MIN int64 = -9223372036854775808
20 INT64_MAX int64 = 9223372036854775807
21
22 Q96_RESOLUTION uint = 96
23 Q128_RESOLUTION uint = 128
24
25 Q64 string = "18446744073709551616" // 2 ** 64
26 Q96 string = "79228162514264337593543950336" // 2 ** 96
27 Q128 string = "340282366920938463463374607431768211456" // 2 ** 128
28)
29
30var (
31 maxInt128FromDecimal = i256.MustFromDecimal(MAX_INT128)
32 maxUint128FromDecimal = u256.MustFromDecimal(MAX_UINT128)
33 q128FromDecimal = u256.MustFromDecimal(Q128)
34)
35
36var uint128Mask = func() *u256.Uint {
37 m := u256.Zero().Lsh(u256.One(), Q128_RESOLUTION)
38 return m.Sub(m, u256.One())
39}()
40
41// safeConvertToInt64 safely converts a *u256.Uint value to an int64, ensuring no overflow.
42// This function attempts to convert the given *u256.Uint value to an int64.
43// If the value exceeds the maximum allowable range for int64 (2^63 - 1), it panics.
44func safeConvertToInt64(value *u256.Uint) int64 {
45 if value == nil {
46 panic(newErrorWithDetail(errInvalidInput, "value is nil"))
47 }
48 res, overflow := value.Uint64WithOverflow()
49 if overflow || res > uint64(INT64_MAX) {
50 panic(ufmt.Sprintf(
51 "%v: amount(%s) overflows int64 range (max %s)",
52 errOutOfRange,
53 value.ToString(),
54 MAX_INT64,
55 ))
56 }
57 return int64(res)
58}
59
60// safeConvertToInt128 safely converts a *u256.Uint value to an *i256.Int, ensuring it does not exceed the int128 range.
61// This function converts an unsigned 256-bit integer to a signed 256-bit integer.
62// If the value exceeds the maximum allowable int128 range (2^127 - 1), it panics.
63func safeConvertToInt128(value *u256.Uint) *i256.Int {
64 liquidityDelta := i256.FromUint256(value)
65 if liquidityDelta.Gt(maxInt128FromDecimal) {
66 panic(ufmt.Sprintf(
67 "%v: amount(%s) overflows int128 range",
68 errOverflow, value.ToString()))
69 }
70 return liquidityDelta
71}
72
73// toUint128 ensures a *u256.Uint value fits within the uint128 range.
74//
75// This function validates that the given `value` is properly initialized and checks whether
76// it exceeds the maximum value of uint128. If the value exceeds the uint128 range,
77// it applies a masking operation to truncate the value to fit within the uint128 limit.
78//
79// Parameters:
80// - value: *u256.Uint, the value to be checked and possibly truncated.
81//
82// Returns:
83// - *u256.Uint: A value guaranteed to fit within the uint128 range.
84//
85// Notes:
86// - The function first checks if the value is not nil to avoid potential runtime errors.
87// - The mask ensures that only the lower 128 bits of the value are retained.
88// - If the input value is already within the uint128 range, it is returned unchanged.
89// - If masking is required, a new instance is returned without modifying the input.
90// - MAX_UINT128 is a constant representing `2^128 - 1`.
91func toUint128(value *u256.Uint) *u256.Uint {
92 if value == nil {
93 panic(newErrorWithDetail(errInvalidInput, "value is nil"))
94 }
95
96 if value.Gt(maxUint128FromDecimal) {
97 return u256.Zero().And(value, uint128Mask)
98 }
99 return value
100}
101
102// u256Min returns the smaller of two *u256.Uint values.
103//
104// This function compares two unsigned 256-bit integers and returns the smaller of the two.
105// If `num1` is less than `num2`, it returns `num1`; otherwise, it returns `num2`.
106//
107// Parameters:
108// - num1 (*u256.Uint): The first unsigned 256-bit integer.
109// - num2 (*u256.Uint): The second unsigned 256-bit integer.
110//
111// Returns:
112// - *u256.Uint: The smaller of `num1` and `num2`.
113//
114// Notes:
115// - This function uses the `Lt` (less than) method of `*u256.Uint` to perform the comparison.
116// - The function assumes both input values are non-nil. If nil inputs are possible in the usage context,
117// additional validation may be needed.
118//
119// Example:
120// smaller := u256Min(u256.MustFromDecimal("10"), u256.MustFromDecimal("20")) // Returns 10
121// smaller := u256Min(u256.MustFromDecimal("30"), u256.MustFromDecimal("20")) // Returns 20
122func u256Min(num1, num2 *u256.Uint) *u256.Uint {
123 if num1.Lt(num2) {
124 return num1
125 }
126 return num2
127}
128
129// checkOverFlowInt128 checks if the value overflows the int128 range.
130func checkOverFlowInt128(value *i256.Int) {
131 if value.Gt(maxInt128FromDecimal) {
132 panic(ufmt.Sprintf(
133 "%v: amount(%s) overflows int128 range",
134 errOverflow, value.ToString()))
135 }
136}
137
138// checkTickSpacing checks if the tick is divisible by the tickSpacing.
139func checkTickSpacing(tick, tickSpacing int32) {
140 if tick%tickSpacing != 0 {
141 panic(newErrorWithDetail(
142 errInvalidTickAndTickSpacing,
143 ufmt.Sprintf("tick(%d) MOD tickSpacing(%d) != 0(%d)", tick, tickSpacing, tick%tickSpacing),
144 ))
145 }
146}
147
148// formatUint converts various unsigned integer types to string representation.
149func formatUint(v any) string {
150 switch v := v.(type) {
151 case uint8:
152 return strconv.FormatUint(uint64(v), 10)
153 case uint16:
154 return strconv.FormatUint(uint64(v), 10)
155 case uint32:
156 return strconv.FormatUint(uint64(v), 10)
157 case uint64:
158 return strconv.FormatUint(v, 10)
159 default:
160 panic(ufmt.Sprintf("invalid type: %T", v))
161 }
162}
163
164// formatInt converts various signed integer types to string representation.
165func formatInt(v any) string {
166 switch v := v.(type) {
167 case int32:
168 return strconv.FormatInt(int64(v), 10)
169 case int64:
170 return strconv.FormatInt(v, 10)
171 case int:
172 return strconv.Itoa(v)
173 default:
174 panic(ufmt.Sprintf("invalid type: %T", v))
175 }
176}
177
178// formatBool converts a boolean value to string representation.
179func formatBool(v bool) string {
180 return strconv.FormatBool(v)
181}
182
183// safeAddInt64 performs safe addition of int64 values, panicking on overflow or underflow
184func safeAddInt64(a, b int64) int64 {
185 if a > 0 && b > math.MaxInt64-a {
186 panic("int64 addition overflow")
187 }
188 if a < 0 && b < math.MinInt64-a {
189 panic("int64 addition underflow")
190 }
191 return a + b
192}
193
194// safeSubInt64 performs safe subtraction of int64 values, panicking on overflow or underflow
195func safeSubInt64(a, b int64) int64 {
196 if b > 0 && a < math.MinInt64+b {
197 panic("int64 subtraction underflow")
198 }
199 if b < 0 && a > math.MaxInt64+b {
200 panic("int64 subtraction overflow")
201 }
202 return a - b
203}
204
205func safeParseInt64(value string) int64 {
206 amountInt64, err := strconv.ParseInt(value, 10, 64)
207 if err != nil {
208 panic(err)
209 }
210
211 return amountInt64
212}