Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}