Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions 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}