Search Apps Documentation Source Content File Folder Download Copy

tellers.gno

3.63 Kb ยท 139 lines
  1package grc20
  2
  3import (
  4	"std"
  5)
  6
  7// CallerTeller returns a GRC20 compatible teller that checks the PrevRealm
  8// caller for each call. It's usually safe to expose it publicly to let users
  9// manipulate their tokens directly, or for realms to use their allowance.
 10func (tok *Token) CallerTeller() Teller {
 11	if tok == nil {
 12		panic("Token cannot be nil")
 13	}
 14
 15	return &fnTeller{
 16		accountFn: func() std.Address {
 17			caller := std.PrevRealm().Addr()
 18			return caller
 19		},
 20		Token: tok,
 21	}
 22}
 23
 24// ReadonlyTeller is a GRC20 compatible teller that panics for any write operation.
 25func (tok *Token) ReadonlyTeller() Teller {
 26	if tok == nil {
 27		panic("Token cannot be nil")
 28	}
 29
 30	return &fnTeller{
 31		accountFn: nil,
 32		Token:     tok,
 33	}
 34}
 35
 36// RealmTeller returns a GRC20 compatible teller that will store the
 37// caller realm permanently. Calling anything through this teller will
 38// result in allowance or balance changes for the realm that initialized the teller.
 39// The initializer of this teller should usually never share the resulting Teller from
 40// this method except maybe for advanced delegation flows such as a DAO treasury
 41// management.
 42func (tok *Token) RealmTeller() Teller {
 43	if tok == nil {
 44		panic("Token cannot be nil")
 45	}
 46
 47	caller := std.PrevRealm().Addr()
 48
 49	return &fnTeller{
 50		accountFn: func() std.Address {
 51			return caller
 52		},
 53		Token: tok,
 54	}
 55}
 56
 57// RealmSubTeller is like RealmTeller but uses the provided slug to derive a
 58// subaccount.
 59func (tok *Token) RealmSubTeller(slug string) Teller {
 60	if tok == nil {
 61		panic("Token cannot be nil")
 62	}
 63
 64	caller := std.PrevRealm().Addr()
 65	account := accountSlugAddr(caller, slug)
 66
 67	return &fnTeller{
 68		accountFn: func() std.Address {
 69			return account
 70		},
 71		Token: tok,
 72	}
 73}
 74
 75// ImpersonateTeller returns a GRC20 compatible teller that impersonates as a
 76// specified address. This allows operations to be performed as if they were
 77// executed by the given address, enabling the caller to manipulate tokens on
 78// behalf of that address.
 79//
 80// It is particularly useful in scenarios where a contract needs to perform
 81// actions on behalf of a user or another account, without exposing the
 82// underlying logic or requiring direct access to the user's account. The
 83// returned teller will use the provided address for all operations, effectively
 84// masking the original caller.
 85//
 86// This method should be used with caution, as it allows for potentially
 87// sensitive operations to be performed under the guise of another address.
 88func (ledger *PrivateLedger) ImpersonateTeller(addr std.Address) Teller {
 89	if ledger == nil {
 90		panic("Ledger cannot be nil")
 91	}
 92
 93	return &fnTeller{
 94		accountFn: func() std.Address {
 95			return addr
 96		},
 97		Token: ledger.token,
 98	}
 99}
100
101// generic tellers methods.
102//
103
104func (ft *fnTeller) Transfer(to std.Address, amount uint64) error {
105	if ft.accountFn == nil {
106		return ErrReadonly
107	}
108	caller := ft.accountFn()
109	return ft.Token.ledger.Transfer(caller, to, amount)
110}
111
112func (ft *fnTeller) Approve(spender std.Address, amount uint64) error {
113	if ft.accountFn == nil {
114		return ErrReadonly
115	}
116	caller := ft.accountFn()
117	return ft.Token.ledger.Approve(caller, spender, amount)
118}
119
120func (ft *fnTeller) TransferFrom(owner, to std.Address, amount uint64) error {
121	if ft.accountFn == nil {
122		return ErrReadonly
123	}
124	spender := ft.accountFn()
125	return ft.Token.ledger.TransferFrom(owner, spender, to, amount)
126}
127
128// helpers
129//
130
131// accountSlugAddr returns the address derived from the specified address and slug.
132func accountSlugAddr(addr std.Address, slug string) std.Address {
133	// XXX: use a new `std.XXX` call for this.
134	if slug == "" {
135		return addr
136	}
137	key := addr.String() + "/" + slug
138	return std.DerivePkgAddr(key) // temporarily using this helper
139}