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}