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/g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr/wbubble

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
wbubble
Namespace
g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr
Files
2 (gnomod.toml)
Exported functions
11
Module
gno.land/r/g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr/wbubble
gno
0.9
This realm implements a recognized token.BUBBLE →

Files (2)

  • gnomod.tomltoml
  • wbubble.gnogno
wbubble.gnogno
1// Package wbubble is wrapped BUBBLE: the Bubble Rumble token as a registered GRC20, backed one to one by BUBBLE2// held in this realm. It exists for gnoswap, which pools only tokens registered in gno.land/r/nt/grc20reg/v0 —3// and the registry takes only a *grc20.Token made by grc20.NewToken inside the registering realm. BUBBLE4// (gno.land/r/g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr/bubble) keeps its ledger in kourt's grc20votes, not a5// grc20.Token, and a realm cannot be redeployed; so this realm holds BUBBLE and issues a registered token for6// it, the way gno.land/r/gnoland/wugnot wraps ugnot (ref/ holds the mainnet sources this mirrors).7//8// Wrap pulls BUBBLE from the caller — an allowance the caller granted THIS realm on the bubble realm, spent by9// this realm as itself — and mints the same amount of wrapped BUBBLE to the caller. Unwrap burns the caller's10// wrapped BUBBLE and sends the same amount of BUBBLE back. Nothing else mints or burns, and nothing here is a11// setting: no admin, no pause, no minter. The reserve (this realm's BUBBLE balance) covers the wrapped supply12// after every call, and a call that would leave it short aborts.13//14// Votes. BUBBLE carries a vote in its own realm; wrapped BUBBLE carries none. The BUBBLE held here is15// self-delegated, inside the bubble ledger, to this realm's own address — the ledger's default for every holder —16// and this realm never delegates it or votes with it, so that weight is never cast. Unwrap to vote.17package wbubble1819import (20	"chain"21	"strconv"22	"strings"2324	"gno.land/p/nt/grc20/v0"25	"gno.land/r/g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr/bubble"26	"gno.land/r/nt/grc20reg/v0"27)2829// Token is the registered token, exported as wugnot exports its own: a *grc20.Token carries no spend30// authority (its tellers act only for the realm that builds them, and only with an allowance), and the registry31// hands the same pointer to anyone. ledger is the mint and burn, and it never leaves this package.32var (33	Token  *grc20.Token34	ledger *grc20.PrivateLedger35)3637const (38	tokenName     = "Bubble Rumble BUBBLE (wrapped)"39	tokenSymbol   = "BUBBLE"40	tokenDecimals = 641	pkgPath       = "gno.land/r/g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr/wbubble" // must match gnomod.toml42	// RegistryKey is what gno.land/r/nt/grc20reg/v0 knows this token as: the realm path and the symbol.43	RegistryKey = pkgPath + "." + tokenSymbol4445	one = int64(1_000_000) // one BUBBLE in base units46)4748func init(cur realm) {49	// wbubble only ever creates this one token, so id 0 can't collide.50	Token, ledger = grc20.NewToken(tokenName, tokenSymbol, tokenDecimals, 0, cur)51	if key := grc20reg.Register(cross(cur), Token, ""); key != RegistryKey {52		panic("wbubble: registered as " + key + ", not " + RegistryKey + ": the package path is not the one in the source")53	}54}5556// Address is this realm's own address: the spender to approve on the bubble realm before Wrap, and the holder of57// the reserve.58func Address() address { return chain.PackageAddress(pkgPath) }5960// Reserve is the BUBBLE this realm holds. It covers TotalSupply after every call (checkReserve).61func Reserve() int64 { return bubble.BalanceOf(Address()) }6263// Wrap takes amount BUBBLE from the caller and mints as much wrapped BUBBLE to them. First, on the bubble realm,64// the caller approves THIS realm for the amount (bubble.Approve with spender Address()): bubble reads its own65// caller as the spender, and its caller here is this realm, not the user. A failure inside bubble panics across66// the realm boundary and aborts the whole transaction, so nothing is minted for BUBBLE that did not arrive.67func Wrap(cur realm, amount int64) {68	require(amount > 0, "wbubble: the amount must be positive")69	// The security guide's rule (gno-security-guide.md §5.6, §8): read the caller from cur only after IsCurrent.70	// Under interrealm v2 (gno-interrealm-v2.md §5.2) a crossing function's own cur is always current, so this71	// refuses nobody; it is kept so the realm meets both documents.72	if !cur.IsCurrent() {73		panic("wbubble: spoofed realm")74	}75	caller := cur.Previous().Address()76	self := cur.Address()77	before := bubble.BalanceOf(self)78	bubble.TransferFrom(cross(cur), caller, self, amount)79	checkErr(ledger.Mint(caller, amount))80	checkReserve(self, before+amount)81}8283// Unwrap burns amount of the caller's wrapped BUBBLE and sends them as much BUBBLE. The burn goes first: a caller84// without the wrapped tokens is refused before anything moves.85func Unwrap(cur realm, amount int64) {86	require(amount > 0, "wbubble: the amount must be positive")87	if !cur.IsCurrent() { // see Wrap88		panic("wbubble: spoofed realm")89	}90	caller := cur.Previous().Address()91	self := cur.Address()92	before := bubble.BalanceOf(self)93	checkErr(ledger.Burn(caller, amount))94	bubble.Transfer(cross(cur), caller, amount)95	checkReserve(self, before-amount)96}9798// checkReserve is the invariant after every move: the reserve moved by exactly the amount, and it covers the99// supply. Not `reserve == supply`: anyone can send BUBBLE straight to this realm's address, and a wrapper that100// demanded equality would then refuse every Wrap and Unwrap for good. Such a gift only puts the reserve over the101// supply; it belongs to nobody and stays.102func checkReserve(self address, want int64) {103	have := bubble.BalanceOf(self)104	if have != want {105		panic("wbubble: the reserve moved by the wrong amount")106	}107	if have < Token.TotalSupply() {108		panic("wbubble: the reserve is short of the wrapped supply")109	}110}111112// ------------------------------------------------------------ the GRC20 --113//114// wugnot's surface, line for line: the reads on the Token, the writes through the ledger's caller teller, which115// acts for whoever crossed into this realm and works nowhere but here.116117func TotalSupply() int64 {118	return Token.TotalSupply()119}120121func BalanceOf(owner address) int64 {122	return Token.BalanceOf(owner)123}124125func Allowance(owner, spender address) int64 {126	return Token.Allowance(owner, spender)127}128129func Transfer(cur realm, to address, amount int64) {130	userTeller := ledger.CallerTeller()131	checkErr(userTeller.Transfer(0, cur, to, amount))132}133134func Approve(cur realm, spender address, amount int64) {135	userTeller := ledger.CallerTeller()136	checkErr(userTeller.Approve(0, cur, spender, amount))137}138139func TransferFrom(cur realm, from, to address, amount int64) {140	userTeller := ledger.CallerTeller()141	checkErr(userTeller.TransferFrom(0, cur, from, to, amount))142}143144// ----------------------------------------------------------------- pages --145146// Render: "" the token's page; "balance/<addr>" one wrapped balance as a number (wugnot's path); "json" the147// figures for the box.148func Render(path string) string {149	parts := strings.Split(path, "/")150	switch {151	case path == "":152		return home()153	case path == "json":154		return json()155	case len(parts) == 2 && parts[0] == "balance":156		return strconv.FormatInt(Token.BalanceOf(address(parts[1])), 10)157	default:158		return "404"159	}160}161162func home() string {163	self := Address()164	supply, reserve := Token.TotalSupply(), bubble.BalanceOf(self)165	var b strings.Builder166	b.WriteString("Wrapped BUBBLE, symbol " + tokenSymbol + ", " + strconv.Itoa(tokenDecimals) + " decimals: the Bubble Rumble token as a registered GRC20, for gnoswap and every realm that reads the token registry.\n\n")167	b.WriteString("Wrapped in circulation: " + amount(supply) + " BUBBLE. Reserve held by this realm at " + self.String() + ": " + amount(reserve) + " BUBBLE")168	switch {169	case reserve == supply:170		b.WriteString(", exactly the supply.\n\n")171	case reserve > supply:172		b.WriteString(", " + amount(reserve-supply) + " over the supply (BUBBLE sent here directly; it belongs to nobody).\n\n")173	default:174		b.WriteString(" — SHORT of the supply by " + amount(supply-reserve) + "; this must never print.\n\n")175	}176	b.WriteString("Registry key: " + RegistryKey + " (gno.land/r/nt/grc20reg/v0).\n\n")177	b.WriteString("To wrap: on the bubble realm call Approve with spender " + self.String() + " and the amount in base units, then call Wrap here with the same amount.\n")178	b.WriteString("To unwrap: call Unwrap here with the amount; the BUBBLE comes back to your address.\n\n")179	b.WriteString("Votes: BUBBLE carries a vote in its own realm and wrapped BUBBLE carries none. What this realm holds is self-delegated to the realm's own address inside the bubble ledger and is never cast. Unwrap to vote.\n")180	return b.String()181}182183func json() string {184	return `{"name":"` + tokenName + `","symbol":"` + tokenSymbol + `","decimals":` + strconv.Itoa(tokenDecimals) +185		`,"supply":` + strconv.FormatInt(Token.TotalSupply(), 10) + `,"reserve":` + strconv.FormatInt(Reserve(), 10) +186		`,"address":"` + Address().String() + `","key":"` + RegistryKey + `"}`187}188189// amount prints base units as BUBBLE with up to six decimals, trailing zeros dropped.190func amount(n int64) string {191	whole, frac := n/one, n%one192	if frac == 0 {193		return strconv.FormatInt(whole, 10)194	}195	f := strconv.FormatInt(frac, 10)196	for len(f) < tokenDecimals {197		f = "0" + f198	}199	return strconv.FormatInt(whole, 10) + "." + strings.TrimRight(f, "0")200}201202func require(condition bool, msg string) {203	if !condition {204		panic(msg)205	}206}207208func checkErr(err error) {209	if err != nil {210		panic("wbubble: " + err.Error())211	}212}213

Functions

  • Address() string

  • Allowance(owner string, spender string) int64

  • Approve(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}, spender string, amount int64)

  • BalanceOf(owner string) int64

  • Render(path string) string

  • Reserve() int64

  • TotalSupply() int64

  • Transfer(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}, to string, amount int64)

  • TransferFrom(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}, from string, to string, amount int64)

  • Unwrap(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}, amount int64)

  • Wrap(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}, amount 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.