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/g1n4pl5uc4yt5r96m9w6fmdznx3x0jyg8l6arhmt/bazaar/perk

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
perk
Namespace
g1n4pl5uc4yt5r96m9w6fmdznx3x0jyg8l6arhmt / bazaar
Files
2 (gnomod.toml)
Exported functions
7
Module
gno.land/r/g1n4pl5uc4yt5r96m9w6fmdznx3x0jyg8l6arhmt/bazaar/perk
gno
0.9

Files (2)

  • gnomod.tomltoml
  • perk.gnogno
perk.gnogno
1package perk23import (4	"chain"5	"chain/banker"6	"chain/runtime/unsafe"7	"strconv"8	"strings"910	"gno.land/p/nt/avl/v0"11	col "gno.land/r/g1n4pl5uc4yt5r96m9w6fmdznx3x0jyg8l6arhmt/bazaar/c/bazaargens"12	factory "gno.land/r/g1n4pl5uc4yt5r96m9w6fmdznx3x0jyg8l6arhmt/bazaar/bazaarv5"13)1415// Perk counts revealed, unlisted Bazaar Gens held in a wallet.16// Fee discount is the highest tier. Share weight is the sum.17// Mainnet staging retargets colPkg to c/bazaargens. Admin then SetGenesis18// on bazaarv5 so Buy sends the 11% protocol share here and NoteHolderDiscount19// accepts this realm. Sync must be called after mint, transfer, list, or reveal.20// Rarity stays unread until the collection reveals it.2122const (23	pkgPath   = "gno.land/r/g1n4pl5uc4yt5r96m9w6fmdznx3x0jyg8l6arhmt/bazaar/perk"24	colPkg    = "gno.land/r/g1n4pl5uc4yt5r96m9w6fmdznx3x0jyg8l6arhmt/bazaar/c/bazaargens"25	native    = "ugnot"26	scale     = int64(1_000_000)27	maxSpan   = 2028	maxDelta  = int64(9_000_000_000_000) // delta * scale stays inside int6429)3031type wallet struct {32	n25     int33	n50     int34	n75     int35	n100    int36	n125    int37	n150    int38	debt    int6439	accrued int6440}4142var (43	wallets     avl.Tree44	tokenWho    avl.Tree45	tokenBps    avl.Tree46	totalWeight int6447	acc         int6448	accounted   int6449	self        address50)5152func Sync(cur realm, id int) {53	requireUser(cur)54	if id < 1 {55		panic("perk: id")56	}57	syncID(cur, id)58}5960func SyncSpan(cur realm, start, end int) {61	requireUser(cur)62	if start < 1 || end < start || end-start >= maxSpan {63		panic("perk: span")64	}65	for id := start; id <= end; id++ {66		syncID(cur, id)67	}68}6970func Claim(cur realm) {71	caller := requireUser(cur)72	syncPot(cur)73	w := mustWallet(caller)74	settle(w)75	amt := w.accrued76	if amt <= 0 {77		panic("perk: nothing")78	}79	if amt > accounted {80		panic("perk: accounted")81	}82	bk := banker.NewBanker(banker.BankerTypeRealmSend, cur)83	if bk.GetCoins(self).AmountOf(native) < amt {84		panic("perk: funds")85	}86	w.accrued = 087	accounted -= amt88	wallets.Set(caller.String(), w)89	bk.SendCoins(self, caller, chain.Coins{{Denom: native, Amount: amt}})90	chain.Emit("Claim", "owner", caller.String(), "amount", strconv.FormatInt(amt, 10))91}9293func ShareWeight(owner string) int64 {94	w := load(owner)95	if w == nil {96		return 097	}98	return shareOf(w)99}100101func FeeDiscount(owner string) int64 {102	w := load(owner)103	if w == nil {104		return 0105	}106	return bestOf(w)107}108109func TotalWeight() int64 {110	return totalWeight111}112113func Render(_ string) string {114	return "# Bazaar perk\n\n- total weight: " + strconv.FormatInt(totalWeight, 10) + "\n- accounted: " + strconv.FormatInt(accounted, 10) + " ugnot\n"115}116117func syncID(cur realm, id int) {118	who, bps := live(id)119	key := strconv.Itoa(id)120	oldWho := address("")121	oldBps := int64(0)122	if v := tokenWho.Get(key); v != nil {123		oldWho = v.(address)124	}125	if v := tokenBps.Get(key); v != nil {126		oldBps = v.(int64)127	}128	if oldWho == who && oldBps == bps {129		return130	}131	if oldBps > 0 && oldWho.IsValid() {132		addTier(cur, oldWho, oldBps, -1)133	}134	if bps > 0 && who.IsValid() {135		addTier(cur, who, bps, 1)136	}137	if bps == 0 || !who.IsValid() {138		tokenWho.Remove(key)139		tokenBps.Remove(key)140		chain.Emit("Sync", "id", key, "bps", "0")141		return142	}143	tokenWho.Set(key, who)144	tokenBps.Set(key, bps)145	chain.Emit("Sync", "id", key, "owner", who.String(), "bps", strconv.FormatInt(bps, 10))146}147148func live(id int) (address, int64) {149	owner, err := col.OwnerOf(strconv.Itoa(id))150	if err != nil || !owner.IsValid() {151		panic("perk: unknown")152	}153	if owner == chain.PackageAddress(colPkg) {154		return address(""), 0155	}156	return owner, bpsOf(col.RarityOf(id))157}158159func bpsOf(rarity string) int64 {160	switch strings.ToLower(strings.TrimSpace(rarity)) {161	case "mythic":162		return 150163	case "legendary":164		return 125165	case "epic":166		return 100167	case "rare":168		return 75169	case "uncommon":170		return 50171	case "common":172		return 25173	default:174		return 0175	}176}177178func addTier(cur realm, who address, bps int64, dir int) {179	if dir != 1 && dir != -1 {180		panic("perk: dir")181	}182	syncPot(cur)183	w := mustWallet(who)184	settle(w)185	switch bps {186	case 25:187		w.n25 += dir188	case 50:189		w.n50 += dir190	case 75:191		w.n75 += dir192	case 100:193		w.n100 += dir194	case 125:195		w.n125 += dir196	case 150:197		w.n150 += dir198	default:199		panic("perk: tier")200	}201	if w.n25 < 0 || w.n50 < 0 || w.n75 < 0 || w.n100 < 0 || w.n125 < 0 || w.n150 < 0 {202		panic("perk: count")203	}204	totalWeight += bps * int64(dir)205	if totalWeight < 0 {206		panic("perk: weight")207	}208	w.debt = shareOf(w) * acc / scale209	wallets.Set(who.String(), w)210	factory.NoteHolderDiscount(cross(cur), who.String(), bestOf(w))211}212213func settle(w *wallet) {214	sw := shareOf(w)215	got := sw * acc / scale216	if got < w.debt {217		panic("perk: debt")218	}219	w.accrued += got - w.debt220	w.debt = got221}222223func syncPot(cur realm) {224	if !self.IsValid() {225		self = cur.Address()226	}227	bk := banker.NewBanker(banker.BankerTypeRealmSend, cur)228	bal := bk.GetCoins(self).AmountOf(native)229	if bal < accounted {230		panic("perk: balance")231	}232	delta := bal - accounted233	if delta == 0 || totalWeight <= 0 {234		return235	}236	if delta > maxDelta {237		panic("perk: amount")238	}239	bump := delta * scale / totalWeight240	if bump <= 0 {241		return242	}243	allocated := bump * totalWeight / scale244	if allocated <= 0 {245		return246	}247	if acc > maxDelta*scale-bump {248		panic("perk: acc")249	}250	acc += bump251	accounted += allocated252}253254func shareOf(w *wallet) int64 {255	return int64(w.n25)*25 + int64(w.n50)*50 + int64(w.n75)*75 + int64(w.n100)*100 + int64(w.n125)*125 + int64(w.n150)*150256}257258func bestOf(w *wallet) int64 {259	if w.n150 > 0 {260		return 150261	}262	if w.n125 > 0 {263		return 125264	}265	if w.n100 > 0 {266		return 100267	}268	if w.n75 > 0 {269		return 75270	}271	if w.n50 > 0 {272		return 50273	}274	if w.n25 > 0 {275		return 25276	}277	return 0278}279280func load(owner string) *wallet {281	v := wallets.Get(strings.ToLower(strings.TrimSpace(owner)))282	if v == nil {283		return nil284	}285	return v.(*wallet)286}287288func mustWallet(who address) *wallet {289	w := load(who.String())290	if w == nil {291		w = &wallet{}292		wallets.Set(who.String(), w)293	}294	return w295}296297func requireUser(cur realm) address {298	if !cur.IsCurrent() {299		panic("perk: spoofed realm")300	}301	prev := cur.Previous()302	if !prev.IsUserCall() {303		panic("perk: EOA only")304	}305	if len(unsafe.OriginSend()) != 0 {306		panic("perk: extra denoms")307	}308	return prev.Address()309}310

Functions

  • Claim(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})

  • FeeDiscount(owner string) int64

  • Render(string) string

  • ShareWeight(owner string) int64

  • Sync(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}, id int)

  • SyncSpan(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}, start int, end int)

  • TotalWeight() int64

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

Rendered

RenderedRawgnoweb ↗

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.