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/nym-thegnomic001/gnomic

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
gnomic
Namespace
nym-thegnomic001
Files
3 (gnomod.toml)
Exported functions
21
Module
gno.land/r/nym-thegnomic001/gnomic
gno
0.9
This realm implements a recognized token.GNOMIC →

Files (3)

  • gnomod.tomltoml
  • config.gnogno
  • token.gnogno
token.gnogno
1// Parametric GRC20 realm for gno.land.2//3// All configuration (name, symbol, decimals, supply, metadata) lives in4// config.gno. This file holds only the logic, which is not meant to be edited.5//6// The realm:7//   - creates a GRC20 token through gno.land/p/nt/grc20/v08//   - registers it with gno.land/r/nt/grc20reg/v0 (required to be discoverable9//     by GnoSwap, wallets and explorers)10//   - mints the initial supply to the deploying address11//   - exposes the GRC20 methods as top-level functions callable via MsgCall12//   - enforces a hard ceiling (maxSupply) on minting13//   - lets the owner give up minting forever (DropOwnership)14package gnomic1516import (17	"chain/runtime"18	"chain/runtime/unsafe"19	"math"20	"strconv"21	"strings"2223	"gno.land/p/nt/grc20/v0"24	"gno.land/p/nt/ownable/v0"25	"gno.land/p/nt/ufmt/v0"26	"gno.land/r/nt/grc20reg/v0"27)2829var (30	// Token is the public handle on the token: other realms can read it, but31	// cannot mutate balances (the PrivateLedger stays private).32	Token *grc20.Token3334	// Ownable holds the administrative authority (mint / administrative burn).35	Ownable *ownable.Ownable3637	privateLedger *grc20.PrivateLedger38	userTeller    grc20.Teller3940	// unit = 10^tokenDecimals, the conversion factor between whole units and41	// base units.42	unit int644344	// hardCap = maxSupply * unit, expressed in base units.45	hardCap int644647	// totalMinted is the CUMULATIVE amount ever minted, and never goes down.48	//49	// The ceiling is checked against this figure rather than against circulating50	// supply, because Burn lowers supply: checking that, burning would reopen51	// minting headroom and "21 million" would become an instantaneous limit52	// instead of a final one. With the cumulative counter burned tokens are gone53	// for good, which is what a fixed supply is supposed to mean.54	totalMinted int645556	// tokenKey is the canonical key in the GRC20 registry: "<pkgpath>.<SYMBOL>".57	// It is the identifier used by GnoSwap and friends.58	tokenKey string5960	deployHeight int6461	realmAddr    address62)6364func init(cur realm) {65	unit = pow10(tokenDecimals)66	hardCap = mulOrPanic(maxSupply, unit)67	initial := mulOrPanic(initialSupply, unit)68	if initial > hardCap {69		panic("token: initialSupply exceeds maxSupply")70	}7172	// Who administers the token:73	//  1. ownerAddress from config.gno, when set (e.g. a multisig or a DAO);74	//  2. otherwise the realm/user that ran the addpkg;75	//  3. otherwise the EOA that signed the deploy transaction.76	owner := address(ownerAddress)77	if !owner.IsValid() {78		owner = cur.Previous().Address()79	}80	if !owner.IsValid() {81		owner = unsafe.OriginCaller()82	}83	if !owner.IsValid() {84		panic("token: cannot determine the owner address")85	}8687	Token, privateLedger = grc20.NewToken(tokenName, tokenSymbol, tokenDecimals, 0, cur)88	userTeller = privateLedger.CallerTeller()89	Ownable = ownable.NewWithAddress(owner)9091	if initial > 0 {92		if err := privateLedger.Mint(owner, initial); err != nil {93			panic(err)94		}95		totalMinted = initial96	}9798	// Registration in the system GRC20 registry. Without this step the token99	// exists but is invisible to GnoSwap, wallets and explorers.100	tokenKey = grc20reg.Register(cross(cur), Token, "")101102	realmAddr = cur.Address()103	deployHeight = runtime.ChainHeight()104}105106// ---------------------------------------------------------------------------107// Reads (no state cost, queryable with `gnokey query vm/qeval`)108// ---------------------------------------------------------------------------109110// Name returns the token name.111func Name() string { return Token.GetName() }112113// Symbol returns the ticker.114func Symbol() string { return Token.GetSymbol() }115116// Decimals returns the precision.117func Decimals() int { return Token.GetDecimals() }118119// TotalSupply returns the circulating supply in base units.120func TotalSupply() int64 { return Token.TotalSupply() }121122// MaxSupply returns the hard ceiling in base units: it caps the cumulative123// amount ever minted, not the circulating supply.124func MaxSupply() int64 { return hardCap }125126// TotalMinted returns the cumulative amount ever minted. It never goes down,127// not even after a Burn: hardCap - TotalMinted() is the remaining headroom.128func TotalMinted() int64 { return totalMinted }129130// Burned returns the total destroyed: cumulative minted minus circulating.131func Burned() int64 { return totalMinted - Token.TotalSupply() }132133// Holders returns the number of addresses with a non-zero balance.134func Holders() int { return Token.KnownAccounts() }135136// BalanceOf returns the balance of owner in base units.137func BalanceOf(owner address) int64 { return Token.BalanceOf(owner) }138139// Allowance returns how much spender may draw from owner.140func Allowance(owner, spender address) int64 { return Token.Allowance(owner, spender) }141142// TokenKey returns the token's key in the GRC20 registry ("<pkgpath>.<SYMBOL>"),143// to be used with r/nt/grc20reg and with GnoSwap.144func TokenKey() string { return tokenKey }145146// RealmAddress returns the address of the realm itself: the address to send147// funds meant for the contract (an airdrop budget, for instance).148func RealmAddress() address { return realmAddr }149150// Owner returns the current administrator ("" once ownership has been dropped).151func Owner() address { return Ownable.Owner() }152153// ---------------------------------------------------------------------------154// Standard GRC20 writes155// ---------------------------------------------------------------------------156157// Transfer sends amount (base units) from the caller to to.158func Transfer(cur realm, to address, amount int64) {159	checkErr(userTeller.Transfer(0, cur, to, amount))160}161162// Approve authorises spender to draw up to amount from the caller.163func Approve(cur realm, spender address, amount int64) {164	checkErr(userTeller.Approve(0, cur, spender, amount))165}166167// TransferFrom moves amount from from to to, consuming the caller's allowance.168func TransferFrom(cur realm, from, to address, amount int64) {169	checkErr(userTeller.TransferFrom(0, cur, from, to, amount))170}171172// Burn destroys amount of the caller's tokens, reducing the supply.173func Burn(cur realm, amount int64) {174	checkErr(privateLedger.Burn(cur.Previous().Address(), amount))175}176177// ---------------------------------------------------------------------------178// Administration179// ---------------------------------------------------------------------------180181// Mint creates amount (base units) in favour of to. Owner only, and never182// beyond maxSupply. After DropOwnership this function is unusable forever: the183// supply becomes immutable upwards.184func Mint(cur realm, to address, amount int64) {185	Ownable.AssertOwnedBy(cur.Previous().Address())186	if amount <= 0 {187		panic("token: amount must be positive")188	}189	if totalMinted > hardCap-amount {190		panic("token: mint would exceed maxSupply")191	}192	totalMinted += amount193	checkErr(privateLedger.Mint(to, amount))194}195196// TransferOwnership hands administration over to newOwner.197func TransferOwnership(cur realm, newOwner address) {198	checkErr(Ownable.TransferOwnership(0, cur, newOwner))199}200201// DropOwnership gives up administration for good: no future mint will ever be202// possible. The operation cannot be undone.203func DropOwnership(cur realm) {204	checkErr(Ownable.DropOwnership(0, cur))205}206207// ---------------------------------------------------------------------------208// Render209// ---------------------------------------------------------------------------210211func Render(path string) string {212	parts := strings.Split(path, "/")213214	switch {215	case path == "":216		return renderHome()217	case len(parts) == 2 && parts[0] == "balance":218		addr := address(parts[1])219		if !addr.IsValid() {220			return "invalid address\n"221		}222		return ufmt.Sprintf("%s %s\n", format(Token.BalanceOf(addr)), tokenSymbol)223	default:224		return "404\n"225	}226}227228func renderHome() string {229	s := ""230	if tokenLogoURI != "" {231		s += ufmt.Sprintf("![%s](%s)\n\n", tokenSymbol, tokenLogoURI)232	}233	s += ufmt.Sprintf("# %s ($%s)\n\n", tokenName, tokenSymbol)234	if tokenDescription != "" {235		s += tokenDescription + "\n\n"236	}237	s += "| | |\n|---|---|\n"238	s += ufmt.Sprintf("| Symbol | %s |\n", tokenSymbol)239	s += ufmt.Sprintf("| Decimals | %d |\n", tokenDecimals)240	s += ufmt.Sprintf("| Circulating supply | %s |\n", format(Token.TotalSupply()))241	s += ufmt.Sprintf("| Max supply | %s |\n", format(hardCap))242	s += ufmt.Sprintf("| Minted in total | %s |\n", format(totalMinted))243	s += ufmt.Sprintf("| Burned | %s |\n", format(Burned()))244	s += ufmt.Sprintf("| Holders | %d |\n", Token.KnownAccounts())245	s += ufmt.Sprintf("| Registry key | `%s` |\n", tokenKey)246	s += ufmt.Sprintf("| Mint | %s |\n", mintStatus())247	s += ufmt.Sprintf("| Deployed at block | %d |\n", deployHeight)248	s += "\n"249	if tokenWebsite != "" {250		s += ufmt.Sprintf("- Website: %s\n", tokenWebsite)251	}252	if tokenTwitter != "" {253		s += ufmt.Sprintf("- X: %s\n", tokenTwitter)254	}255	s += "\nLook up a balance: `:balance/<address>`\n"256	return s257}258259func mintStatus() string {260	if !Ownable.Owner().IsValid() {261		return "**closed for good** (ownership dropped)"262	}263	if totalMinted >= hardCap {264		return "**exhausted**: the mint ceiling is reached, no further token can be created"265	}266	return ufmt.Sprintf("%s left, controlled by %s",267		format(hardCap-totalMinted), Ownable.Owner().String())268}269270// ---------------------------------------------------------------------------271// Helpers272// ---------------------------------------------------------------------------273274// format turns base units into a readable decimal string.275//276// The sign is applied at the end rather than by negating v: for |v| < unit the277// whole part is 0, so the minus would be lost (format(-500000) gave "0.5").278// Negating v directly is no good either, because -math.MinInt64 overflows;279// instead the whole part and the remainder are negated, both safe in magnitude.280func format(v int64) string {281	if unit == 1 {282		return strconv.FormatInt(v, 10)283	}284	neg := v < 0285	whole := v / unit286	frac := v % unit287	if whole < 0 {288		whole = -whole289	}290	if frac < 0 {291		frac = -frac292	}293294	fs := strconv.FormatInt(frac, 10)295	for len(fs) < tokenDecimals {296		fs = "0" + fs297	}298	fs = strings.TrimRight(fs, "0")299300	out := strconv.FormatInt(whole, 10)301	if fs != "" {302		out += "." + fs303	}304	if neg {305		out = "-" + out306	}307	return out308}309310func pow10(n int) int64 {311	r := int64(1)312	for i := 0; i < n; i++ {313		r *= 10314	}315	return r316}317318func mulOrPanic(a, b int64) int64 {319	if a < 0 || b <= 0 {320		panic("token: invalid supply parameters")321	}322	if a > math.MaxInt64/b {323		panic("token: supply * 10^decimals exceeds int64")324	}325	return a * b326}327328func checkErr(err error) {329	if err != nil {330		panic(err.Error())331	}332}333

Functions

  • 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

  • Burn(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)

  • Burned() int64

  • Decimals() int

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

  • Holders() int

  • MaxSupply() int64

  • Mint(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)

  • Name() string

  • Owner() string

  • RealmAddress() string

  • Render(path string) string

  • Symbol() string

  • TokenKey() string

  • TotalMinted() 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)

  • TransferOwnership(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}, newOwner string)

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.