render.gno
3.35 Kb · 100 lines
1package nativereg
2
3import (
4 "strings"
5
6 "gno.land/p/moul/kit/ui/v0"
7 "gno.land/p/moul/md/v0"
8 "gno.land/p/nt/ufmt/v0"
9)
10
11// Render lists the registry. `?<denom>` shows one entry, `?<pkgpath>` shows
12// everything one realm issues.
13func Render(path string) string {
14 if path == "" {
15 return renderIndex()
16 }
17 if strings.HasPrefix(path, "/") {
18 return renderDenom(path)
19 }
20 return renderIssuer(path)
21}
22
23func renderIndex() string {
24 var sb strings.Builder
25 sb.WriteString(md.H1("nativereg: what a native denom means"))
26 sb.WriteString("\nA realm-issued coin is a string and a balance. The chain stores no name, " +
27 "no symbol and no decimals for it, so this realm does. An issuer registers its own " +
28 "denoms and nobody else's: the package path is embedded in the denom, and that is " +
29 "the whole authorization.\n\n")
30
31 t := ui.NewTable("denom", "symbol", "name", "decimals", "issuer")
32 for _, e := range List() {
33 t.Row(md.InlineCode(ui.ShortN(e.Denom, 22, 12)), ui.Cell(e.Symbol), ui.Cell(e.Name),
34 ufmt.Sprintf("%d", e.Decimals), md.Link(ui.Short(e.Issuer), "/"+strings.TrimPrefix(e.Issuer, "gno.land/")))
35 }
36 sb.WriteString(md.H2("Registered"))
37 sb.WriteString("\n" + t.OrEmpty("Nothing registered yet.") + "\n")
38
39 sb.WriteString(md.H2("Register your own"))
40 sb.WriteString("\nFrom inside the realm that issues the coin, never from a wallet:\n\n")
41 sb.WriteString(md.LanguageCodeBlock("go",
42 "import \"gno.land/r/moul/x/nativereg/v0\"\n\n"+
43 "func init(cur realm) {\n"+
44 "\tnativereg.Register(cross(cur), Denom, \"My Coin\", \"MINE\", 6,\n"+
45 "\t\t\"one line about what it is for\")\n"+
46 "}"))
47 sb.WriteString("\n" + md.Italic("Decimals is a display hint. The bank counts whole units and "+
48 "knows nothing about divisibility.") + "\n")
49 return sb.String()
50}
51
52func renderDenom(denom string) string {
53 e, ok := Get(denom)
54 if !ok {
55 return md.H1("Not registered") + "\n" + md.InlineCode(denom) +
56 " has said nothing about itself.\n\nIts issuer is " +
57 md.InlineCode(safeIssuer(denom)) + ", and only that realm can change it.\n"
58 }
59
60 t := ui.NewTable("", "")
61 t.Row("denom", md.InlineCode(e.Denom))
62 t.Row("issuer", md.InlineCode(e.Issuer))
63 t.Row("name", ui.Cell(e.Name))
64 t.Row("symbol", ui.Cell(e.Symbol))
65 t.Row("decimals", ufmt.Sprintf("%d (display hint)", e.Decimals))
66 t.Row("registered at block", ufmt.Sprintf("%d", e.Height))
67 t.Row("revisions", ufmt.Sprintf("%d", e.Revisions))
68
69 s := md.H1(ui.Inline(e.Symbol)) + "\n"
70 if e.Doc != "" {
71 s += ui.Inline(e.Doc) + "\n\n"
72 }
73 s += t.String() + "\n"
74 s += md.Blockquote("The issuer can rewrite every row but the first two, and can remove "+
75 "this coin from any balance at any time. That is what a realm-issued coin is.") + "\n"
76 return s
77}
78
79func renderIssuer(pkgPath string) string {
80 entries := ByIssuer(pkgPath)
81 s := md.H1("Issued by "+ui.Inline(pkgPath)) + "\n"
82 t := ui.NewTable("denom", "symbol", "name")
83 for _, e := range entries {
84 t.Row(md.InlineCode(ui.ShortN(e.Denom, 22, 12)), ui.Cell(e.Symbol), ui.Cell(e.Name))
85 }
86 return s + t.OrEmpty("This realm has registered nothing here.") + "\n"
87}
88
89// safeIssuer is IssuerOf for a Render, which must never abort on a path a reader
90// typed into the URL bar.
91func safeIssuer(denom string) string {
92 if !strings.HasPrefix(denom, "/") {
93 return "unknown (not a realm denom)"
94 }
95 i := strings.LastIndex(denom, ":")
96 if i < 1 {
97 return "unknown (not a realm denom)"
98 }
99 return denom[1:i]
100}