PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/g17cjym5e9hhws46lt6329pv2gtx2ay0503hgems/gems/campaign

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
campaign
Namespace
g17cjym5e9hhws46lt6329pv2gtx2ay0503hgems / gems
Files
2 (gnomod.toml)
Exported functions
9
Module
gno.land/r/g17cjym5e9hhws46lt6329pv2gtx2ay0503hgems/gems/campaign
gno
0.9

Files (2)

  • gnomod.tomltoml
  • campaign.gnogno
campaign.gnogno
1// Package campaign is a near-verbatim copy of the real gems6/campaign2// realm, redeployed here under the test address so this whole3// reveal-delay + gemsartfab prototype is self-contained and testable4// without touching the live gems6 deployment or needing the vesting5// wallet's own key. Logic is unchanged from the original -- see that6// package's own doc comments for the full design rationale (why a7// dedicated prunable realm instead of a Merkle root, the stacking rule8// in grantOne, etc.).9package campaign1011// Storage (2026-09-26): every grant lives in ONE map, packed as a single12// int64 (remainingUses*packBase + bps), plus one slice of wallets for13// EntryAt's stable order. The first version kept an avl.Tree of *entry14// pointers: every wallet became its own tree node plus entry object, about15// 2.9 KB each on a local chain (0.29 GNOT per wallet, ~85 GNOT for the16// 284-wallet campaign). A map and a slice are stored as a few objects17// whose size grows by roughly the key and value per wallet.1819import (20	unsaferealm "chain/runtime/unsafe"21	"strings"22)2324const packBase = 10001 // bps is 0..100002526var (27	collectionOwner  address = "g17cjym5e9hhws46lt6329pv2gtx2ay0503hgems"28	approvedConsumer string29	grants           = map[string]int64{} // wallet -> remainingUses*packBase + bps30	order            []string             // wallets with a grant, for EntryAt31)3233func pack(bps, uses int64) int64     { return uses*packBase + bps }34func unpack(v int64) (bps, uses int64) { return v % packBase, v / packBase }3536func callerAddress() address {37	return unsaferealm.PreviousRealm().Address()38}3940func assertOwner() {41	if callerAddress() != collectionOwner {42		panic("unauthorized: caller is not the collection owner")43	}44}4546func SetApprovedConsumer(cur realm, pkgpath string) {47	assertOwner()48	approvedConsumer = pkgpath49}5051func validateBps(bps int64) {52	if bps < 0 || bps > 10000 {53		panic("bps must be between 0 and 10000")54	}55}5657func validateMaxUses(maxUses int64) {58	if maxUses <= 0 {59		panic("maxUses must be positive")60	}61}6263// grantOne adds uses to a wallet; a second grant stacks its uses and keeps64// the better (lower) bps.65func grantOne(wallet string, bps int64, maxUses int64) {66	if v, ok := grants[wallet]; ok {67		oldBps, uses := unpack(v)68		if oldBps < bps {69			bps = oldBps70		}71		grants[wallet] = pack(bps, uses+maxUses)72		return73	}74	grants[wallet] = pack(bps, maxUses)75	order = append(order, wallet)76}7778func removeOne(wallet string) {79	if _, ok := grants[wallet]; !ok {80		return81	}82	delete(grants, wallet)83	for i, w := range order {84		if w == wallet {85			order[i] = order[len(order)-1]86			order = order[:len(order)-1]87			break88		}89	}90}9192func AddWallet(cur realm, wallet address, bps int64, maxUses int64) {93	assertOwner()94	validateBps(bps)95	validateMaxUses(maxUses)96	grantOne(wallet.String(), bps, maxUses)97}9899func AddWalletsBatch(cur realm, walletsCSV string, bps int64, maxUses int64) {100	assertOwner()101	validateBps(bps)102	validateMaxUses(maxUses)103	for _, w := range strings.Split(walletsCSV, ",") {104		w = strings.TrimSpace(w)105		if w == "" {106			continue107		}108		grantOne(w, bps, maxUses)109	}110}111112func RemoveWallet(cur realm, wallet address) {113	assertOwner()114	removeOne(wallet.String())115}116117func RemoveWalletsBatch(cur realm, walletsCSV string) {118	assertOwner()119	for _, w := range strings.Split(walletsCSV, ",") {120		w = strings.TrimSpace(w)121		if w == "" {122			continue123		}124		removeOne(w)125	}126}127128func assertCallerIsApprovedConsumer(cur realm) {129	caller := cur.Previous().PkgPath()130	if approvedConsumer == "" || caller != approvedConsumer {131		panic("unauthorized: caller is not the approved consumer realm")132	}133}134135func Peek(wallet address) (bps int64, remainingUses int64, ok bool) {136	v, has := grants[wallet.String()]137	if !has {138		return 0, 0, false139	}140	bps, remainingUses = unpack(v)141	return bps, remainingUses, true142}143144func ConsumeDiscount(cur realm, wallet address) (bps int64, ok bool) {145	assertCallerIsApprovedConsumer(cur)146	w := wallet.String()147	v, has := grants[w]148	if !has {149		return 0, false150	}151	bps, uses := unpack(v)152	if uses <= 1 {153		removeOne(w)154	} else {155		grants[w] = pack(bps, uses-1)156	}157	return bps, true158}159160func Count() int64 { return int64(len(order)) }161162func EntryAt(index int) (wallet string, bps int64, remainingUses int64) {163	wallet = order[index]164	bps, remainingUses = unpack(grants[wallet])165	return wallet, bps, remainingUses166}167

Functions

  • AddWallet(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, wallet string, bps int64, maxUses int64)

  • AddWalletsBatch(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, walletsCSV string, bps int64, maxUses int64)

  • ConsumeDiscount(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, wallet string) (bps int64, ok bool)

  • Count() int64

  • EntryAt(index int) (wallet string, bps int64, remainingUses int64)

  • Peek(wallet string) (bps int64, remainingUses int64, ok bool)

  • RemoveWallet(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, wallet string)

  • RemoveWalletsBatch(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, walletsCSV string)

  • SetApprovedConsumer(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pkgpath string)

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗
This realm does not provide renderable output (vm/qrender → NoRenderDeclError). View on gnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.