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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

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}