Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}