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

campaign.gno

2.85 Kb · 136 lines
  1package campaign
  2
  3import (
  4	unsaferealm "chain/runtime/unsafe"
  5	"strings"
  6
  7	"gno.land/p/nt/avl/v0"
  8)
  9
 10var (
 11	collectionOwner  address = "g1wx60nkcp5lfsxmedeg7sfs47tzxkath05u63t4"
 12	approvedConsumer string
 13	entries          avl.Tree // wallet.String() -> *entry
 14)
 15
 16type entry struct {
 17	Bps           int64
 18	RemainingUses int64
 19}
 20
 21func callerAddress() address {
 22	return unsaferealm.PreviousRealm().Address()
 23}
 24
 25func assertOwner() {
 26	if callerAddress() != collectionOwner {
 27		panic("unauthorized: caller is not the collection owner")
 28	}
 29}
 30
 31func SetApprovedConsumer(cur realm, pkgpath string) {
 32	assertOwner()
 33	approvedConsumer = pkgpath
 34}
 35
 36func validateBps(bps int64) {
 37	if bps < 0 || bps > 10000 {
 38		panic("bps must be between 0 and 10000")
 39	}
 40}
 41
 42func validateMaxUses(maxUses int64) {
 43	if maxUses <= 0 {
 44		panic("maxUses must be positive")
 45	}
 46}
 47
 48func grantOne(wallet string, bps int64, maxUses int64) {
 49	if raw := entries.Get(wallet); raw != nil {
 50		if e, ok := raw.(*entry); ok {
 51			e.RemainingUses += maxUses
 52			if bps < e.Bps {
 53				e.Bps = bps
 54			}
 55			entries.Set(wallet, e)
 56			return
 57		}
 58	}
 59	entries.Set(wallet, &entry{Bps: bps, RemainingUses: maxUses})
 60}
 61
 62func AddWallet(cur realm, wallet address, bps int64, maxUses int64) {
 63	assertOwner()
 64	validateBps(bps)
 65	validateMaxUses(maxUses)
 66	grantOne(wallet.String(), bps, maxUses)
 67}
 68
 69func AddWalletsBatch(cur realm, walletsCSV string, bps int64, maxUses int64) {
 70	assertOwner()
 71	validateBps(bps)
 72	validateMaxUses(maxUses)
 73	for _, w := range strings.Split(walletsCSV, ",") {
 74		w = strings.TrimSpace(w)
 75		if w == "" {
 76			continue
 77		}
 78		grantOne(w, bps, maxUses)
 79	}
 80}
 81
 82func RemoveWallet(cur realm, wallet address) {
 83	assertOwner()
 84	entries.Remove(wallet.String())
 85}
 86
 87func RemoveWalletsBatch(cur realm, walletsCSV string) {
 88	assertOwner()
 89	for _, w := range strings.Split(walletsCSV, ",") {
 90		w = strings.TrimSpace(w)
 91		if w == "" {
 92			continue
 93		}
 94		entries.Remove(w)
 95	}
 96}
 97
 98func assertCallerIsApprovedConsumer(cur realm) {
 99	caller := cur.Previous().PkgPath()
100	if approvedConsumer == "" || caller != approvedConsumer {
101		panic("unauthorized: caller is not the approved consumer realm")
102	}
103}
104
105func Peek(wallet address) (bps int64, remainingUses int64, ok bool) {
106	raw := entries.Get(wallet.String())
107	e, isEntry := raw.(*entry)
108	if !isEntry {
109		return 0, 0, false
110	}
111	return e.Bps, e.RemainingUses, true
112}
113
114func ConsumeDiscount(cur realm, wallet address) (bps int64, ok bool) {
115	assertCallerIsApprovedConsumer(cur)
116	raw := entries.Get(wallet.String())
117	e, isEntry := raw.(*entry)
118	if !isEntry {
119		return 0, false
120	}
121	e.RemainingUses--
122	if e.RemainingUses <= 0 {
123		entries.Remove(wallet.String())
124	} else {
125		entries.Set(wallet.String(), e)
126	}
127	return e.Bps, true
128}
129
130func Count() int64 { return int64(entries.Size()) }
131
132func EntryAt(index int) (wallet string, bps int64, remainingUses int64) {
133	w, v := entries.GetByIndex(index)
134	e := v.(*entry)
135	return w, e.Bps, e.RemainingUses
136}