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/p/nt/grc721/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
nt / grc721
Files
8 (gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/nt/grc721/v0
gno
0.9

Files (8)

  • gnomod.tomltoml
  • tellers.gnogno
  • token.gnogno
  • types.gnogno
  • newtoken_event_filetest.gnogno
  • tellers_test.gnogno
  • token_test.gnogno
  • veto_no_event_filetest.gnogno
  • tellers.gnogno
    1package grc72123import (4	"chain"5)67// CallerTeller resolves the acting account at each write as rlm.Previous() —8

    Functions

    not supported for pure packages by the node (vm/qfuncs)

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

    // the realm that crossed into the realm holding the teller.
    9//
    10// SECURITY: this accessor hangs off *PrivateLedger, not *Token, and that is
    11// load-bearing. A frame-relative teller acts as whoever crossed into its
    12// holder, so it is only meaningful inside the token's own realm, where the
    13// wrappers act for a caller who knowingly invoked the collection. Anywhere
    14// else it is a confused deputy: a realm a user merely calls could move that
    15// user's tokens. The *Token pointer is published — exported vars, the
    16// collection facade, grc721reg — while the ledger is not, since NewToken hands
    17// it to the creating realm and nowhere else. So a foreign realm cannot mint
    18// one.
    19//
    20// Construction privacy alone is not enough: a realm may legally build a teller
    21// and then export the VALUE. The write methods therefore also verify that the
    22// invoking realm is the token's own (see guardHome), which leaves a leaked
    23// teller inert everywhere but home.
    24func (led *PrivateLedger) CallerTeller() Teller {
    25 if led == nil {
    26 panic("Ledger cannot be nil")
    27 }
    28
    29 return &fnTeller{
    30 accountFn: func(_ int, rlm realm) address {
    31 return rlm.Previous().Address()
    32 },
    33 homeGuard: true,
    34 Token: led.token,
    35 }
    36}
    37
    38// Write methods return ErrReadonly.
    39func (tok *Token) ReadonlyTeller() Teller {
    40 if tok == nil {
    41 panic("Token cannot be nil")
    42 }
    43
    44 return &fnTeller{
    45 accountFn: nil,
    46 Token: tok,
    47 }
    48}
    49
    50// Permanently acts as the calling realm (verified via IsCurrent).
    51func (tok *Token) RealmTeller(_ int, rlm realm) Teller {
    52 if tok == nil {
    53 panic("Token cannot be nil")
    54 }
    55
    56 if !rlm.IsCurrent() {
    57 panic(ErrSpoofedRealm)
    58 }
    59
    60 caller := rlm.Address()
    61
    62 return &fnTeller{
    63 accountFn: func(_ int, _ realm) address {
    64 return caller
    65 },
    66 Token: tok,
    67 }
    68}
    69
    70// Like RealmTeller but acts as a sub-account derived from slug.
    71func (tok *Token) RealmSubTeller(_ int, rlm realm, slug string) Teller {
    72 if tok == nil {
    73 panic("Token cannot be nil")
    74 }
    75
    76 if !rlm.IsCurrent() {
    77 panic(ErrSpoofedRealm)
    78 }
    79
    80 account := accountSlugAddr(rlm.Address(), slug)
    81
    82 return &fnTeller{
    83 accountFn: func(_ int, _ realm) address {
    84 return account
    85 },
    86 Token: tok,
    87 }
    88}
    89
    90// Admin-grade: issuer-only (holds the PrivateLedger). Panics on invalid addr to close the empty-sentinel hole.
    91func (led *PrivateLedger) ImpersonateTeller(addr address) Teller {
    92 if led == nil {
    93 panic("Ledger cannot be nil")
    94 }
    95
    96 if !addr.IsValid() {
    97 panic(ErrInvalidAddress)
    98 }
    99
    100 return &fnTeller{
    101 accountFn: func(_ int, _ realm) address {
    102 return addr
    103 },
    104 Token: led.token,
    105 }
    106}
    107
    108// guardHome confines a frame-relative teller to the token's own realm.
    109// Construction privacy stops a foreign realm from minting one; this stops a
    110// minted one from travelling, which is what happens when a realm legally builds
    111// a teller and then exports the value.
    112//
    113// The check is on the invoking realm's path alone — deliberately NOT on whether
    114// the resolved actor is an end user. Keying on the actor only blocks the case
    115// where the debited party is the signing user, and leaves two doors open: a
    116// realm can be charged by a realm it calls, and TransferFrom resolves the
    117// *spender* from the frame, so a realm reached from an honest hub spends that
    118// hub's approvals against any owner who granted one. Both are the same defect
    119// as the original one level up — frame-relative resolution means whoever you
    120// call can act as you — and neither is reachable once the teller only works at
    121// home.
    122//
    123// The host is compared after stripping any ":subpath" synthesized by realm.Sub,
    124// so the token's own sub-realms are not falsely rejected.
    125//
    126// A foreign realm that needs to move a user's tokens uses the ordinary route:
    127// the owner Approves it, and it spends as itself through RealmTeller, which is
    128// eagerly bound to its own address and approval-gated.
    129//
    130// The leading int keeps this a plain method.
    131func (ft *fnTeller) guardHome(_ int, rlm realm) error {
    132 if !ft.homeGuard {
    133 return nil
    134 }
    135
    136 host, _, _ := chain.SplitPkgSubPath(rlm.PkgPath())
    137 if host != ft.Token.origRealm {
    138 return ErrForeignCallerTeller
    139 }
    140
    141 return nil
    142}
    143
    144func (ft *fnTeller) Approve(_ int, rlm realm, to address, tid TokenID) error {
    145 if ft.accountFn == nil {
    146 return ErrReadonly
    147 }
    148
    149 if !rlm.IsCurrent() {
    150 return ErrSpoofedRealm
    151 }
    152
    153 if err := ft.guardHome(0, rlm); err != nil {
    154 return err
    155 }
    156
    157 caller := ft.accountFn(0, rlm)
    158
    159 return ft.Token.ledger.Approve(caller, to, tid)
    160}
    161
    162func (ft *fnTeller) SetApprovalForAll(_ int, rlm realm, operator address, approved bool) error {
    163 if ft.accountFn == nil {
    164 return ErrReadonly
    165 }
    166
    167 if !rlm.IsCurrent() {
    168 return ErrSpoofedRealm
    169 }
    170
    171 if err := ft.guardHome(0, rlm); err != nil {
    172 return err
    173 }
    174
    175 caller := ft.accountFn(0, rlm)
    176
    177 return ft.Token.ledger.SetApprovalForAll(caller, operator, approved)
    178}
    179
    180func (ft *fnTeller) TransferFrom(_ int, rlm realm, from, to address, tid TokenID) error {
    181 if ft.accountFn == nil {
    182 return ErrReadonly
    183 }
    184
    185 if !rlm.IsCurrent() {
    186 return ErrSpoofedRealm
    187 }
    188
    189 if err := ft.guardHome(0, rlm); err != nil {
    190 return err
    191 }
    192
    193 spender := ft.accountFn(0, rlm)
    194
    195 return ft.Token.ledger.TransferFrom(spender, from, to, tid)
    196}
    197
    198func accountSlugAddr(addr address, slug string) address {
    199 if slug == "" {
    200 return addr
    201 }
    202
    203 key := addr.String() + "/" + slug
    204
    205 return chain.PackageAddress(key)
    206}
    207