Search Apps Documentation Source Content File Folder Download Copy Actions Download

render.gno

5.42 Kb · 208 lines
  1package acr
  2
  3import (
  4	"net/url"
  5	"strconv"
  6
  7	"gno.land/p/jeronimoalbi/pager"
  8	"gno.land/p/nt/ufmt"
  9	"gno.land/r/akkadia/admin"
 10)
 11
 12const pageSize = 20
 13
 14// Render handles RESTful routing and returns Markdown responses
 15func Render(iUrl string) string {
 16	u, err := url.Parse(iUrl)
 17	if err != nil {
 18		return renderError("Invalid URL")
 19	}
 20
 21	query := u.Query()
 22
 23	switch u.Path {
 24	case "":
 25		return renderHome()
 26	case "top/balance":
 27		return renderTopByBalance(iUrl)
 28	case "top/minted":
 29		return renderTopByMinted(iUrl)
 30	case "account":
 31		addr := query.Get("address")
 32		if addr == "" {
 33			return renderError("Address required")
 34		}
 35		return renderAccount(addr)
 36	default:
 37		return renderError("Page not found")
 38	}
 39}
 40
 41// renderHome renders the home page with stats, description, and links
 42func renderHome() string {
 43	output := ufmt.Sprintf("# %s (%s)\n\n", token.GetName(), token.GetSymbol())
 44
 45	output += `## Introduction
 46
 47**Akkadia Community Rune (ACR)** is the utility token of the Akkadia ecosystem.
 48Users earn ACR through in-game activities and community participation.
 49
 50`
 51	output += "## Token Info\n\n"
 52	output += ufmt.Sprintf("* **Decimals**: %d\n", token.GetDecimals())
 53	output += ufmt.Sprintf("* **Total Supply**: %s\n", formatAmount(token.TotalSupply()))
 54	output += ufmt.Sprintf("* **Known Accounts**: %d\n", token.KnownAccounts())
 55
 56	output += `
 57## Quick Links
 58
 59* [Top Holders by Balance](/r/akkadia/acr:top/balance)
 60* [Top Holders by Minted](/r/akkadia/acr:top/minted)
 61
 62## Account Lookup
 63
 64<gno-form path="account">
 65  <gno-input name="address" placeholder="Enter wallet address (g1...)" />
 66</gno-form>
 67`
 68	return output
 69}
 70
 71// renderTopByBalance renders paginated list of top holders by balance
 72func renderTopByBalance(iUrl string) string {
 73	output := "# Top Holders by Balance\n\n"
 74	output += "[← Home](/r/akkadia/acr:)\n\n"
 75
 76	totalAccounts := token.KnownAccounts()
 77	if totalAccounts == 0 {
 78		output += "*No accounts yet.*\n"
 79		return output
 80	}
 81
 82	pages, err := pager.New(iUrl, totalAccounts, pager.WithPageSize(pageSize))
 83	if err != nil {
 84		return renderError("Invalid page")
 85	}
 86
 87	// Convert pager offset to 1-indexed page for ListTopUsersByBalance
 88	page := (pages.Offset() / pages.PageSize()) + 1
 89	count := pages.PageSize()
 90
 91	users := ListTopUsersByBalance(page, count)
 92
 93	if len(users) == 0 {
 94		output += "*No data available.*\n"
 95		return output
 96	}
 97
 98	output += "| Rank | Address | Balance |\n"
 99	output += "|------|---------|--------|\n"
100
101	startRank := pages.Offset() + 1
102	for i, u := range users {
103		addr := u["user"]
104		balance, _ := strconv.ParseInt(u["balance"], 10, 64)
105		addrLink := ufmt.Sprintf("%s [[View on Explorer](%s/m/explorer/player?address=%s)]", addr, admin.GetExplorerURL(), addr)
106		output += ufmt.Sprintf("| %d | %s | %s |\n", startRank+i, addrLink, formatAmount(balance))
107	}
108
109	if pages.HasPages() {
110		output += "\n" + pager.Picker(pages)
111	}
112
113	return output
114}
115
116// renderTopByMinted renders paginated list of top holders by minted amount
117func renderTopByMinted(iUrl string) string {
118	output := "# Top Holders by Minted Amount\n\n"
119	output += "[← Home](/r/akkadia/acr:)\n\n"
120
121	totalAccounts := token.KnownAccounts()
122	if totalAccounts == 0 {
123		output += "*No accounts yet.*\n"
124		return output
125	}
126
127	pages, err := pager.New(iUrl, totalAccounts, pager.WithPageSize(pageSize))
128	if err != nil {
129		return renderError("Invalid page")
130	}
131
132	// Convert pager offset to 1-indexed page for ListTopUsersByMinting
133	page := (pages.Offset() / pages.PageSize()) + 1
134	count := pages.PageSize()
135
136	users := ListTopUsersByMinting(page, count)
137
138	if len(users) == 0 {
139		output += "*No data available.*\n"
140		return output
141	}
142
143	output += "| Rank | Address | Total Minted |\n"
144	output += "|------|---------|-------------|\n"
145
146	startRank := pages.Offset() + 1
147	for i, u := range users {
148		addr := u["user"]
149		minted, _ := strconv.ParseInt(u["minted"], 10, 64)
150		addrLink := ufmt.Sprintf("%s [[View on Explorer](%s/m/explorer/player?address=%s)]", addr, admin.GetExplorerURL(), addr)
151		output += ufmt.Sprintf("| %d | %s | %s |\n", startRank+i, addrLink, formatAmount(minted))
152	}
153
154	if pages.HasPages() {
155		output += "\n" + pager.Picker(pages)
156	}
157
158	return output
159}
160
161// renderAccount renders a single account's ACR details
162func renderAccount(addrStr string) string {
163	addr := address(addrStr)
164	if !addr.IsValid() {
165		return renderError("Invalid address")
166	}
167
168	balance := BalanceOf(addr)
169	minted := MintedOf(addr)
170
171	output := "# Account Details\n\n"
172	output += "[← Home](/r/akkadia/acr:)\n\n"
173
174	output += ufmt.Sprintf("* **Address**: %s [[View on Explorer](%s/m/explorer/player?address=%s)]\n", addrStr, admin.GetExplorerURL(), addrStr)
175	output += ufmt.Sprintf("* **Balance**: %s %s\n", formatAmount(balance), token.GetSymbol())
176	output += ufmt.Sprintf("* **Total Minted**: %s %s\n", formatAmount(minted), token.GetSymbol())
177
178	return output
179}
180
181// renderError renders an error page
182func renderError(message string) string {
183	output := "# Error\n\n"
184	output += ufmt.Sprintf("> %s\n\n", message)
185	output += "[← Back to Home](/r/akkadia/acr:)\n"
186	return output
187}
188
189// formatAmount formats token amount with proper decimal places
190func formatAmount(amount int64) string {
191	decimals := token.GetDecimals()
192	if decimals == 0 {
193		return ufmt.Sprintf("%d", amount)
194	}
195
196	// Calculate divisor (10^decimals)
197	divisor := int64(1)
198	for i := 0; i < decimals; i++ {
199		divisor *= 10
200	}
201
202	intPart := amount / divisor
203	fracPart := amount % divisor
204
205	// Format with proper decimal places
206	format := ufmt.Sprintf("%%d.%%0%dd", decimals)
207	return ufmt.Sprintf(format, intPart, fracPart)
208}