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.

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}