disperse.gno
3.28 Kb · 114 lines
1package disperse
2
3import (
4 "chain"
5 "chain/banker"
6 "chain/runtime"
7
8 tokens "gno.land/r/demo/defi/grc20factory"
9)
10
11var realmAddr = runtime.CurrentRealm().Address()
12
13// DisperseUgnot parses receivers and amounts and sends out ugnot
14// The function will send out the coins to the addresses and return the leftover coins to the caller
15// if there are any to return
16func DisperseUgnot(cur realm, addresses []address, coins chain.Coins) {
17 // Reject non-EOA callers: banker.OriginSend() and the realm-balance
18 // check below describe coins that actually landed at this realm only
19 // when the caller is a pure EOA. A `maketx run` ephemeral realm or
20 // intermediate code realm could otherwise consume the envelope and
21 // have this function disperse pre-existing realm balance to
22 // attacker-chosen addresses.
23 if !runtime.PreviousRealm().IsUserCall() {
24 panic("only user-call (maketx call) accepted")
25 }
26 coinSent := banker.OriginSend()
27 caller := runtime.PreviousRealm().Address()
28 banker_ := banker.NewBanker(banker.BankerTypeRealmSend)
29
30 if len(addresses) != len(coins) {
31 panic(ErrNumAddrValMismatch)
32 }
33
34 for _, coin := range coins {
35 if coin.Amount <= 0 {
36 panic(ErrNegativeCoinAmount)
37 }
38
39 if banker_.GetCoins(realmAddr).AmountOf(coin.Denom) < coin.Amount {
40 panic(ErrMismatchBetweenSentAndParams)
41 }
42 }
43
44 // Send coins
45 for i := range addresses {
46 banker_.SendCoins(realmAddr, addresses[i], chain.NewCoins(coins[i]))
47 }
48
49 // Return possible leftover coins
50 for _, coin := range coinSent {
51 leftoverAmt := banker_.GetCoins(realmAddr).AmountOf(coin.Denom)
52 if leftoverAmt > 0 {
53 send := chain.Coins{chain.NewCoin(coin.Denom, leftoverAmt)}
54 banker_.SendCoins(realmAddr, caller, send)
55 }
56 }
57}
58
59// DisperseUgnotString receives a string of addresses and a string of amounts
60// and parses them to be used in DisperseUgnot
61func DisperseUgnotString(cur realm, addresses string, amounts string) {
62 parsedAddresses, err := parseAddresses(addresses)
63 if err != nil {
64 panic(err)
65 }
66
67 parsedAmounts, err := parseAmounts(amounts)
68 if err != nil {
69 panic(err)
70 }
71
72 coins := make(chain.Coins, len(parsedAmounts))
73 for i, amount := range parsedAmounts {
74 coins[i] = chain.NewCoin("ugnot", amount)
75 }
76
77 DisperseUgnot(cur, parsedAddresses, coins)
78}
79
80// DisperseGRC20 disperses tokens to multiple addresses
81// Note that it is necessary to approve the realm to spend the tokens before calling this function
82// see the corresponding filetests for examples
83func DisperseGRC20(cur realm, addresses []address, amounts []int64, symbols []string) {
84 caller := runtime.PreviousRealm().Address()
85
86 if (len(addresses) != len(amounts)) || (len(amounts) != len(symbols)) {
87 panic(ErrArgLenAndSentLenMismatch)
88 }
89 for _, amount := range amounts {
90 if amount < 0 {
91 panic(ErrInvalidAmount)
92 }
93 }
94
95 for i := 0; i < len(addresses); i++ {
96 tokens.TransferFrom(cross, symbols[i], caller, addresses[i], amounts[i])
97 }
98}
99
100// DisperseGRC20String receives a string of addresses and a string of tokens
101// and parses them to be used in DisperseGRC20
102func DisperseGRC20String(cur realm, addresses string, tokens string) {
103 parsedAddresses, err := parseAddresses(addresses)
104 if err != nil {
105 panic(err)
106 }
107
108 parsedAmounts, parsedSymbols, err := parseTokens(tokens)
109 if err != nil {
110 panic(err)
111 }
112
113 DisperseGRC20(cur, parsedAddresses, parsedAmounts, parsedSymbols)
114}