banker_coins.gno

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