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