Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}