utils.gno
2.81 Kb · 132 lines
1package personal_world
2
3import "gno.land/r/akkadia/v0/admin"
4
5func copyStringMap(source map[string]string) map[string]string {
6 if source == nil {
7 return nil
8 }
9 result := map[string]string{}
10 for key, value := range source {
11 result[key] = value
12 }
13 return result
14}
15
16func copyStringSlice(source []string) []string {
17 if source == nil {
18 return nil
19 }
20 result := make([]string, len(source))
21 for i, value := range source {
22 result[i] = value
23 }
24 return result
25}
26
27const (
28 maxInt64 = int64(9223372036854775807)
29)
30
31func assertCanGrantRole(worldID uint32, caller address, roleName string) {
32 if admin.IsAdmin(caller) || isOwner(worldID, caller) {
33 return
34 }
35 if HasPermission(worldID, caller, "role:grant") && hasGrantableRole(worldID, caller, roleName) {
36 return
37 }
38 panic("cannot grant role: caller lacks permission to assign role '" + roleName + "'")
39}
40
41func assertCanRevokeRole(worldID uint32, caller address, roleName string) {
42 if admin.IsAdmin(caller) || isOwner(worldID, caller) {
43 return
44 }
45 if HasPermission(worldID, caller, "role:revoke") && hasRevokableRole(worldID, caller, roleName) {
46 return
47 }
48 panic("cannot revoke role: caller lacks permission to revoke role '" + roleName + "'")
49}
50
51func parseCSVMap(keys, values string, panicMessagePrefix string) map[string]string {
52 pending := map[string]string{}
53 keyStart, valStart := 0, 0
54 keyIdx, valIdx := 0, 0
55 for {
56 for keyIdx < len(keys) && keys[keyIdx] != ',' {
57 keyIdx++
58 }
59 for valIdx < len(values) && values[valIdx] != ',' {
60 valIdx++
61 }
62
63 key := keys[keyStart:keyIdx]
64 val := values[valStart:valIdx]
65 pending[key] = val
66
67 keyEnd := keyIdx >= len(keys)
68 valEnd := valIdx >= len(values)
69
70 if keyEnd != valEnd {
71 panic(panicMessagePrefix + " keys and values count mismatch")
72 }
73 if keyEnd {
74 break
75 }
76
77 keyIdx++
78 valIdx++
79 keyStart = keyIdx
80 valStart = valIdx
81 }
82
83 return pending
84}
85
86func calculateBPSShares(amount int64, bps int64) (int64, int64) {
87 if amount <= 0 {
88 return 0, 0
89 }
90 denominator := int64(10000)
91 first := (amount/denominator)*bps + ((amount%denominator)*bps)/denominator
92 return first, amount - first
93}
94
95func multiplyByBPS(amount int64, bps int64, panicMsg string) int64 {
96 if amount <= 0 {
97 return 0
98 }
99 if bps < 0 {
100 panic(panicMsg)
101 }
102
103 denominator := int64(10000)
104 wholeAmount := amount / denominator
105 remainingAmount := amount % denominator
106 first := safeMultiply(wholeAmount, bps, panicMsg)
107 second := safeMultiply(remainingAmount, bps, panicMsg) / denominator
108 return safeAdd(first, second, panicMsg)
109}
110
111func safeMultiply(a int64, b int64, panicMsg string) int64 {
112 if a == 0 || b == 0 {
113 return 0
114 }
115 if a < 0 || b < 0 {
116 panic(panicMsg)
117 }
118 if a > maxInt64/b {
119 panic(panicMsg)
120 }
121 return a * b
122}
123
124func safeAdd(a int64, b int64, panicMsg string) int64 {
125 if a < 0 || b < 0 {
126 panic(panicMsg)
127 }
128 if a > maxInt64-b {
129 panic(panicMsg)
130 }
131 return a + b
132}