Search Apps Documentation Source Content File Folder Download Copy Actions Download

banker_grc20.gno

3.36 Kb · 131 lines
  1package treasury
  2
  3import (
  4	"errors"
  5	"strconv"
  6
  7	"gno.land/p/demo/tokens/grc20"
  8	"gno.land/p/nt/ufmt/v0"
  9)
 10
 11var (
 12	ErrNoListerProvided   = errors.New("no lister provided")
 13	ErrGRC20TokenNotFound = errors.New("GRC20 token not found")
 14)
 15
 16// GRC20Banker is a Banker that sends GRC20 tokens listed using a getter
 17// set during initialization.
 18type GRC20Banker struct {
 19	owner  address         // The address of this GRC20 banker owner.
 20	lister TokenListerFunc // Allows to list tokens from methods that require it.
 21}
 22
 23// TokenListerFunc is a function type that returns a map of GRC20 tokens.
 24type TokenListerFunc func() map[string]*grc20.Token
 25
 26var _ Banker = (*GRC20Banker)(nil)
 27
 28// ID implements Banker.
 29func (GRC20Banker) ID() string {
 30	return "GRC20"
 31}
 32
 33// Send implements Banker.
 34//
 35// rlm must be the caller's own captured cur (i.e. the cur of the
 36// immediate crossing-function caller). Sending with rlm = cur.Previous()
 37// or any other realm value is rejected: rlm.IsCurrent() asserts pointer
 38// identity against the topmost crossing frame. Combined with the
 39// rlm.Address() == gb.owner check, this restricts Send to the owning
 40// realm acting in its own frame.
 41func (gb *GRC20Banker) Send(_ int, rlm realm, p Payment) error {
 42	if !rlm.IsCurrent() {
 43		return ErrSpoofedRealm
 44	}
 45	if rlm.Address() != gb.owner {
 46		return ErrCurrentRealmIsNotOwner
 47	}
 48
 49	payment, ok := p.(grc20Payment)
 50	if !ok {
 51		return ErrInvalidPaymentType
 52	}
 53
 54	// Get the GRC20 tokens using the lister.
 55	tokens := gb.lister()
 56
 57	// Look for the token corresponding to the payment tokenKey.
 58	token, ok := tokens[payment.tokenKey]
 59	if !ok {
 60		return ufmt.Errorf("%v: %s", ErrGRC20TokenNotFound, payment.tokenKey)
 61	}
 62
 63	// Send the token from the owner's balance.
 64	return token.RealmTeller(0, rlm).Transfer(0, rlm, payment.toAddress, payment.amount)
 65}
 66
 67// Balances implements Banker.
 68func (gb *GRC20Banker) Balances() []Balance {
 69	// Get the GRC20 tokens from the lister.
 70	tokens := gb.lister()
 71
 72	// Convert GRC20 tokens to []Balance.
 73	var balances []Balance
 74	for key, token := range tokens {
 75		balances = append(balances, Balance{
 76			Denom:  key,
 77			Amount: token.BalanceOf(gb.owner),
 78		})
 79	}
 80	return balances
 81}
 82
 83// Address implements Banker.
 84func (gb *GRC20Banker) Address() string {
 85	return gb.owner.String()
 86}
 87
 88// NewGRC20BankerWithOwner creates a new GRC20Banker with the given address.
 89func NewGRC20BankerWithOwner(owner address, lister TokenListerFunc) (*GRC20Banker, error) {
 90	if owner == "" {
 91		return nil, ErrNoOwnerProvided
 92	}
 93
 94	if lister == nil {
 95		return nil, ErrNoListerProvided
 96	}
 97
 98	return &GRC20Banker{
 99		owner:  owner,
100		lister: lister,
101	}, nil
102}
103
104// grc20Payment represents a payment that is issued by a GRC20Banker.
105type grc20Payment struct {
106	tokenKey  string  // The key associated with the GRC20 token.
107	amount    int64   // The amount of token to send.
108	toAddress address // The recipient of the payment.
109}
110
111var _ Payment = (*grc20Payment)(nil)
112
113// BankerID implements Payment.
114func (grc20Payment) BankerID() string {
115	return GRC20Banker{}.ID()
116}
117
118// String implements Payment.
119func (gp grc20Payment) String() string {
120	amount := strconv.Itoa(int(gp.amount))
121	return amount + gp.tokenKey + " to " + gp.toAddress.String()
122}
123
124// NewGRC20Payment creates a new grc20Payment.
125func NewGRC20Payment(tokenKey string, amount int64, toAddress address) Payment {
126	return grc20Payment{
127		tokenKey:  tokenKey,
128		amount:    amount,
129		toAddress: toAddress,
130	}
131}