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

lotto.gno

2.66 Kb · 90 lines
 1package lotto
 2
 3import (
 4	"chain"
 5	"strconv"
 6
 7	"gno.land/p/akkadia/beta/accesscontrol"
 8	"gno.land/p/nt/bptree/v0"
 9	"gno.land/r/akkadia/beta/admin"
10)
11
12const AddNumberEvent = "AddNumber"
13
14var holdings = bptree.NewBPTree32()
15
16// AddNumber increments the holding once per successful call, including retries.
17// Only the direct admin or operator caller may register a number. Individual
18// ticket identities, issuance times and past round balances are not retained.
19func AddNumber(cur realm, owner address, number uint64) {
20	accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
21	assertValidAddress(owner)
22	key := strconv.FormatUint(number, 10) + ":" + owner.String()
23	count := uint64(0)
24	if current := holdings.Get(key); current != nil {
25		count = current.(uint64)
26	}
27	if count == ^uint64(0) {
28		panic("number count overflow")
29	}
30	count++
31	holdings.Set(key, count)
32	chain.Emit(
33		AddNumberEvent,
34		"owner", owner.String(),
35		"number", strconv.FormatUint(number, 10),
36		"count", strconv.FormatUint(count, 10),
37	)
38}
39
40func DeleteAll(cur realm) {
41	accesscontrol.AssertIsAdmin(0, cur, admin.IsAdmin)
42	holdings = bptree.NewBPTree32()
43}
44
45// GetNumberCount returns zero when the valid owner has no holding for number.
46func GetNumberCount(number uint64, owner address) uint64 {
47	assertValidAddress(owner)
48	current := holdings.Get(strconv.FormatUint(number, 10) + ":" + owner.String())
49	if current == nil {
50		return 0
51	}
52	return current.(uint64)
53}
54
55// ListOwnersByNumber returns fresh values in ascending address order. A cursor
56// need not be stored. Each row carries the page cursor; an empty cursor or empty
57// list ends pagination. Counts are decimal strings to preserve uint64 precision.
58// Pages reflect current state, not a historical snapshot.
59func ListOwnersByNumber(number uint64, afterOwner string, limit int) []map[string]string {
60	if afterOwner != "" {
61		assertValidAddress(address(afterOwner))
62	}
63	assertListLimit(limit)
64	numberStr := strconv.FormatUint(number, 10)
65	prefix := numberStr + ":"
66	start := prefix
67	if afterOwner != "" {
68		// Valid address strings cannot contain NUL, so this excludes the cursor
69		// without visiting it or scanning preceding owners.
70		start += afterOwner + "\x00"
71	}
72	result := make([]map[string]string, 0, limit)
73	nextOwner := ""
74	holdings.Iterate(start, numberStr+";", func(key string, count any) bool {
75		if len(result) == limit {
76			nextOwner = result[len(result)-1]["owner"]
77			return true
78		}
79		result = append(result, map[string]string{
80			"owner":     key[len(prefix):],
81			"count":     strconv.FormatUint(count.(uint64), 10),
82			"nextOwner": "",
83		})
84		return false
85	})
86	for _, item := range result {
87		item["nextOwner"] = nextOwner
88	}
89	return result
90}