1// Package erc1155 is an idiomatic gno.land port of the Solidity ERC-11552// multi-token standard. A single realm tracks many distinct token ids, each3// with its own fungible balances. Balances are keyed by (owner, id) in an4// avl.Tree so Render can iterate deterministically.5package erc115567import (8 "strconv"9 "strings"1011 "chain"12 "chain/runtime/unsafe"1314 "gno.land/p/nt/avl/v0"15)1617// balances maps "<owner>:<id>" -> uint64 amount.18var balances avl.Tree1920// supply maps "<id>" -> uint64 total minted for that id.21var supply avl.Tree2223func balKey(owner address, id int) string {24 return owner.String() + ":" + strconv.Itoa(id)25}2627func supKey(id int) string {28 return strconv.Itoa(id)29}3031func getBalance(owner address, id int) uint64 {32 k := balKey(owner, id)33 if !balances.Has(k) {34 return 035 }36 return balances.Get(k).(uint64)37}3839func setBalance(owner address, id int, amount uint64) {40 k := balKey(owner, id)41 if amount == 0 {42 balances.Remove(k)43 return44 }45 balances.Set(k, amount)46}4748func getSupply(id int) uint64 {49 k := supKey(id)50 if !supply.Has(k) {51 return 052 }53 return supply.Get(k).(uint64)54}5556// Mint creates `amount` units of token `id` and credits them to `to`.57func Mint(cur realm, to address, id int, amount uint64) {58 if !to.IsValid() {59 panic("erc1155: mint to invalid address")60 }61 if amount == 0 {62 panic("erc1155: mint amount must be > 0")63 }64 setBalance(to, id, getBalance(to, id)+amount)65 supply.Set(supKey(id), getSupply(id)+amount)6667 operator := unsafe.PreviousRealm().Address()68 chain.Emit("Mint",69 "operator", operator.String(),70 "to", to.String(),71 "id", strconv.Itoa(id),72 "amount", strconv.FormatUint(amount, 10),73 )74}7576// TransferSingle moves `amount` of token `id` from the caller to `to`.77func TransferSingle(cur realm, to address, id int, amount uint64) {78 if !to.IsValid() {79 panic("erc1155: transfer to invalid address")80 }81 if amount == 0 {82 panic("erc1155: transfer amount must be > 0")83 }84 from := unsafe.PreviousRealm().Address()85 fromBal := getBalance(from, id)86 if fromBal < amount {87 panic("erc1155: insufficient balance")88 }89 setBalance(from, id, fromBal-amount)90 setBalance(to, id, getBalance(to, id)+amount)9192 chain.Emit("TransferSingle",93 "from", from.String(),94 "to", to.String(),95 "id", strconv.Itoa(id),96 "amount", strconv.FormatUint(amount, 10),97 )98}99100// BalanceOf returns the amount of token `id` held by `owner`.101func BalanceOf(owner address, id int) uint64 {102 return getBalance(owner, id)103}104105// TotalSupply returns the total amount minted of token `id`.106func TotalSupply(id int) uint64 {107 return getSupply(id)108}109110// Render prints a balances table and a per-id supply table.111func Render(path string) string {112 var b strings.Builder113 b.WriteString("# ERC-1155 Multi-Token\n\n")114 b.WriteString("A single realm holding many fungible token ids. ")115 b.WriteString("Balances are keyed by `(owner, id)`.\n\n")116117 b.WriteString("## Balances\n\n")118 if balances.Size() == 0 {119 b.WriteString("_No balances yet. Call `Mint` to create tokens._\n\n")120 } else {121 b.WriteString("| Owner | ID | Amount |\n")122 b.WriteString("|---|---|---|\n")123 balances.Iterate("", "", func(key string, value interface{}) bool {124 owner, id := splitBalKey(key)125 b.WriteString("| `" + owner + "` | " + id + " | " +126 strconv.FormatUint(value.(uint64), 10) + " |\n")127 return false128 })129 b.WriteString("\n")130 }131132 b.WriteString("## Supply per ID\n\n")133 if supply.Size() == 0 {134 b.WriteString("_No tokens minted._\n")135 } else {136 b.WriteString("| ID | Total Supply |\n")137 b.WriteString("|---|---|\n")138 supply.Iterate("", "", func(key string, value interface{}) bool {139 b.WriteString("| " + key + " | " +140 strconv.FormatUint(value.(uint64), 10) + " |\n")141 return false142 })143 }144145 return b.String()146}147148// splitBalKey splits a "<owner>:<id>" balance key. The owner (a bech32149// address) contains no ':', so the id is the substring after the last ':'.150func splitBalKey(key string) (owner, id string) {151 i := strings.LastIndex(key, ":")152 if i < 0 {153 return key, ""154 }155 return key[:i], key[i+1:]156}157BalanceOf(owner string, id int) uint64
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, id int, amount uint64)
Render(path string) string
TotalSupply(id int) uint64
TransferSingle(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, id int, amount uint64)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
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.