banker_coins.gno

2.90 Kb ยท 117 lines
  1package treasury
  2
  3import (
  4	"errors"
  5	"std"
  6
  7	"gno.land/p/aeddi/panictoerr"
  8)
  9
 10var ErrNoStdBankerProvided = errors.New("no std banker provided")
 11
 12// CoinsBanker is a Banker that sends std.Coins.
 13type CoinsBanker struct {
 14	owner  std.Address // The address of this coins banker owner.
 15	banker std.Banker  // The underlying std banker, must be a BankerTypeRealmSend.
 16}
 17
 18var _ Banker = (*CoinsBanker)(nil)
 19
 20// ID implements Banker.
 21func (CoinsBanker) ID() string {
 22	return "Coins"
 23}
 24
 25// Send implements Banker.
 26func (cb *CoinsBanker) Send(p Payment) error {
 27	if std.CurrentRealm().Address() != cb.owner {
 28		return ErrCurrentRealmIsNotOwner
 29	}
 30	// Check if payment is of type coinsPayment.
 31	payment, ok := p.(coinsPayment)
 32	if !ok {
 33		return ErrInvalidPaymentType
 34	}
 35
 36	// Send the coins.
 37	return panictoerr.PanicToError(func() {
 38		cb.banker.SendCoins(cb.owner, payment.toAddress, payment.coins)
 39	})
 40}
 41
 42// Balances implements Banker.
 43func (cb *CoinsBanker) Balances() []Balance {
 44	// Get the coins from the banker.
 45	coins := cb.banker.GetCoins(cb.owner)
 46
 47	// Convert std.Coins to []Balance.
 48	balances := make([]Balance, len(coins))
 49	for i := range coins {
 50		balances[i] = Balance{
 51			Denom:  coins[i].Denom,
 52			Amount: coins[i].Amount,
 53		}
 54	}
 55
 56	return balances
 57}
 58
 59// Address implements Banker.
 60func (cb *CoinsBanker) Address() string {
 61	return cb.owner.String()
 62}
 63
 64// NewCoinsBanker creates a new CoinsBanker with the current Realm's address
 65// as the owner.
 66func NewCoinsBanker(banker std.Banker) (*CoinsBanker, error) {
 67	owner := std.CurrentRealm().Address()
 68
 69	return NewCoinsBankerWithOwner(owner, banker)
 70}
 71
 72// NewCoinsBankerWithOwner creates a new CoinsBanker with the given address.
 73func NewCoinsBankerWithOwner(owner std.Address, banker std.Banker) (*CoinsBanker, error) {
 74	if owner == "" {
 75		return nil, ErrNoOwnerProvided
 76	}
 77
 78	// NOTE: Should we add methods to std.Banker to check both its type and the
 79	// associated Realm for this kind of case?
 80	// For example:
 81	// if banker.Type() != std.BankerTypeRealmSend { panic("banker must be of type std.BankerTypeRealmSend") }
 82	// if banker.Realm().Address() != owner { panic("banker must be owned by the given owner address") }
 83	if banker == nil {
 84		return nil, ErrNoStdBankerProvided
 85	}
 86
 87	return &CoinsBanker{
 88		owner:  owner,
 89		banker: banker,
 90	}, nil
 91}
 92
 93// coinsPayment represents a payment that is issued by a CoinsBanker.
 94type coinsPayment struct {
 95	coins     std.Coins   // The coins being sent.
 96	toAddress std.Address // The recipient of the payment.
 97}
 98
 99var _ Payment = (*coinsPayment)(nil)
100
101// BankerID implements Payment.
102func (coinsPayment) BankerID() string {
103	return CoinsBanker{}.ID()
104}
105
106// String implements Payment.
107func (cp coinsPayment) String() string {
108	return cp.coins.String() + " to " + cp.toAddress.String()
109}
110
111// NewCoinsPayment creates a new coinsPayment.
112func NewCoinsPayment(coins std.Coins, toAddress std.Address) Payment {
113	return coinsPayment{
114		coins:     coins,
115		toAddress: toAddress,
116	}
117}