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

currency.gno

3.20 Kb · 93 lines
 1// Package currency moves launchpad payments in native ugnot or any GRC20 token.
 2//
 3// Every function takes the calling realm's own cur as rlm, so funds always move
 4// to or from that realm and never from a realm the caller can name.
 5package currency
 6
 7import (
 8	"chain"
 9	"chain/banker"
10	"chain/runtime/unsafe"
11
12	"gno.land/p/nt/grc20/v0"
13	"gno.land/p/samcrew/launchpad/meta/v1"
14)
15
16const NativeDenom = "ugnot"
17
18// CollectNative accepts exactly amount ugnot attached by the user who called
19// the realm directly, and returns that user. Coins attached to a call that
20// reaches the realm through another realm belong to that other realm and are
21// refused.
22func CollectNative(_ int, rlm realm, amount int64) address {
23	if !rlm.IsCurrent() {
24		panic("launchpad/currency: rlm is not the current realm")
25	}
26	prev := rlm.Previous()
27	if !prev.IsUserCall() {
28		panic("launchpad/currency: native payment must be attached to a direct user call")
29	}
30	sent := unsafe.OriginSend()
31	if len(sent) != 1 || sent[0].Denom != NativeDenom || sent[0].Amount != amount {
32		panic("launchpad/currency: attached coins do not match the amount due")
33	}
34	return prev.Address()
35}
36
37// AssertNoCoins refuses coins attached by a user who calls the realm directly:
38// they would land in the realm, which keeps no account of them. Coins attached
39// to a call that reaches the realm through another realm went to that other
40// realm and are its business. The pinned chain also fails a call whose coins
41// no code reads; this check does not depend on that.
42func AssertNoCoins(_ int, rlm realm) {
43	if !rlm.IsCurrent() {
44		panic("launchpad/currency: rlm is not the current realm")
45	}
46	if rlm.Previous().IsUserCall() && len(unsafe.OriginSend()) != 0 {
47		panic("launchpad/currency: this call does not accept coins")
48	}
49}
50
51// A token ledger keys balances by the receiver's text, so a receiver in any
52// spelling but the one the chain gives a caller would be paid into a balance
53// no caller can reach.
54func assertReceiver(to address) {
55	if !meta.ValidAddress(to) {
56		panic("launchpad/currency: invalid receiver")
57	}
58}
59
60// PayNative sends amount ugnot from the calling realm.
61func PayNative(_ int, rlm realm, to address, amount int64) {
62	if !rlm.IsCurrent() {
63		panic("launchpad/currency: rlm is not the current realm")
64	}
65	assertReceiver(to)
66	banker.NewBanker(banker.BankerTypeRealmSend, rlm).
67		SendCoins(rlm.Address(), to, chain.Coins{{NativeDenom, amount}})
68}
69
70// CollectToken pulls amount of tok from the realm's direct caller, who must have
71// approved the calling realm, and returns that caller.
72func CollectToken(_ int, rlm realm, tok *grc20.Token, amount int64) address {
73	if !rlm.IsCurrent() {
74		panic("launchpad/currency: rlm is not the current realm")
75	}
76	AssertNoCoins(0, rlm)
77	payer := rlm.Previous().Address()
78	if err := tok.RealmTeller(0, rlm).TransferFrom(0, rlm, payer, rlm.Address(), amount); err != nil {
79		panic(err.Error())
80	}
81	return payer
82}
83
84// PayToken sends amount of tok from the calling realm's own balance.
85func PayToken(_ int, rlm realm, tok *grc20.Token, to address, amount int64) {
86	if !rlm.IsCurrent() {
87		panic("launchpad/currency: rlm is not the current realm")
88	}
89	assertReceiver(to)
90	if err := tok.RealmTeller(0, rlm).Transfer(0, rlm, to, amount); err != nil {
91		panic(err.Error())
92	}
93}