support.gno
4.54 Kb · 136 lines
1package catalog
2
3import (
4 "chain"
5 "chain/banker"
6 "strings"
7 "time"
8
9 "gno.land/p/nym-alexiscolin000/gnoradio/role/v0"
10 "gno.land/p/nym-alexiscolin000/gnoradio/store/v0"
11 "gno.land/p/nym-alexiscolin000/gnoradio/text/v0"
12 "gno.land/r/nym-alexiscolin000/gnoradio/data"
13)
14
15// GnoRadio's own funding, always on top of what artists receive and always
16// visible on-chain: direct support and the optional share added to a tip.
17// Every coin is forwarded to the treasury in the same transaction.
18
19// SupportGnoRadio sends the attached ugnot to the GnoRadio treasury.
20func SupportGnoRadio(cur realm) {
21 caller := userCaller(cur)
22 amt := paid()
23 if amt < minTip || amt > maxTip {
24 panic("catalog: support is between 0.1 and 1000000 GNOT")
25 }
26 t := rd()
27 if treasury(t) == "" {
28 panic("catalog: no treasury is set, GnoRadio takes no support")
29 }
30 bk := banker.NewBanker(banker.BankerTypeRealmSend, cur)
31 bk.SendCoins(cur.Address(), treasury(t), chain.Coins{{Denom: denom, Amount: amt}})
32 recordSupport(t, caller, amt)
33 save(cur, t)
34 emitEvent("Supported", "by", caller.String(), "amount", text.Itoa64(amt))
35}
36
37// SetTreasury changes where GnoRadio's support goes; "" (the default) takes none. Admin only.
38func SetTreasury(cur realm, to address) {
39 onlyAdmin(cur)
40 if to != "" && !role.Canonical(to) { // "" switches support off
41 panic("catalog: invalid address")
42 }
43 if data.IsGnoRadio(to) {
44 panic("catalog: the treasury cannot be a GnoRadio realm")
45 }
46 t := rd()
47 emitEvent("TreasuryChanged", "from", treasury(t).String(), "to", to.String())
48 t.set(cConfig, "treasury", to.String())
49 save(cur, t)
50}
51
52// SetMonthlyGoal sets the monthly support goal shown in the app (ugnot). Admin only.
53func SetMonthlyGoal(cur realm, ugnot int64) {
54 onlyAdmin(cur)
55 if ugnot < 0 || ugnot > maxTip {
56 panic("catalog: goal out of range")
57 }
58 t := rd()
59 t.set(cConfig, "goal", text.Itoa64(ugnot))
60 save(cur, t)
61 emitEvent("MonthlyGoal", "ugnot", text.Itoa64(ugnot))
62}
63
64func treasury(t *tx) address { return address(t.val(cConfig, "treasury")) }
65
66func Treasury() address { return treasury(rd()) }
67
68// SupportInfo returns GnoRadio's public funding state for this month.
69func SupportInfo() (to address, total int64, supporters int, monthTotal, goal int64) {
70 t := rd()
71 return treasury(t), t.count(mSupport), int(t.count(mSupporters)), text.Atoi64(t.val(cMonthly, month(now()))), text.Atoi64(t.val(cConfig, "goal"))
72}
73
74func recordSupport(t *tx, by address, amt int64) {
75 t.bump(mSupport, amt)
76 s, had := t.get(cSupporters, by.String())
77 if !had {
78 t.bump(mSupporters, 1)
79 }
80 total := text.Atoi64(s) + amt
81 t.set(cSupporters, by.String(), text.Itoa64(total))
82 t.rank(topSupport, by.String(), total, true)
83 mo := month(now())
84 t.set(cMonthly, mo, text.Itoa64(text.Atoi64(t.val(cMonthly, mo))+amt))
85 t.activity("support", by, "0", "0", text.Itoa64(amt))
86}
87
88func month(unix int64) string { return time.Unix(unix, 0).UTC().Format("2006-01") }
89
90// Activities returns up to limit entries, newest first.
91func Activities(limit int) []Activity {
92 limit = store.Limit(limit, activitySize)
93 t := rd()
94 head := text.Atoi(t.val(cMeta, "head"))
95 out := make([]Activity, 0, limit)
96 for i := 1; i <= limit; i++ {
97 v := t.val(cActivity, store.Pad((head-i+activitySize)%activitySize))
98 if v == "" {
99 break // the ring is not full yet
100 }
101 f := store.Fields(v)
102 out = append(out, Activity{Kind: f[0], By: address(f[1]), Track: text.Atoi(f[2]), Artist: text.Atoi(f[3]), Amount: text.Atoi64(f[4]), At: text.Atoi64(f[5])})
103 }
104 return out
105}
106
107// ActivityJSON returns the activity feed, newest first (limit <= 64).
108func ActivityJSON(limit int) string {
109 var b strings.Builder
110 b.WriteString("[")
111 for i, a := range Activities(limit) {
112 if i > 0 {
113 b.WriteString(",")
114 }
115 b.WriteString(`{"kind":` + text.Str(a.Kind) + `,"by":` + text.Str(a.By.String()) + `,"track":` + text.Itoa(a.Track) +
116 `,"artist":` + text.Itoa(a.Artist) + `,"amount":` + text.Itoa64(a.Amount) + `,"at":` + text.Itoa64(a.At) + `}`)
117 }
118 b.WriteString("]")
119 return b.String()
120}
121
122// SupportJSON returns GnoRadio's public funding state.
123func SupportJSON() string {
124 to, total, supporters, mt, goal := SupportInfo()
125 var b strings.Builder
126 b.WriteString(`{"treasury":` + text.Str(to.String()) + `,"total":` + text.Itoa64(total) + `,"supporters":` + text.Itoa(supporters) +
127 `,"month":` + text.Str(month(now())) + `,"monthTotal":` + text.Itoa64(mt) + `,"goal":` + text.Itoa64(goal) + `,"top":[`)
128 for i, r := range rd().top(topSupport) {
129 if i > 0 {
130 b.WriteString(",")
131 }
132 b.WriteString(`{"address":` + text.Str(r.Key) + `,"amount":` + text.Itoa64(r.Value) + `}`)
133 }
134 b.WriteString(`]}`)
135 return b.String()
136}