entry.gno
9.65 Kb · 312 lines
1package game_vault
2
3import (
4 "strconv"
5
6 "gno.land/p/akkadia/beta/accesscontrol"
7 "gno.land/r/akkadia/beta/admin"
8)
9
10type EntryProcessStatus int
11
12const (
13 EntryProcessStatusInvalid EntryProcessStatus = iota
14 EntryProcessStatusOpen
15 EntryProcessStatusClosed
16 EntryProcessStatusCanceled
17)
18
19type EntryFundStatus int
20
21const (
22 EntryFundStatusInvalid EntryFundStatus = iota
23 EntryFundStatusHeld
24 EntryFundStatusRefunded
25)
26
27type EntryProcess struct {
28 ID uint64
29 ProcessKey string
30 GameWorldID uint64
31 EntryFee int64
32 Status EntryProcessStatus
33 HeldBalance int64
34 RefundedTotal int64
35 FundCount uint64
36}
37
38type EntryFund struct {
39 ID uint64
40 ProcessID uint64
41 ParticipationKey string
42 EntryKey string
43 Owner address
44 Amount int64
45 Refunded bool
46}
47
48func CreateEntryProcess(cur realm, processKey string, gameWorldID uint64, entryFeeUgnot int64) uint64 {
49 accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
50 assertNoAttachedCoins()
51 assertKeyLength(processKey, "process key")
52 if entryProcessIDs.Has(processKey) {
53 panic("entry process key already exists")
54 }
55 if entryFeeUgnot <= 0 {
56 panic("entry fee must be positive")
57 }
58 assertGameWorldExists(gameWorldID)
59 if latestEntryProcessID == maxUint64 {
60 panic("entry process id exhausted")
61 }
62
63 latestEntryProcessID++
64 processID := latestEntryProcessID
65 treeSet(entryProcesses, processID, EntryProcess{
66 ID: processID,
67 ProcessKey: processKey,
68 GameWorldID: gameWorldID,
69 EntryFee: entryFeeUgnot,
70 Status: EntryProcessStatusOpen,
71 })
72 entryProcessIDs.Set(processKey, processID)
73 getOrCreateIDSet(gameWorldEntryProcessIDs, gameWorldID).Set(uint64Key(processID), true)
74 return processID
75}
76
77func CloseEntryProcess(cur realm, processID uint64) {
78 accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
79 assertNoAttachedCoins()
80 process := GetEntryProcess(processID)
81 if process.Status == EntryProcessStatusClosed {
82 return
83 }
84 if process.Status != EntryProcessStatusOpen {
85 panic("entry process cannot be closed")
86 }
87 process.Status = EntryProcessStatusClosed
88 treeSet(entryProcesses, processID, process)
89}
90
91func CancelEntryProcess(cur realm, processID uint64) {
92 accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
93 assertNoAttachedCoins()
94 process := GetEntryProcess(processID)
95 if process.Status == EntryProcessStatusCanceled {
96 return
97 }
98 if process.Status != EntryProcessStatusOpen && process.Status != EntryProcessStatusClosed {
99 panic("entry process cannot be canceled")
100 }
101 process.Status = EntryProcessStatusCanceled
102 treeSet(entryProcesses, processID, process)
103}
104
105func DepositEntry(cur realm, processID uint64, participationKey, entryKey string) uint64 {
106 owner := accesscontrol.MustGetUserCaller(0, cur)
107 assertKeyLength(participationKey, "participation key")
108 assertKeyLength(entryKey, "entry key")
109 process := GetEntryProcess(processID)
110 if process.Status != EntryProcessStatusOpen {
111 panic("entry process is not open")
112 }
113 entryIndexKey := keyedOwnerKey(processID, owner, entryKey)
114 if entryFundIDs.Has(entryIndexKey) {
115 panic("entry key already processed")
116 }
117 assertExactUgnotPayment(process.EntryFee)
118 if latestEntryFundID == maxUint64 || process.FundCount == maxUint64 {
119 panic("entry fund id exhausted")
120 }
121 if process.HeldBalance > maxInt64-process.EntryFee || accountedUgnotTotal > maxInt64-process.EntryFee {
122 panic("vault fund amount overflow")
123 }
124
125 latestEntryFundID++
126 fundID := latestEntryFundID
127 treeSet(entryFunds, fundID, EntryFund{
128 ID: fundID,
129 ProcessID: processID,
130 ParticipationKey: participationKey,
131 EntryKey: entryKey,
132 Owner: owner,
133 Amount: process.EntryFee,
134 })
135 entryFundIDs.Set(entryIndexKey, fundID)
136 addStringSetID(entryOwnerFundIDs, ownerKey(processID, owner), fundID)
137 addStringSetID(entryGroupFundIDs, keyedOwnerKey(processID, owner, participationKey), fundID)
138 process.HeldBalance += process.EntryFee
139 process.FundCount++
140 treeSet(entryProcesses, processID, process)
141 accountedUgnotTotal += process.EntryFee
142 return fundID
143}
144
145func RefundEntryFund(cur realm, fundID uint64, operationKey string) uint64 {
146 executor := accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
147 assertNoAttachedCoins()
148 assertNewOperationKey(operationKey)
149 fund := GetEntryFund(fundID)
150 if fund.Refunded {
151 panic("entry fund already refunded")
152 }
153 process := GetEntryProcess(fund.ProcessID)
154 if process.Status != EntryProcessStatusOpen && process.Status != EntryProcessStatusClosed && process.Status != EntryProcessStatusCanceled {
155 panic("entry fund cannot be refunded")
156 }
157 if process.HeldBalance < fund.Amount {
158 panic("insufficient entry fund balance")
159 }
160
161 process.HeldBalance -= fund.Amount
162 process.RefundedTotal += fund.Amount
163 treeSet(entryProcesses, process.ID, process)
164 fund.Refunded = true
165 treeSet(entryFunds, fund.ID, fund)
166 return recordAndSendRefund(cross(cur), 0, operationKey, fund.EntryKey, fund.Owner, fund.Amount, "entry", executor)
167}
168
169func GetEntryProcessID(processKey string) uint64 {
170 assertKeyLength(processKey, "process key")
171 value, found := stringGet(entryProcessIDs, processKey)
172 if !found {
173 return 0
174 }
175 return value.(uint64)
176}
177
178func GetEntryProcess(processID uint64) EntryProcess {
179 value, found := treeGet(entryProcesses, processID)
180 if !found {
181 panic("entry process not found: " + strconv.FormatUint(processID, 10))
182 }
183 return value.(EntryProcess)
184}
185
186func GetLatestEntryProcessID() uint64 { return latestEntryProcessID }
187
188func ListEntryRefundStates(processKeysCSV, ownersCSV, entryKeysCSV string) []map[string]string {
189 result := []map[string]string{}
190 if processKeysCSV == "" && ownersCSV == "" && entryKeysCSV == "" {
191 return result
192 }
193 processStart, ownerStart, entryStart := 0, 0, 0
194 for {
195 processKey, processNext, processDone := readQueryCSVEntry(processKeysCSV, processStart)
196 ownerValue, ownerNext, ownerDone := readQueryCSVEntry(ownersCSV, ownerStart)
197 entryKey, entryNext, entryDone := readQueryCSVEntry(entryKeysCSV, entryStart)
198 if processDone != ownerDone || ownerDone != entryDone {
199 panic("entry refund value count mismatch")
200 }
201 if len(result) == gameVaultList {
202 panic("count exceeds game vault list limit")
203 }
204 owner := address(ownerValue)
205 processID := GetEntryProcessID(processKey)
206 assertValidOwner(owner)
207 assertKeyLength(entryKey, "entry key")
208 state := map[string]string{
209 "requestedProcessKey": processKey,
210 "owner": owner.String(),
211 "entryKey": entryKey,
212 "processId": "0",
213 "processKey": "",
214 "entryFee": "0",
215 "processStatus": "0",
216 "fundId": "0",
217 "fundProcessId": "0",
218 "participationKey": "",
219 "fundEntryKey": "",
220 "fundOwner": "",
221 "fundAmount": "0",
222 "fundRefunded": "false",
223 }
224 if processID != 0 {
225 process := GetEntryProcess(processID)
226 state["processId"] = strconv.FormatUint(process.ID, 10)
227 state["processKey"] = process.ProcessKey
228 state["entryFee"] = strconv.FormatInt(process.EntryFee, 10)
229 state["processStatus"] = strconv.Itoa(int(process.Status))
230 fundID, found := stringGet(entryFundIDs, keyedOwnerKey(processID, owner, entryKey))
231 if found {
232 fund := GetEntryFund(fundID.(uint64))
233 state["fundId"] = strconv.FormatUint(fund.ID, 10)
234 state["fundProcessId"] = strconv.FormatUint(fund.ProcessID, 10)
235 state["participationKey"] = fund.ParticipationKey
236 state["fundEntryKey"] = fund.EntryKey
237 state["fundOwner"] = fund.Owner.String()
238 state["fundAmount"] = strconv.FormatInt(fund.Amount, 10)
239 state["fundRefunded"] = strconv.FormatBool(fund.Refunded)
240 }
241 }
242 result = append(result, state)
243 if processDone {
244 return result
245 }
246 processStart, ownerStart, entryStart = processNext, ownerNext, entryNext
247 }
248}
249
250func GetEntryFund(fundID uint64) EntryFund {
251 value, found := treeGet(entryFunds, fundID)
252 if !found {
253 panic("entry fund not found: " + strconv.FormatUint(fundID, 10))
254 }
255 return value.(EntryFund)
256}
257
258func GetLatestEntryFundID() uint64 { return latestEntryFundID }
259
260func GetEntryFundStatus(fundID uint64) EntryFundStatus {
261 if GetEntryFund(fundID).Refunded {
262 return EntryFundStatusRefunded
263 }
264 return EntryFundStatusHeld
265}
266
267func GetEntryFundID(processID uint64, owner address, entryKey string) uint64 {
268 GetEntryProcess(processID)
269 assertValidOwner(owner)
270 assertKeyLength(entryKey, "entry key")
271 value, found := stringGet(entryFundIDs, keyedOwnerKey(processID, owner, entryKey))
272 if !found {
273 return 0
274 }
275 return value.(uint64)
276}
277
278func GetEntryFundCount(processID uint64, owner address, participationKey string) int {
279 GetEntryProcess(processID)
280 assertValidOwner(owner)
281 assertKeyLength(participationKey, "participation key")
282 ids, found := getStringSet(entryGroupFundIDs, keyedOwnerKey(processID, owner, participationKey))
283 if !found {
284 return 0
285 }
286 return ids.Size()
287}
288
289func ListEntryFundIDs(processID uint64, owner address, participationKey string, page, count int) []uint64 {
290 GetEntryProcess(processID)
291 assertValidOwner(owner)
292 assertKeyLength(participationKey, "participation key")
293 ids, _ := getStringSet(entryGroupFundIDs, keyedOwnerKey(processID, owner, participationKey))
294 return listIDs(ids, page, count)
295}
296
297func GetEntryFundCountByOwner(processID uint64, owner address) int {
298 GetEntryProcess(processID)
299 assertValidOwner(owner)
300 ids, found := getStringSet(entryOwnerFundIDs, ownerKey(processID, owner))
301 if !found {
302 return 0
303 }
304 return ids.Size()
305}
306
307func ListEntryFundIDsByOwner(processID uint64, owner address, page, count int) []uint64 {
308 GetEntryProcess(processID)
309 assertValidOwner(owner)
310 ids, _ := getStringSet(entryOwnerFundIDs, ownerKey(processID, owner))
311 return listIDs(ids, page, count)
312}