1package grc20
2
3import (
4 "errors"
5 "std"
6
7 "gno.land/p/demo/avl"
8 "gno.land/p/demo/grc/exts"
9)
10
11// Teller interface defines the methods that a GRC20 token must implement. It
12// extends the TokenMetadata interface to include methods for managing token
13// transfers, allowances, and querying balances.
14//
15// The Teller interface is designed to ensure that any token adhering to this
16// standard provides a consistent API for interacting with fungible tokens.
17type Teller interface {
18 exts.TokenMetadata
19
20 // Returns the amount of tokens in existence.
21 TotalSupply() uint64
22
23 // Returns the amount of tokens owned by `account`.
24 BalanceOf(account std.Address) uint64
25
26 // Moves `amount` tokens from the caller's account to `to`.
27 //
28 // Returns an error if the operation failed.
29 Transfer(to std.Address, amount uint64) error
30
31 // Returns the remaining number of tokens that `spender` will be
32 // allowed to spend on behalf of `owner` through {transferFrom}. This is
33 // zero by default.
34 //
35 // This value changes when {approve} or {transferFrom} are called.
36 Allowance(owner, spender std.Address) uint64
37
38 // Sets `amount` as the allowance of `spender` over the caller's tokens.
39 //
40 // Returns an error if the operation failed.
41 //
42 // IMPORTANT: Beware that changing an allowance with this method brings
43 // the risk that someone may use both the old and the new allowance by
44 // unfortunate transaction ordering. One possible solution to mitigate
45 // this race condition is to first reduce the spender's allowance to 0
46 // and set the desired value afterwards:
47 // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
48 Approve(spender std.Address, amount uint64) error
49
50 // Moves `amount` tokens from `from` to `to` using the
51 // allowance mechanism. `amount` is then deducted from the caller's
52 // allowance.
53 //
54 // Returns an error if the operation failed.
55 TransferFrom(from, to std.Address, amount uint64) error
56}
57
58// Token represents a fungible token with a name, symbol, and a certain number
59// of decimal places. It maintains a ledger for tracking balances and allowances
60// of addresses.
61//
62// The Token struct provides methods for retrieving token metadata, such as the
63// name, symbol, and decimals, as well as methods for interacting with the
64// ledger, including checking balances and allowances.
65type Token struct {
66 // Name of the token (e.g., "Dummy Token").
67 name string
68 // Symbol of the token (e.g., "DUMMY").
69 symbol string
70 // Number of decimal places used for the token's precision.
71 decimals uint
72 // Pointer to the PrivateLedger that manages balances and allowances.
73 ledger *PrivateLedger
74}
75
76// TokenGetter is a function type that returns a Token pointer. This type allows
77// bypassing a limitation where we cannot directly pass Token pointers between
78// realms. Instead, we pass this function which can then be called to get the
79// Token pointer. For more details on this limitation and workaround, see:
80// https://github.com/gnolang/gno/pull/3135
81type TokenGetter func() *Token
82
83// PrivateLedger is a struct that holds the balances and allowances for the
84// token. It provides administrative functions for minting, burning,
85// transferring tokens, and managing allowances.
86//
87// The PrivateLedger is not safe to expose publicly, as it contains sensitive
88// information regarding token balances and allowances, and allows direct,
89// unrestricted access to all administrative functions.
90type PrivateLedger struct {
91 // Total supply of the token managed by this ledger.
92 totalSupply uint64
93 // std.Address -> uint64
94 balances avl.Tree
95 // owner.(std.Address)+":"+spender.(std.Address)) -> uint64
96 allowances avl.Tree
97 // Pointer to the associated Token struct
98 token *Token
99}
100
101var (
102 ErrInsufficientBalance = errors.New("insufficient balance")
103 ErrInsufficientAllowance = errors.New("insufficient allowance")
104 ErrInvalidAddress = errors.New("invalid address")
105 ErrCannotTransferToSelf = errors.New("cannot send transfer to self")
106 ErrReadonly = errors.New("banker is readonly")
107 ErrRestrictedTokenOwner = errors.New("restricted to bank owner")
108 ErrOverflow = errors.New("Mint overflow")
109)
110
111const (
112 MintEvent = "Mint"
113 BurnEvent = "Burn"
114 TransferEvent = "Transfer"
115 ApprovalEvent = "Approval"
116)
117
118type fnTeller struct {
119 accountFn func() std.Address
120 *Token
121}
122
123var _ Teller = (*fnTeller)(nil)
types.gno
4.27 Kb ยท 123 lines