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

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}