utils.gno
5.97 Kb ยท 210 lines
1package v1
2
3import (
4 "strconv"
5 "strings"
6
7 "gno.land/p/demo/tokens/grc721"
8 prabc "gno.land/p/gnoswap/rbac"
9 u256 "gno.land/p/gnoswap/uint256"
10 "gno.land/p/nt/ufmt"
11 "gno.land/r/gnoswap/access"
12)
13
14const MAX_UINT256 string = "115792089237316195423570985008687907853269984665640564039457584007913129639935"
15
16func mustGetPositionAddress() address {
17 return access.MustGetAddress(prabc.ROLE_POSITION.String())
18}
19
20func mustGetStakerAddress() address {
21 return access.MustGetAddress(prabc.ROLE_STAKER.String())
22}
23
24// positionIdFrom converts positionId to grc721.TokenID type
25// NOTE: input parameter positionId can be string, int, uint64, or grc721.TokenID
26// if positionId is nil or not supported, it will panic
27// if positionId is not found, it will panic
28// input: positionId any
29// output: grc721.TokenID
30func positionIdFrom(positionId any) grc721.TokenID {
31 if positionId == nil {
32 panic(newErrorWithDetail(errInvalidInput, "positionId is nil"))
33 }
34
35 switch positionId.(type) {
36 case string:
37 return grc721.TokenID(positionId.(string))
38 case int:
39 return grc721.TokenID(strconv.Itoa(positionId.(int)))
40 case uint64:
41 return grc721.TokenID(strconv.Itoa(int(positionId.(uint64))))
42 case grc721.TokenID:
43 return positionId.(grc721.TokenID)
44 default:
45 panic(newErrorWithDetail(errInvalidInput, "unsupported positionId type"))
46 }
47}
48
49// exists checks whether positionId exists
50// If positionId doesn't exist, return false, otherwise return true
51// input: positionId uint64
52// output: bool
53func (p *positionV1) exists(positionId uint64) bool {
54 return p.nftAccessor.Exists(positionIdFrom(positionId))
55}
56
57// isOwner checks whether the caller is the owner of the positionId
58// If the caller is the owner of the positionId, return true, otherwise return false
59// input: positionId uint64, addr std.Address
60// output: bool
61func (p *positionV1) isOwner(positionId uint64, addr address) bool {
62 owner, err := p.nftAccessor.OwnerOf(positionIdFrom(positionId))
63 if err != nil {
64 return false
65 }
66 return owner == addr
67}
68
69// isOperator checks whether the caller is the approved operator of the positionId
70// If the caller is the approved operator of the positionId, return true, otherwise return false
71// input: positionId uint64, addr std.Address
72// output: bool
73func (p *positionV1) isOperator(positionId uint64, addr address) bool {
74 return p.GetPositionOperator(positionId) == addr
75}
76
77// isStaked checks whether positionId is staked
78// If positionId is staked, owner of positionId is staker contract
79// If positionId is staked, return true, otherwise return false
80// input: positionId grc721.TokenID
81// output: bool
82func (p *positionV1) isStaked(positionId grc721.TokenID) bool {
83 exist := p.nftAccessor.Exists(positionId)
84 if !exist {
85 return false
86 }
87 owner, err := p.nftAccessor.OwnerOf(positionId)
88 if err == nil && owner == mustGetStakerAddress() {
89 return true
90 }
91 return false
92}
93
94// isOwnerOrOperator checks whether the caller is the owner or approved operator of the positionId
95// If the caller is the owner or approved operator of the positionId, return true, otherwise return false
96// input: addr std.Address, positionId uint64
97// output: bool
98func (p *positionV1) isOwnerOrOperator(positionId uint64, addr address) bool {
99 if !addr.IsValid() || !p.exists(positionId) {
100 return false
101 }
102
103 if p.isStaked(positionIdFrom(positionId)) {
104 return p.isOperator(positionId, addr)
105 }
106
107 return p.isOwner(positionId, addr)
108}
109
110// splitOf divides poolKey into pToken0, pToken1, and pFee
111// If poolKey is invalid, it will panic
112//
113// input: poolKey string
114// output:
115// - token0Path string
116// - token1Path string
117// - fee uint32
118func splitOf(poolKey string) (string, string, uint32) {
119 res := strings.Split(poolKey, ":")
120 if len(res) != 3 {
121 panic(newErrorWithDetail(errInvalidInput, ufmt.Sprintf("invalid poolKey(%s)", poolKey)))
122 }
123
124 pToken0, pToken1, pFeeStr := res[0], res[1], res[2]
125
126 pFee, err := strconv.Atoi(pFeeStr)
127 if err != nil {
128 panic(newErrorWithDetail(errInvalidInput, ufmt.Sprintf("invalid fee(%s)", pFeeStr)))
129 }
130
131 return pToken0, pToken1, uint32(pFee)
132}
133
134func formatUint(v any) string {
135 switch v := v.(type) {
136 case uint8:
137 return strconv.FormatUint(uint64(v), 10)
138 case uint32:
139 return strconv.FormatUint(uint64(v), 10)
140 case uint64:
141 return strconv.FormatUint(v, 10)
142 default:
143 panic(ufmt.Sprintf("invalid type: %T", v))
144 }
145}
146
147func formatInt(v any) string {
148 switch v := v.(type) {
149 case int32:
150 return strconv.FormatInt(int64(v), 10)
151 case int64:
152 return strconv.FormatInt(v, 10)
153 case int:
154 return strconv.Itoa(v)
155 default:
156 panic(ufmt.Sprintf("invalid type: %T", v))
157 }
158}
159
160func formatBool(v bool) string {
161 return strconv.FormatBool(v)
162}
163
164func mustParseInt64(v string) int64 {
165 amountInt, err := strconv.ParseInt(v, 10, 64)
166 if err != nil {
167 panic(err)
168 }
169
170 return amountInt
171}
172
173func isSlippageExceeded(amount0, amount1, amount0Min, amount1Min *u256.Uint) bool {
174 return !(amount0.Gte(amount0Min) && amount1.Gte(amount1Min))
175}
176
177func subUint256(x, y *u256.Uint) *u256.Uint {
178 if x.Cmp(y) < 0 {
179 diff := u256.Zero().Sub(u256.MustFromDecimal(MAX_UINT256), y)
180 result := u256.Zero().Add(diff, x)
181 return result.Add(result, u256.One())
182 }
183
184 return u256.Zero().Sub(x, y)
185}
186
187// safeConvertToInt64 safely converts a *u256.Uint value to an int64, ensuring no overflow.
188//
189// This function attempts to convert the given *u256.Uint value to an int64. If the value exceeds
190// the maximum allowable range for int64 (`2^63 - 1`), it triggers a panic with a descriptive error message.
191//
192// Parameters:
193// - value (*u256.Uint): The unsigned 256-bit integer to be converted.
194//
195// Returns:
196// - int64: The converted value if it falls within the int64 range.
197//
198// Panics:
199// - If the `value` exceeds the range of int64, the function will panic with an error indicating
200// the overflow and the original value.
201func safeConvertToInt64(value *u256.Uint) int64 {
202 res, overflow := value.Uint64WithOverflow()
203 if overflow || res > 9223372036854775807 {
204 panic(ufmt.Sprintf(
205 "amount(%s) overflows int64 range (max: 9223372036854775807)",
206 value.ToString(),
207 ))
208 }
209 return int64(res)
210}