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/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/nfts/skins

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
skins
Namespace
g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd / gnofly / nfts
Files
10 (gnomod.toml)
Exported functions
12
Module
gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/nfts/skins
gno
0.9

Files (10)

  • gnomod.tomltoml
  • buy.gnogno
  • catalog.gnogno
  • doc.gnogno
  • errors.gnogno
  • json.gnogno
  • render.gnogno
  • roles.gnogno
  • skins.gnogno
  • validate.gnogno
  • json.gnogno
    1package skins23import (4	"errors"5	"strings"67	"gno.land/p/nt/grc721/v0"8

    Functions

    • BalanceOf(addr string) (int64, interface {Error func() string})

    • 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}, id int64)

    • Buy(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}, skinID string) int64

    • CatalogJSON() string

    • OwnerOf(tid string) (string, interface {Error func() string})

    • Render(path string) string

    • SetSkin(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 string, name string, model string, pilot string, body string, wing string, accent string, price int64, maxSupply int64)

    • SetSkinListed(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 string, listed bool)

    • SkinOf(id int64) string

    • SkinsOf(addr string) string

    • TokenMetadata(tid string) (string, interface {Error func() string})

    • TokenURI(tid string) (string, interface {Error func() string})

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

    Rendered

    RenderedRawgnoweb ↗
    "gno.land/p/onbloc/json/v0"
    9)
    10
    11// CatalogJSON returns every design, sorted by id, as a JSON array:
    12//
    13// [ { "id": "baron", "name": "Red Baron", "model": "biplane", "pilot": "none",
    14// "body": "#c1121f", "wing": "#780000", "accent": "#fdf0d5",
    15// "price": 1000000, "listed": true, "minted": 3, "maxSupply": 0 } ]
    16//
    17// The output has no whitespace. maxSupply 0 is unlimited. Classic, the free
    18// look, is not in it: the client draws it without a token.
    19func CatalogJSON() string {
    20 items := []*json.Node{}
    21 designs.Iterate("", "", func(_ string, v any) bool {
    22 d := v.(*design)
    23 b := json.Builder().
    24 WriteString("id", d.id).
    25 WriteString("name", d.name).
    26 WriteString("model", d.model).
    27 WriteString("pilot", d.pilot).
    28 WriteString("body", d.body).
    29 WriteString("wing", d.wing).
    30 WriteString("accent", d.accent).
    31 WriteNumber("price", float64(d.price)).
    32 WriteBool("listed", d.listed).
    33 WriteNumber("minted", float64(d.minted)).
    34 WriteNumber("maxSupply", float64(d.maxSupply))
    35 items = append(items, b.Node())
    36 return false
    37 })
    38 return encode(json.ArrayNode("", items))
    39}
    40
    41// SkinsOf returns the designs addr owns a token of, sorted by id, as a JSON
    42// array: ["baron","goldie"]. It is [] for an address without skins.
    43func SkinsOf(addr address) string {
    44 ids := []*json.Node{}
    45 prefix := addr.String() + "/"
    46 if validAddress(addr) {
    47 // Keys sort as "<addr>/<design>": the designs of addr are one range,
    48 // "/" + 1 is "0".
    49 owned.Iterate(prefix, addr.String()+"0", func(key string, _ any) bool {
    50 ids = append(ids, json.StringNode("", strings.TrimPrefix(key, prefix)))
    51 return false
    52 })
    53 }
    54 return encode(json.ArrayNode("", ids))
    55}
    56
    57// The read functions a wallet calls take a grc721.TokenID and return an
    58// error rather than panic, the way Adena calls them: OwnerOf("1") into two
    59// values, TokenURI("1") as the image it shows, TokenMetadata("1") as JSON
    60// for the traits. The errors are made on the call, not stored (errors.gno).
    61
    62// OwnerOf returns who owns skin token tid, or an error when there is none.
    63func OwnerOf(tid grc721.TokenID) (address, error) {
    64 id, err := mintedID(tid)
    65 if err != nil {
    66 return "", err
    67 }
    68 return ownerOf(id), nil
    69}
    70
    71// BalanceOf returns how many skin tokens addr owns, one per design at most.
    72func BalanceOf(addr address) (int64, error) {
    73 return token.BalanceOf(addr)
    74}
    75
    76// TokenMetadata returns the metadata of skin token tid as JSON, the same for
    77// every token of a design, with the keys Adena reads:
    78//
    79// {"name":"Red Baron","description":"A gnofly skin, a biplane. ...",
    80// "image":"https://gnofly.xyz/nft/skins/baron.png",
    81// "attributes":[{"traitType":"model","value":"biplane"}, ...]}
    82func TokenMetadata(tid grc721.TokenID) (string, error) {
    83 id, err := mintedID(tid)
    84 if err != nil {
    85 return "", err
    86 }
    87 d := getDesign(skinOf(id))
    88 if d == nil {
    89 return "", errors.New(errNotMinted)
    90 }
    91 pilot := ""
    92 if d.pilot == "gnome" {
    93 pilot = " flown by a gnome"
    94 }
    95 b := json.Builder().
    96 WriteString("name", d.name).
    97 WriteString("description", "A gnofly skin, a "+d.model+pilot+". Bound to its buyer: it cannot be transferred.").
    98 WriteString("image", uriBase+d.id+".png").
    99 WriteArray("attributes", func(ab *json.ArrayBuilder) {
    100 for _, t := range [][2]string{
    101 {"model", d.model}, {"pilot", d.pilot}, {"body", d.body}, {"wing", d.wing},
    102 {"accent", d.accent}, {"soulbound", "yes"},
    103 } {
    104 ab.WriteObject(func(o *json.NodeBuilder) {
    105 o.WriteString("traitType", t[0]).WriteString("value", t[1])
    106 })
    107 }
    108 })
    109 return encode(b.Node()), nil
    110}
    111
    112// mintedID reads a token id, "1" and up in decimal, and checks it exists.
    113func mintedID(tid grc721.TokenID) (int64, error) {
    114 s := string(tid)
    115 n := int64(0)
    116 for i := 0; i < len(s); i++ {
    117 if s[i] < '0' || s[i] > '9' || i > 15 || (i == 0 && s[i] == '0') {
    118 return 0, errors.New(errNotMinted)
    119 }
    120 n = n*10 + int64(s[i]-'0')
    121 }
    122 if n == 0 || ownerOf(n) == "" {
    123 return 0, errors.New(errNotMinted)
    124 }
    125 return n, nil
    126}
    127
    128// SkinOf returns the design of skin token id, "" when there is no such token.
    129func SkinOf(id int64) string {
    130 return skinOf(id)
    131}
    132
    133// TokenURI returns the image of skin token tid,
    134// "https://gnofly.xyz/nft/skins/<design>.png": what a wallet shows (Adena
    135// puts it in an <img>). The metadata is TokenMetadata, or
    136// "https://gnofly.xyz/nft/skins/<design>.json" on the website. It is
    137// computed, not stored: a token costs no URI in deposit.
    138func TokenURI(tid grc721.TokenID) (string, error) {
    139 id, err := mintedID(tid)
    140 if err != nil {
    141 return "", err
    142 }
    143 return uriBase + skinOf(id) + ".png", nil
    144}
    145
    146// encode marshals a document built above; it cannot fail on one.
    147func encode(n *json.Node) string {
    148 out, err := json.Marshal(n)
    149 if err != nil {
    150 panic(err)
    151 }
    152 return string(out)
    153}
    154

    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.