package acr import ( "net/url" "strconv" "gno.land/p/jeronimoalbi/pager" "gno.land/p/nt/ufmt" "gno.land/r/akkadia/admin" ) const pageSize = 20 // Render handles RESTful routing and returns Markdown responses func Render(iUrl string) string { u, err := url.Parse(iUrl) if err != nil { return renderError("Invalid URL") } query := u.Query() switch u.Path { case "": return renderHome() case "top/balance": return renderTopByBalance(iUrl) case "top/minted": return renderTopByMinted(iUrl) case "account": addr := query.Get("address") if addr == "" { return renderError("Address required") } return renderAccount(addr) default: return renderError("Page not found") } } // renderHome renders the home page with stats, description, and links func renderHome() string { output := ufmt.Sprintf("# %s (%s)\n\n", token.GetName(), token.GetSymbol()) output += `## Introduction **Akkadia Community Rune (ACR)** is the utility token of the Akkadia ecosystem. Users earn ACR through in-game activities and community participation. ` output += "## Token Info\n\n" output += ufmt.Sprintf("* **Decimals**: %d\n", token.GetDecimals()) output += ufmt.Sprintf("* **Total Supply**: %s\n", formatAmount(token.TotalSupply())) output += ufmt.Sprintf("* **Known Accounts**: %d\n", token.KnownAccounts()) output += ` ## Quick Links * [Top Holders by Balance](/r/akkadia/acr:top/balance) * [Top Holders by Minted](/r/akkadia/acr:top/minted) ## Account Lookup ` return output } // renderTopByBalance renders paginated list of top holders by balance func renderTopByBalance(iUrl string) string { output := "# Top Holders by Balance\n\n" output += "[← Home](/r/akkadia/acr:)\n\n" totalAccounts := token.KnownAccounts() if totalAccounts == 0 { output += "*No accounts yet.*\n" return output } pages, err := pager.New(iUrl, totalAccounts, pager.WithPageSize(pageSize)) if err != nil { return renderError("Invalid page") } // Convert pager offset to 1-indexed page for ListTopUsersByBalance page := (pages.Offset() / pages.PageSize()) + 1 count := pages.PageSize() users := ListTopUsersByBalance(page, count) if len(users) == 0 { output += "*No data available.*\n" return output } output += "| Rank | Address | Balance |\n" output += "|------|---------|--------|\n" startRank := pages.Offset() + 1 for i, u := range users { addr := u["user"] balance, _ := strconv.ParseInt(u["balance"], 10, 64) addrLink := ufmt.Sprintf("%s [[View on Explorer](%s/m/explorer/player?address=%s)]", addr, admin.GetExplorerURL(), addr) output += ufmt.Sprintf("| %d | %s | %s |\n", startRank+i, addrLink, formatAmount(balance)) } if pages.HasPages() { output += "\n" + pager.Picker(pages) } return output } // renderTopByMinted renders paginated list of top holders by minted amount func renderTopByMinted(iUrl string) string { output := "# Top Holders by Minted Amount\n\n" output += "[← Home](/r/akkadia/acr:)\n\n" totalAccounts := token.KnownAccounts() if totalAccounts == 0 { output += "*No accounts yet.*\n" return output } pages, err := pager.New(iUrl, totalAccounts, pager.WithPageSize(pageSize)) if err != nil { return renderError("Invalid page") } // Convert pager offset to 1-indexed page for ListTopUsersByMinting page := (pages.Offset() / pages.PageSize()) + 1 count := pages.PageSize() users := ListTopUsersByMinting(page, count) if len(users) == 0 { output += "*No data available.*\n" return output } output += "| Rank | Address | Total Minted |\n" output += "|------|---------|-------------|\n" startRank := pages.Offset() + 1 for i, u := range users { addr := u["user"] minted, _ := strconv.ParseInt(u["minted"], 10, 64) addrLink := ufmt.Sprintf("%s [[View on Explorer](%s/m/explorer/player?address=%s)]", addr, admin.GetExplorerURL(), addr) output += ufmt.Sprintf("| %d | %s | %s |\n", startRank+i, addrLink, formatAmount(minted)) } if pages.HasPages() { output += "\n" + pager.Picker(pages) } return output } // renderAccount renders a single account's ACR details func renderAccount(addrStr string) string { addr := address(addrStr) if !addr.IsValid() { return renderError("Invalid address") } balance := BalanceOf(addr) minted := MintedOf(addr) output := "# Account Details\n\n" output += "[← Home](/r/akkadia/acr:)\n\n" output += ufmt.Sprintf("* **Address**: %s [[View on Explorer](%s/m/explorer/player?address=%s)]\n", addrStr, admin.GetExplorerURL(), addrStr) output += ufmt.Sprintf("* **Balance**: %s %s\n", formatAmount(balance), token.GetSymbol()) output += ufmt.Sprintf("* **Total Minted**: %s %s\n", formatAmount(minted), token.GetSymbol()) return output } // renderError renders an error page func renderError(message string) string { output := "# Error\n\n" output += ufmt.Sprintf("> %s\n\n", message) output += "[← Back to Home](/r/akkadia/acr:)\n" return output } // formatAmount formats token amount with proper decimal places func formatAmount(amount int64) string { decimals := token.GetDecimals() if decimals == 0 { return ufmt.Sprintf("%d", amount) } // Calculate divisor (10^decimals) divisor := int64(1) for i := 0; i < decimals; i++ { divisor *= 10 } intPart := amount / divisor fracPart := amount % divisor // Format with proper decimal places format := ufmt.Sprintf("%%d.%%0%dd", decimals) return ufmt.Sprintf(format, intPart, fracPart) }