Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}