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

payment.gno

2.78 Kb · 93 lines
 1package drops
 2
 3import (
 4	"chain/banker"
 5
 6	"gno.land/p/samcrew/launchpad/currency/v1"
 7	sm "gno.land/p/samcrew/launchpad/safemath/v1"
 8	"gno.land/r/nt/grc20reg/v0"
 9	"gno.land/r/samcrew/launchpad/config/v1"
10)
11
12// terms is what this realm needs from config.
13type terms struct {
14	treasury      address
15	primaryFeeBPS int64 // share of each mint price
16	collectionFee int64 // in the currency asked for
17}
18
19// termsOf reads the terms in force. The collection fee is -1 for a currency
20// that has none.
21func termsOf(currencyKey string) terms {
22	p := config.GetVersion(config.GetCurrentVersion())
23	t := terms{treasury: p.Treasury, primaryFeeBPS: p.NFTPrimaryFeeBPS, collectionFee: -1}
24	for _, c := range p.Currencies {
25		if c.Key == currencyKey {
26			t.collectionFee = c.CollectionFee
27		}
28	}
29	return t
30}
31
32// policy returns the terms in force after checking that the lane is open for
33// the currency. It is a variable only so that unit tests can stand in for the
34// config realm, whose admin cannot be set from another package's tests.
35var policy = func(lane, currencyKey string) terms {
36	config.AssertLaneOpen(lane, currencyKey)
37	return termsOf(currencyKey)
38}
39
40// balance reads one denomination, so coins of other denominations sent to
41// the realm never add to the cost of a payment.
42func balance(cur realm, key string) int64 {
43	if key == config.NativeCurrency {
44		return banker.NewReadonlyBanker().GetCoin(cur.Address(), key)
45	}
46	return grc20reg.MustGet(key).BalanceOf(cur.Address())
47}
48
49// take collects price from the direct caller and returns what the realm held
50// before. Native coins come attached: the caller attaches exactly offered, at
51// least the price, and the difference goes straight back. A token is pulled
52// for exactly the price.
53func take(cur realm, key string, price, offered int64) int64 {
54	if offered < price {
55		panic("launchpad/drops: price above the amount offered")
56	}
57	if key != config.NativeCurrency {
58		held := balance(cur, key)
59		if price == 0 {
60			currency.AssertNoCoins(0, cur)
61		} else {
62			currency.CollectToken(0, cur, grc20reg.MustGet(key), price)
63		}
64		return held
65	}
66	if offered == 0 {
67		currency.AssertNoCoins(0, cur)
68		return balance(cur, key)
69	}
70	buyer := currency.CollectNative(0, cur, offered)
71	held := sm.Sub(balance(cur, key), offered)
72	pay(cur, key, buyer, offered-price)
73	return held
74}
75
76func pay(cur realm, key string, to address, amount int64) {
77	if amount == 0 {
78		return
79	}
80	if key == config.NativeCurrency {
81		currency.PayNative(0, cur, to, amount)
82	} else {
83		currency.PayToken(0, cur, grc20reg.MustGet(key), to, amount)
84	}
85}
86
87// settled aborts the transaction unless everything taken has been paid out:
88// the realm must hold exactly what it held before the call.
89func settled(cur realm, key string, held int64) {
90	if balance(cur, key) != held {
91		panic("launchpad/drops: payment not fully settled")
92	}
93}