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.

campaign.gno

2.89 Kb · 136 lines
  1package campaign
  2
  3import (
  4	unsaferealm "chain/runtime/unsafe"
  5	"strings"
  6
  7	"gno.land/p/g1wx60nkcp5lfsxmedeg7sfs47tzxkath05u63t4/avl"
  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}