render.gno
3.63 Kb · 105 lines
1package moultest
2
3import (
4 "chain/runtime"
5 "strings"
6
7 "gno.land/p/moul/kit/ui/v0"
8 "gno.land/p/moul/md/v0"
9 "gno.land/p/nt/ufmt/v0"
10)
11
12// Render shows the coin, what is left under each cap, and the tip board.
13// `?<address>` adds that address's balance and claim state.
14func Render(path string) string {
15 var sb strings.Builder
16
17 sb.WriteString(md.H1("moultest: a native coin you can help yourself to"))
18 sb.WriteString("\nNot a GRC20. The chain's bank holds it, so it moves with a plain send, " +
19 "shows up beside GNOT on any account page, and can ride the `-send` envelope of a " +
20 "transaction. There is no ledger in this realm and no registry entry anywhere.\n\n")
21 sb.WriteString(md.LanguageCodeBlock("", Denom))
22 sb.WriteString("\n")
23
24 sb.WriteString(renderSupply())
25 sb.WriteString(renderAccount(path))
26 sb.WriteString(renderTips())
27 sb.WriteString(renderUsage())
28 return sb.String()
29}
30
31func renderSupply() string {
32 t := ui.NewTable("", "amount", "cap", "left")
33 t.Row("issued, ever", ufmt.Sprintf("%d", issued), ufmt.Sprintf("%d", MaxSupply),
34 ufmt.Sprintf("%d", MaxSupply-issued))
35 t.Row("circulating", ufmt.Sprintf("%d", Circulating()), "", "")
36 t.Row("burned", ufmt.Sprintf("%d", burned), "", "")
37 t.Row("accounts", ufmt.Sprintf("%d", accounts.Size()), "", "")
38
39 s := md.H2("Supply") + "\n" + t.String()
40 s += "\n" + ufmt.Sprintf(
41 "`%d` per claim, once every `%d` blocks, `%d` per address for life. "+
42 "Burning lowers what circulates and gives back no headroom, "+
43 "or claim-burn-claim would be an unlimited faucet.\n",
44 ClaimAmount, ClaimEvery, MaxPerAccount)
45 return s + "\n"
46}
47
48func renderAccount(path string) string {
49 who := address(path)
50 if path == "" || !who.IsValid() {
51 return ""
52 }
53
54 s := md.H2("Account "+ui.AddrText(who)) + "\n"
55 t := ui.NewTable("", "")
56 t.Row("address", ui.AddrFull(who))
57 t.Row("balance", ufmt.Sprintf("%d moultest", BalanceOf(who)))
58 t.Row("claimed for life", ufmt.Sprintf("%d of %d", ClaimedBy(who), MaxPerAccount))
59
60 next, ever := NextClaim(who)
61 switch {
62 case !ever:
63 t.Row("next claim", "now, this address has never claimed")
64 case runtime.ChainHeight() >= next:
65 t.Row("next claim", "now")
66 default:
67 t.Row("next claim", ufmt.Sprintf("block %d (%d to go)", next, next-runtime.ChainHeight()))
68 }
69 return s + t.String() + "\n"
70}
71
72func renderTips() string {
73 s := md.H2("Tips") + "\n"
74 if len(tips) == 0 {
75 return s + ui.Empty("Nobody has tipped anybody yet.") + "\n"
76 }
77 t := ui.NewTable("block", "from", "to", "amount", "note")
78 // Most recent first; the slice keeps them oldest first.
79 for i := len(tips) - 1; i >= 0; i-- {
80 e := tips[i]
81 t.Row(ufmt.Sprintf("%d", e.height), ui.Addr(e.from), ui.Addr(e.to),
82 ufmt.Sprintf("%d", e.amount), ui.Cell(e.note))
83 }
84 return s + t.String() + "\n"
85}
86
87func renderUsage() string {
88 s := md.H2("Use it") + "\n"
89 s += md.BulletItem(ui.Action("Claim "+ufmt.Sprintf("%d moultest", ClaimAmount), "Claim"))
90 s += "\n"
91 s += "Then it is an ordinary coin, and moving it needs nothing from this realm:\n\n"
92 s += md.LanguageCodeBlock("", ""+
93 "# help yourself\n"+
94 "gnokey maketx call -pkgpath "+Path+" -func Claim ...\n\n"+
95 "# send some to a friend: a bank message, no realm call at all\n"+
96 "gnokey maketx send -to <address> -send 2500"+Denom+" ...\n\n"+
97 "# tip somebody through this realm, note included. The coin rides the\n"+
98 "# envelope, which is the thing a GRC20 cannot do.\n"+
99 "gnokey maketx call -pkgpath "+Path+" -func Tip \\\n"+
100 " -args <address> -args \"nice work\" -send 1000"+Denom+" ...\n\n"+
101 "# destroy some of your own\n"+
102 "gnokey maketx call -pkgpath "+Path+" -func Burn -args 1000 ...")
103 s += "\n" + md.Italic("Worthless by construction. Do not price it.") + "\n"
104 return s
105}