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

render.gno

4.26 Kb · 165 lines
  1package vouch
  2
  3import (
  4	"strconv"
  5
  6	"gno.land/p/moul/kit/num/v0"
  7	"gno.land/p/moul/kit/ui/v0"
  8	"gno.land/p/moul/md/v0"
  9	"gno.land/p/moul/realmpath/v0"
 10	vo "gno.land/p/moul/x/social/vouch/v0"
 11)
 12
 13// Render routes two views: the realm's own index, and one address's page.
 14//
 15// An address carries no slash, so the per-address route is a path element and
 16// not a prefix strip.
 17func Render(path string) string {
 18	req := realmpath.Parse(path)
 19
 20	switch req.PathPart(0) {
 21	case "":
 22		return renderIndex()
 23	case "addr":
 24		return renderAddr(req.PathPart(1))
 25	default:
 26		return md.H1("Not found") + "No such view: " + ui.Inline(req.Path)
 27	}
 28}
 29
 30func renderIndex() string {
 31	out := md.H1("Vouch")
 32	out += "A web of trust other realms gate on. One address vouches for another, " +
 33		"in writing, optionally with GNOT locked behind it.\n\n"
 34
 35	t := ui.NewTable("vouches", "people vouched for", "bonded", "awaiting withdrawal")
 36	t.Row(
 37		strconv.Itoa(graph.Count()),
 38		strconv.Itoa(graph.People()),
 39		num.GNOTf(graph.TotalBonded()),
 40		num.GNOTf(graph.TotalOwed()),
 41	)
 42	out += t.String()
 43
 44	out += md.H2("Most vouched for")
 45	out += board()
 46
 47	out += md.H2("The gate")
 48	out += "One line in the realm that wants it, and it costs no transaction:\n\n"
 49	out += md.LanguageCodeBlock("go", `import "`+realmPath+`"
 50
 51if !vouch.IsTrusted(addr, 2) {
 52	panic("get two people to vouch for you first")
 53}`)
 54	out += md.Italic("A score counts distinct vouchers, so restating a vouch does not " +
 55		"raise it and revoking lowers it. It does not count distinct people: a pair " +
 56		"vouching for each other both reach one, which is why a real gate asks for " +
 57		"more.") + "\n\n"
 58
 59	out += md.H2("Take part")
 60	out += ui.Action("\U0001F91D Vouch", "Vouch", "target", "", "reason", "") +
 61		" · " + ui.Action("\U0001F4B0 Withdraw a refunded bond", "Withdraw") + "\n\n"
 62	out += md.Italic("Coins sent with Vouch are locked as a bond on that vouch and come " +
 63		"back when you revoke it. There is no slashing: deciding that a vouch was a lie " +
 64		"needs an arbiter, and choosing one is the whole design question.") + "\n"
 65
 66	return out
 67}
 68
 69func board() string {
 70	rows := graph.Leaderboard(BoardSize)
 71	if len(rows) == 0 {
 72		return ui.Empty("Nobody has been vouched for yet.")
 73	}
 74	t := ui.NewTable("", "address", "vouchers", "bonded")
 75	for i, r := range rows {
 76		t.Row(
 77			ui.Podium(i),
 78			md.Link(ui.AddrText(r.Addr), vo.AddrURL(realmPath, r.Addr)),
 79			strconv.Itoa(r.Score),
 80			num.GNOTf(r.Bonded),
 81		)
 82	}
 83	return t.String()
 84}
 85
 86func renderAddr(raw string) string {
 87	addr := address(raw)
 88	if !addr.IsValid() {
 89		return md.H1("Vouch") + "Not an address: " + ui.Inline(raw)
 90	}
 91
 92	out := md.H1("Vouch for " + ui.AddrText(addr))
 93	out += ui.AddrFull(addr) + "\n\n"
 94
 95	score := graph.ScoreOf(addr)
 96	t := ui.NewTable("vouchers", "bonded on them", "trusted at 2", "awaiting withdrawal")
 97	t.Row(
 98		strconv.Itoa(score),
 99		num.GNOTf(graph.BondedFor(addr)),
100		yesno(graph.IsTrusted(addr, 2)),
101		num.GNOTf(graph.Owed(addr)),
102	)
103	out += t.String()
104
105	out += md.H2("Vouched for by")
106	out += inbound(addr)
107
108	out += md.H2("Vouches for")
109	out += outbound(addr)
110
111	out += "\n" + ui.Action("\U0001F91D Vouch for this address", "Vouch",
112		"target", addr.String(), "reason", "") +
113		" · " + ui.Action("\U0000274C Revoke mine", "Revoke", "target", addr.String()) + "\n"
114	return out
115}
116
117func inbound(addr address) string {
118	from := graph.VouchedBy(addr)
119	if len(from) == 0 {
120		return ui.Empty("Nobody vouches for this address.")
121	}
122	t := ui.NewTable("voucher", "reason", "bond", "mutual", "since")
123	for _, f := range from {
124		v, ok := graph.Get(f, addr)
125		if !ok {
126			continue
127		}
128		t.Row(
129			md.Link(ui.AddrText(f), vo.AddrURL(realmPath, f)),
130			ui.Cell(v.Reason),
131			num.GNOTf(v.Bond),
132			yesno(graph.Mutual(f, addr)),
133			strconv.FormatInt(v.At, 10),
134		)
135	}
136	return t.String()
137}
138
139func outbound(addr address) string {
140	to := graph.VouchesOf(addr)
141	if len(to) == 0 {
142		return ui.Empty("This address vouches for nobody.")
143	}
144	t := ui.NewTable("for", "reason", "bond", "their vouchers")
145	for _, target := range to {
146		v, ok := graph.Get(addr, target)
147		if !ok {
148			continue
149		}
150		t.Row(
151			md.Link(ui.AddrText(target), vo.AddrURL(realmPath, target)),
152			ui.Cell(v.Reason),
153			num.GNOTf(v.Bond),
154			strconv.Itoa(graph.ScoreOf(target)),
155		)
156	}
157	return t.String()
158}
159
160func yesno(b bool) string {
161	if b {
162		return "yes"
163	}
164	return "no"
165}