Gno.land
| 1 | package lotto |
| 2 | |
| 3 | import ( |
| 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 | |
| 12 | const AddNumberEvent = "AddNumber" |
| 13 | |
| 14 | var 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. |
| 19 | func 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 | |
| 40 | func 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. |
| 46 | func 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. |
| 59 | func 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 | } |
| Function | Parameters |
|---|---|
| AddNumber | (owner string, number uint64) |
| DeleteAll | () |
| GetNumberCount | (number uint64, owner string) |
| ListOwnersByNumber | (number uint64, afterOwner string, limit int) |
| Render | (path string) |
AKKADIA Lotto
Look up owners and their quantities for a number.
<gno-form path="number"> <gno-input name="number" placeholder="Enter a number" /> </gno-form>
| Function | Caller | Age |
|---|---|---|
| AddNumber | g1vzacmg…8sjcz7 | 1h ago |
| AddNumber | g1qqa6p4…zu6m0v | 1h ago |
| AddNumber | g1d8yap8…6pfzau | 1h ago |
| AddNumber | g1vzacmg…8sjcz7 | 1h ago |
| AddNumber | g1qqa6p4…zu6m0v | 1h ago |
| AddNumber | g1vzacmg…8sjcz7 | 3h ago |
| AddNumber | g1qqa6p4…zu6m0v | 3h ago |
| AddNumber | g1d8yap8…6pfzau | 3h ago |
| AddNumber | g1vzacmg…8sjcz7 | 3h ago |
| AddNumber | g1d8yap8…6pfzau | 6h ago |
| AddNumber | g1vzacmg…8sjcz7 | 6h ago |
| AddNumber | g1qqa6p4…zu6m0v | 6h ago |