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}