Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}