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 move4// to or from that realm and never from a realm the caller can name.5package currency67import (8 "chain"9 "chain/banker"10 "chain/runtime/unsafe"1112 "gno.land/p/nt/grc20/v0"13 "gno.land/p/samcrew/launchpad/meta/v1"14)1516const NativeDenom = "ugnot"1718// CollectNative accepts exactly amount ugnot attached by the user who called19// the realm directly, and returns that user. Coins attached to a call that20// reaches the realm through another realm belong to that other realm and are21// 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}3637// 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 attached39// to a call that reaches the realm through another realm went to that other40// realm and are its business. The pinned chain also fails a call whose coins41// 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}5051// A token ledger keys balances by the receiver's text, so a receiver in any52// spelling but the one the chain gives a caller would be paid into a balance53// no caller can reach.54func assertReceiver(to address) {55 if !meta.ValidAddress(to) {56 panic("launchpad/currency: invalid receiver")57 }58}5960// 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}6970// CollectToken pulls amount of tok from the realm's direct caller, who must have71// 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 payer82}8384// 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}94Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.