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_test.gnogno
    1package grc72123import (4	"testing"56	"gno.land/p/nt/uassert/v0"7	"gno.land/p/nt/urequire/v0"8

    Functions

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

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

    )
    9
    10type evilTeller struct{ Teller }
    11
    12func TestIsCanonicalTeller(cur realm, t *testing.T) {
    13 tok, led := newTestToken("Foo", "FOO", 0, cur)
    14
    15 var realmTeller Teller
    16 func(cur realm) {
    17 realmTeller = tok.RealmTeller(0, cur)
    18 }(cross(cur))
    19
    20 tests := []struct {
    21 name string
    22 te Teller
    23 want bool
    24 }{
    25 {"CallerTeller is canonical", led.CallerTeller(), true},
    26 {"ReadonlyTeller is canonical", tok.ReadonlyTeller(), true},
    27 {"RealmTeller is canonical", realmTeller, true},
    28 {"ImpersonateTeller is canonical", led.ImpersonateTeller(alice), true},
    29 {"embedding wrapper is rejected", &evilTeller{led.CallerTeller()}, false},
    30 }
    31
    32 for _, tc := range tests {
    33 tc := tc
    34 t.Run(tc.name, func(t *testing.T) {
    35 uassert.Equal(t, tc.want, IsCanonicalTeller(tc.te))
    36 })
    37 }
    38}
    39
    40func TestTellerNilGuards(cur realm, t *testing.T) {
    41 var nilTok *Token
    42 var nilLed *PrivateLedger
    43
    44 tests := []struct {
    45 name string
    46 msg string
    47 fn func()
    48 }{
    49 {"CallerTeller on nil ledger panics", "Ledger cannot be nil", func() {
    50 nilLed.CallerTeller()
    51 }},
    52 {"ReadonlyTeller on nil token panics", "Token cannot be nil", func() {
    53 nilTok.ReadonlyTeller()
    54 }},
    55 {"RealmTeller on nil token panics", "Token cannot be nil", func() {
    56 nilTok.RealmTeller(0, cur)
    57 }},
    58 {"RealmSubTeller on nil token panics", "Token cannot be nil", func() {
    59 nilTok.RealmSubTeller(0, cur, "slug")
    60 }},
    61 {"ImpersonateTeller on nil ledger panics", "Ledger cannot be nil", func() {
    62 nilLed.ImpersonateTeller(alice)
    63 }},
    64 }
    65
    66 for _, tc := range tests {
    67 tc := tc
    68 t.Run(tc.name, func(t *testing.T) {
    69 uassert.PanicsWithMessage(t, cur, tc.msg, tc.fn)
    70 })
    71 }
    72}
    73
    74func TestReadonlyTeller(cur realm, t *testing.T) {
    75 tok, led := newTestToken("Foo", "FOO", 0, cur)
    76 urequire.NoError(t, led.Mint(alice, "1"))
    77 ro := tok.ReadonlyTeller()
    78
    79 tests := []struct {
    80 name string
    81 op string
    82 }{
    83 {"Approve rejected with ErrReadonly", "approve"},
    84 {"TransferFrom rejected with ErrReadonly", "transfer"},
    85 {"SetApprovalForAll rejected with ErrReadonly", "setall"},
    86 }
    87
    88 for _, tc := range tests {
    89 tc := tc
    90 t.Run(tc.name, func(t *testing.T) {
    91 var err error
    92 testing.SetRealm(testing.NewUserRealm(alice))
    93 func(cur realm) {
    94 switch tc.op {
    95 case "approve":
    96 err = ro.Approve(0, cur, bob, "1")
    97 case "transfer":
    98 err = ro.TransferFrom(0, cur, alice, bob, "1")
    99 case "setall":
    100 err = ro.SetApprovalForAll(0, cur, bob, true)
    101 }
    102 }(cross(cur))
    103 uassert.ErrorIs(t, err, ErrReadonly)
    104 })
    105 }
    106}
    107
    108func TestCallerTellerFlow(cur realm, t *testing.T) {
    109 tok, led := newTestToken("Foo", "FOO", 0, cur)
    110 urequire.NoError(t, led.Mint(alice, "1"))
    111 urequire.NoError(t, led.Mint(alice, "2"))
    112
    113 teller := led.CallerTeller()
    114
    115 testing.SetRealm(testing.NewUserRealm(alice))
    116 func(cur realm) {
    117 urequire.NoError(t, teller.Approve(0, cur, bob, "1"))
    118 }(cross(cur))
    119
    120 testing.SetRealm(testing.NewUserRealm(alice))
    121 func(cur realm) {
    122 urequire.NoError(t, teller.SetApprovalForAll(0, cur, bob, true))
    123 }(cross(cur))
    124 uassert.True(t, tok.IsApprovedForAll(alice, bob))
    125
    126 testing.SetRealm(testing.NewUserRealm(bob))
    127 func(cur realm) {
    128 urequire.NoError(t, teller.TransferFrom(0, cur, alice, carl, "1"))
    129 }(cross(cur))
    130
    131 owner, err := tok.OwnerOf("1")
    132 urequire.NoError(t, err)
    133 uassert.Equal(t, carl, owner)
    134
    135 testing.SetRealm(testing.NewUserRealm(bob))
    136 func(cur realm) {
    137 uassert.ErrorIs(t, teller.TransferFrom(0, cur, carl, bob, "1"), ErrCallerIsNotOwnerOrApproved)
    138 }(cross(cur))
    139}
    140
    141func TestCallerTellerSpoofedRealm(cur realm, t *testing.T) {
    142 _, led := newTestToken("Foo", "FOO", 0, cur)
    143 urequire.NoError(t, led.Mint(alice, "1"))
    144 teller := led.CallerTeller()
    145
    146 // Stale outer cur while a fresh frame is current → ErrSpoofedRealm.
    147 tests := []struct {
    148 name string
    149 op string
    150 }{
    151 {"Approve rejects spoofed realm", "approve"},
    152 {"TransferFrom rejects spoofed realm", "transfer"},
    153 {"SetApprovalForAll rejects spoofed realm", "setall"},
    154 }
    155
    156 for _, tc := range tests {
    157 tc := tc
    158 t.Run(tc.name, func(t *testing.T) {
    159 var err error
    160 stale := cur
    161 func(cur realm) {
    162 switch tc.op {
    163 case "approve":
    164 err = teller.Approve(0, stale, bob, "1")
    165 case "transfer":
    166 err = teller.TransferFrom(0, stale, alice, bob, "1")
    167 case "setall":
    168 err = teller.SetApprovalForAll(0, stale, bob, true)
    169 }
    170 }(cross(cur))
    171 uassert.ErrorIs(t, err, ErrSpoofedRealm)
    172 })
    173 }
    174}
    175
    176func TestRealmTellerFlow(cur realm, t *testing.T) {
    177 tok, led := newTestToken("Foo", "FOO", 0, cur)
    178
    179 var teller Teller
    180 var realmAddr address
    181 func(cur realm) {
    182 teller = tok.RealmTeller(0, cur)
    183 realmAddr = cur.Address()
    184 }(cross(cur))
    185
    186 urequire.NoError(t, led.Mint(realmAddr, "1"))
    187
    188 testing.SetRealm(testing.NewUserRealm(alice))
    189 func(cur realm) {
    190 urequire.NoError(t, teller.TransferFrom(0, cur, realmAddr, bob, "1"))
    191 }(cross(cur))
    192
    193 owner, err := tok.OwnerOf("1")
    194 urequire.NoError(t, err)
    195 uassert.Equal(t, bob, owner)
    196}
    197
    198func TestRealmSubTellerFlow(cur realm, t *testing.T) {
    199 tok, led := newTestToken("Foo", "FOO", 0, cur)
    200
    201 tests := []struct {
    202 name string
    203 slug string
    204 tid TokenID
    205 wantsRealmAddr bool
    206 }{
    207 {"empty slug derives the realm address itself", "", "10", true},
    208 {"non-empty slug derives a sub-account", "vault", "11", false},
    209 }
    210
    211 for _, tc := range tests {
    212 tc := tc
    213 t.Run(tc.name, func(t *testing.T) {
    214 var teller Teller
    215 var realmAddr, account address
    216 func(cur realm) {
    217 teller = tok.RealmSubTeller(0, cur, tc.slug)
    218 realmAddr = cur.Address()
    219 account = accountSlugAddr(cur.Address(), tc.slug)
    220 }(cross(cur))
    221
    222 if tc.wantsRealmAddr {
    223 uassert.Equal(t, realmAddr, account)
    224 } else {
    225 uassert.True(t, realmAddr != account, "sub-account must differ from realm address")
    226 }
    227
    228 urequire.NoError(t, led.Mint(account, tc.tid))
    229 testing.SetRealm(testing.NewUserRealm(alice))
    230 func(cur realm) {
    231 urequire.NoError(t, teller.TransferFrom(0, cur, account, bob, tc.tid))
    232 }(cross(cur))
    233
    234 owner, err := tok.OwnerOf(tc.tid)
    235 urequire.NoError(t, err)
    236 uassert.Equal(t, bob, owner)
    237 })
    238 }
    239}
    240
    241func TestRealmTellerSpoofedRealm(cur realm, t *testing.T) {
    242 tok, _ := newTestToken("Foo", "FOO", 0, cur)
    243
    244 tests := []struct {
    245 name string
    246 fn func()
    247 }{
    248 {"RealmTeller rejects spoofed realm", func() {
    249 stale := cur
    250 func(cur realm) {
    251 tok.RealmTeller(0, stale)
    252 }(cross(cur))
    253 }},
    254 {"RealmSubTeller rejects spoofed realm", func() {
    255 stale := cur
    256 func(cur realm) {
    257 tok.RealmSubTeller(0, stale, "vault")
    258 }(cross(cur))
    259 }},
    260 }
    261
    262 for _, tc := range tests {
    263 tc := tc
    264 t.Run(tc.name, func(t *testing.T) {
    265 urequire.AbortsContains(t, cur, "rlm does not match the current crossing frame", tc.fn)
    266 })
    267 }
    268}
    269
    270func TestImpersonateTeller(cur realm, t *testing.T) {
    271 tok, led := newTestToken("Foo", "FOO", 0, cur)
    272 urequire.NoError(t, led.Mint(alice, "1"))
    273
    274 teller := led.ImpersonateTeller(alice)
    275 testing.SetRealm(testing.NewUserRealm(bob))
    276 func(cur realm) {
    277 urequire.NoError(t, teller.TransferFrom(0, cur, alice, bob, "1"))
    278 }(cross(cur))
    279
    280 owner, err := tok.OwnerOf("1")
    281 urequire.NoError(t, err)
    282 uassert.Equal(t, bob, owner)
    283}
    284
    285func TestImpersonateTellerRejectsInvalidAddress(cur realm, t *testing.T) {
    286 _, led := newTestToken("Foo", "FOO", 0, cur)
    287 uassert.PanicsWithMessage(t, cur, "invalid address", func() {
    288 led.ImpersonateTeller(zeroAddress)
    289 })
    290}
    291