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/grc20/v0

Package
Open in gnoweb ↗

Overview

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

Files (12)

  • gnomod.tomltoml
  • mock.gnogno
  • tellers.gnogno
  • token.gnogno
  • types.gnogno
  • caller_teller_sub_realm_filetest.gnogno
  • event_provenance_filetest.gno
gno
  • examples_test.gnogno
  • newtoken_event_filetest.gnogno
  • tellers_test.gnogno
  • token_identity_filetest.gnogno
  • token_test.gnogno
  • event_provenance_filetest.gnogno
    1// PKGPATH: gno.land/r/demo/grc20provenance23// This filetest is the reference for how an indexer attributes a grc20 event to4// the realm that issued the token. It is the cross-realm counterpart to5// newtoken_event_filetest.gno, which covers the within-realm duplicate signal.6//7// Two fields matter, and neither is sufficient alone:

    Functions

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

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

    8
    //
    9// - pkg_path is stamped by the VM from the package whose code calls
    10// chain.Emit. Every genuine grc20 event therefore carries
    11// gno.land/p/nt/grc20/v0 — a constant, so it identifies the library
    12// but never the token.
    13// - the "token" attribute carries Token.ID(), whose leading component is
    14// rlm.PkgPath() captured under IsCurrent() in NewToken. A realm cannot
    15// produce a Token whose id claims a different realm.
    16//
    17// Chained, they are sufficient: pkg_path proves the event came from grc20's
    18// code, and grc20's code only ever writes an IsCurrent-verified realm prefix
    19// into "token". So for any event bearing grc20's pkg_path, the realm prefix in
    20// "token" is unforgeable.
    21//
    22// The realm below is an impostor trying to pass its own transfers off as
    23// another realm's token, by both routes available to it, and failing at both.
    24package grc20provenance
    25
    26import (
    27 "chain"
    28
    29 "gno.land/p/nt/grc20/v0"
    30)
    31
    32// Stand-in for a token issued and registered by some other realm. Written as a
    33// literal rather than imported: a filetest under a /p/ package that imports an
    34// /r/ realm which itself imports that /p/ package forms a genesis dependency
    35// cycle (grc20 -> realm -> grc20), which breaks package loading chain-wide.
    36const canonical = "gno.land/r/demo/canonicaltoken.FOO.0000000"
    37
    38func main(cur realm) {
    39 println("canonical id:", canonical)
    40
    41 // Route 1: ask grc20 for a token using the canonical token's own
    42 // name/symbol/decimals/id. NewToken derives the id prefix from the live
    43 // crossing frame, so the id names *this* realm. No argument changes that.
    44 impostor, impostorLedger := grc20.NewToken("Foo", "FOO", 4, 0, cur)
    45 println("impostor id: ", impostor.ID())
    46 println("impostor claims canonical id:", impostor.ID() == canonical)
    47
    48 // A genuine grc20 event from the impostor. It carries grc20's pkg_path —
    49 // identical to the canonical token's events — but the "token" prefix is
    50 // this realm, so an indexer attributes it here.
    51 impostorLedger.Mint(cur.Address(), 999_999)
    52
    53 // Route 2: skip grc20 and hand-emit an event carrying the canonical id.
    54 // The attributes are fully attacker-chosen, but pkg_path is not: the VM
    55 // stamps this realm. An indexer that accepts Transfer only from grc20's
    56 // pkg_path drops this event.
    57 chain.Emit(
    58 "Transfer",
    59 "token", canonical,
    60 "from", "",
    61 "to", cur.Address().String(),
    62 "value", "999999",
    63 )
    64}
    65
    66// Output:
    67// canonical id: gno.land/r/demo/canonicaltoken.FOO.0000000
    68// impostor id: gno.land/r/demo/grc20provenance.FOO.0000000
    69// impostor claims canonical id: false
    70
    71// Events:
    72// [
    73// {
    74// "type": "NewToken",
    75// "attrs": [
    76// {
    77// "key": "token",
    78// "value": "gno.land/r/demo/grc20provenance.FOO.0000000"
    79// },
    80// {
    81// "key": "name",
    82// "value": "Foo"
    83// },
    84// {
    85// "key": "symbol",
    86// "value": "FOO"
    87// },
    88// {
    89// "key": "decimals",
    90// "value": "4"
    91// }
    92// ],
    93// "pkg_path": "gno.land/p/nt/grc20/v0"
    94// },
    95// {
    96// "type": "Transfer",
    97// "attrs": [
    98// {
    99// "key": "token",
    100// "value": "gno.land/r/demo/grc20provenance.FOO.0000000"
    101// },
    102// {
    103// "key": "from",
    104// "value": ""
    105// },
    106// {
    107// "key": "to",
    108// "value": "g1vz4y807zq7p3s63dmyng9g80l58nmuc3lgmfjs"
    109// },
    110// {
    111// "key": "value",
    112// "value": "999999"
    113// }
    114// ],
    115// "pkg_path": "gno.land/p/nt/grc20/v0"
    116// },
    117// {
    118// "type": "Transfer",
    119// "attrs": [
    120// {
    121// "key": "token",
    122// "value": "gno.land/r/demo/canonicaltoken.FOO.0000000"
    123// },
    124// {
    125// "key": "from",
    126// "value": ""
    127// },
    128// {
    129// "key": "to",
    130// "value": "g1vz4y807zq7p3s63dmyng9g80l58nmuc3lgmfjs"
    131// },
    132// {
    133// "key": "value",
    134// "value": "999999"
    135// }
    136// ],
    137// "pkg_path": "gno.land/r/demo/grc20provenance"
    138// }
    139// ]
    140