PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

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
  • types.gnogno
    1package grc2023import (4	"errors"56	"gno.land/p/nt/avl/v0"7)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// Teller interface defines the methods that a GRC20 token must implement. It
    10// extends the TokenMetadata interface to include methods for managing token
    11// transfers, allowances, and querying balances.
    12//
    13// The Teller interface is designed to ensure that any token adhering to this
    14// standard provides a consistent API for interacting with fungible tokens.
    15//
    16// SECURITY: Transfer/Approve/TransferFrom take (_ int, rlm realm, ...), so
    17// handing a Teller value to untrusted code yields a capability token to
    18// whatever Transfer/Approve/TransferFrom impl that code dispatches into.
    19// Any /p/ or /r/ function that accepts a Teller as a parameter from external
    20// callers MUST type-assert against the canonical concrete type (*fnTeller)
    21// via IsCanonicalTeller and reject otherwise. An unexported-marker "seal"
    22// does NOT defend against this — see
    23// p/test/seal/filetests/z_seal_iface_embedding_filetest.gno
    24// for the realistic embedding-bypass attack. Reference impl for the
    25// canonical-allowlist pattern: p/jaekwon/allowancesender.
    26type Teller interface {
    27 // Returns the name of the token.
    28 GetName() string
    29
    30 // Returns the symbol of the token, usually a shorter version of the
    31 // name.
    32 GetSymbol() string
    33
    34 // Returns the decimals places of the token.
    35 GetDecimals() int
    36
    37 // Returns the amount of tokens in existence.
    38 TotalSupply() int64
    39
    40 // Returns the amount of tokens owned by `account`.
    41 BalanceOf(account address) int64
    42
    43 // Moves `amount` tokens from the caller's account to `to`. rlm must
    44 // be the caller's own captured cur — verified via rlm.IsCurrent().
    45 //
    46 // Returns an error if the operation failed.
    47 Transfer(_ int, rlm realm, to address, amount int64) error
    48
    49 // Returns the remaining number of tokens that `spender` will be
    50 // allowed to spend on behalf of `owner` through {transferFrom}. This is
    51 // zero by default.
    52 //
    53 // This value changes when {approve} or {transferFrom} are called.
    54 Allowance(owner, spender address) int64
    55
    56 // Sets `amount` as the allowance of `spender` over the caller's tokens.
    57 //
    58 // Returns an error if the operation failed.
    59 //
    60 // IMPORTANT: Beware that changing an allowance with this method brings
    61 // the risk that someone may use both the old and the new allowance by
    62 // unfortunate transaction ordering. One possible solution to mitigate
    63 // this race condition is to first reduce the spender's allowance to 0
    64 // and set the desired value afterwards:
    65 // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    66 Approve(_ int, rlm realm, spender address, amount int64) error
    67
    68 // Moves `amount` tokens from `from` to `to` using the
    69 // allowance mechanism. `amount` is then deducted from the caller's
    70 // allowance.
    71 //
    72 // Returns an error if the operation failed.
    73 TransferFrom(_ int, rlm realm, from, to address, amount int64) error
    74}
    75
    76// Token represents a fungible token with an ID, name, symbol, and a certain
    77// number of decimal places. It maintains a ledger for tracking balances and
    78// allowances of addresses.
    79//
    80// The Token struct provides methods for retrieving token metadata, such as the
    81// name, symbol, and decimals, as well as methods for interacting with the
    82// ledger, including checking balances and allowances.
    83type Token struct {
    84 // Identifier precomputed in NewToken to make ID() a cheap field read.
    85 id string
    86 // Name of the token (e.g., "Dummy Token").
    87 name string
    88 // Symbol of the token (e.g., "DUMMY").
    89 symbol string
    90 // Number of decimal places used for the token's precision.
    91 decimals int
    92 // Pointer to the PrivateLedger that manages balances and allowances.
    93 ledger *PrivateLedger
    94 // origRealm is the PkgPath of the realm that created the token, captured
    95 // unforgeably in NewToken. A frame-relative teller only works there.
    96 origRealm string
    97}
    98
    99// PrivateLedger is a struct that holds the balances and allowances for the
    100// token. It provides administrative functions for minting, burning,
    101// transferring tokens, and managing allowances.
    102//
    103// The PrivateLedger is not safe to expose publicly, as it contains sensitive
    104// information regarding token balances and allowances, and allows direct,
    105// unrestricted access to all administrative functions.
    106type PrivateLedger struct {
    107 // Total supply of the token managed by this ledger.
    108 totalSupply int64
    109 // chain.Address -> int64
    110 balances avl.Tree
    111 // owner.(chain.Address)+":"+spender.(chain.Address)) -> int64
    112 allowances avl.Tree
    113 // Pointer to the associated Token struct
    114 token *Token
    115}
    116
    117var (
    118 ErrInsufficientBalance = errors.New("insufficient balance")
    119 ErrInsufficientAllowance = errors.New("insufficient allowance")
    120 ErrInvalidAddress = errors.New("invalid address")
    121 ErrCannotTransferToSelf = errors.New("cannot send transfer to self")
    122 ErrReadonly = errors.New("banker is readonly")
    123 ErrRestrictedTokenOwner = errors.New("restricted to bank owner")
    124 ErrMintOverflow = errors.New("mint overflow")
    125 ErrInvalidAmount = errors.New("invalid amount")
    126 ErrSpoofedRealm = errors.New("rlm does not match the current crossing frame")
    127 ErrForeignCallerTeller = errors.New("caller teller is confined to the token's own realm")
    128 ErrNotRealm = errors.New("rlm must be a realm (got EOA/origin)")
    129 ErrInvalidName = errors.New("invalid token name (empty, too long, or contains control chars)")
    130 ErrInvalidSymbol = errors.New("invalid token symbol (empty, too long, or contains chars outside [A-Za-z0-9_-])")
    131 ErrInvalidDecimals = errors.New("invalid decimals (must be 0..18)")
    132)
    133
    134// Construction limits. Symbol is restricted to the same charset as
    135// grc20reg.validateSlug because it is included in Token.ID(), which is
    136// emitted in events and frequently used as a registry slug; banning `.` `/`
    137// and whitespace here prevents downstream parsers from being fooled by
    138// ambiguous IDs. Name is for display only and allows any valid UTF-8 except
    139// control characters.
    140const (
    141 MaxNameLen = 64
    142 MaxSymbolLen = 11
    143 MaxDecimals = 18
    144)
    145
    146const (
    147 NewTokenEvent = "NewToken"
    148 MintEvent = "Mint"
    149 BurnEvent = "Burn"
    150 TransferEvent = "Transfer"
    151 ApprovalEvent = "Approval"
    152)
    153
    154type fnTeller struct {
    155 accountFn func(_ int, rlm realm) address
    156 // homeGuard marks a frame-relative teller (PrivateLedger.CallerTeller),
    157 // whose actor is resolved from the invoking frame. Such a teller is only
    158 // meaningful in the token's own realm and is refused anywhere else, so
    159 // exporting the value cannot hand out a spend capability.
    160 homeGuard bool
    161 *Token
    162}
    163
    164var _ Teller = (*fnTeller)(nil)
    165
    166// IsCanonicalTeller reports whether t is the canonical *fnTeller produced by
    167// Token.CallerTeller / RealmTeller / RealmSubTeller / ReadonlyTeller /
    168// ImpersonateTeller. Use this at any public entry point that accepts a
    169// Teller from an external caller before invoking its methods.
    170//
    171// Foreign types — including embedding-based wrappers like
    172// `type Evil struct { grc20.Teller }` — are rejected because type
    173// assertions are nominal: *Evil is not *fnTeller, regardless of method
    174// promotion. This is the reliable defense; the unexported-marker "seal"
    175// pattern is bypassable via embedding (see
    176// p/test/seal/filetests/z_seal_iface_embedding_filetest.gno).
    177//
    178// Mirrors the precedent of chain/banker.IsCanonical and
    179// p/jaekwon/allowancesender's canonical-impl check.
    180func IsCanonicalTeller(t Teller) bool {
    181 _, ok := t.(*fnTeller)
    182 return ok
    183}
    184