render.gno
3.37 Kb · 114 lines
1package memba_nft_market_v3_1
2
3// Render — public read-only views.
4//
5// Routes:
6// "" — home: active listings count + volume
7// "stats" — platform fee, totals
8// "sales" — recent sales (up to 20)
9// * — 404
10
11import (
12 "strings"
13
14 "gno.land/p/nt/ufmt/v0"
15)
16
17func Render(path string) string {
18 switch path {
19 case "":
20 return renderHome()
21 case "stats":
22 return renderStats()
23 case "sales":
24 return renderSales()
25 default:
26 return "# 404\nNot found: " + path
27 }
28}
29
30func renderHome() string {
31 var sb strings.Builder
32 sb.WriteString("# NFT Marketplace\n\n")
33 sb.WriteString(ufmt.Sprintf("**Active Listings:** %d\n", listings.Size()))
34 volGnot := ufmt.Sprintf("%d.%06d", totalVolume/1_000_000, totalVolume%1_000_000)
35 sb.WriteString(ufmt.Sprintf("**Total Volume:** %s GNOT\n", volGnot))
36
37 if len(listingOrder) == 0 {
38 sb.WriteString("\n*No active listings.*\n")
39 return sb.String()
40 }
41
42 const homePageCap = 50
43
44 sb.WriteString("\n| # | Collection | Token | Price | Seller |\n")
45 sb.WriteString("|---|-----------|-------|-------|--------|\n")
46 shown := 0
47 for i, key := range listingOrder {
48 if shown >= homePageCap {
49 break
50 }
51 val, exists := listings.Get(key)
52 if !exists {
53 continue
54 }
55 l := val.(*Listing)
56 priceGnot := ufmt.Sprintf("%d.%06d", l.Price/1_000_000, l.Price%1_000_000)
57 sb.WriteString(ufmt.Sprintf("| %d | %s | %s | %s GNOT | %s |\n",
58 i+1, truncPath(l.CollectionID), l.TokenID, priceGnot, truncAddr(l.Seller)))
59 shown++
60 }
61 if len(listingOrder) > homePageCap {
62 sb.WriteString(ufmt.Sprintf("\n*… showing first %d of %d listings.*\n", homePageCap, len(listingOrder)))
63 }
64 return sb.String()
65}
66
67// feePctString renders FeeBPS as a percent with two decimals (e.g. 200 bps -> "2.00").
68// gno's ufmt parses width digits but drops the zero-pad flag, so "%02d" does NOT
69// zero-pad — pad the fractional bps explicitly.
70func feePctString() string {
71 whole := FeeBPS / 100
72 frac := FeeBPS % 100
73 if frac < 10 {
74 return ufmt.Sprintf("%d.0%d", whole, frac)
75 }
76 return ufmt.Sprintf("%d.%d", whole, frac)
77}
78
79func renderStats() string {
80 var sb strings.Builder
81 sb.WriteString("# Marketplace Stats\n\n")
82 sb.WriteString(ufmt.Sprintf("**Active Listings:** %d\n", listings.Size()))
83 sb.WriteString(ufmt.Sprintf("**Total Sales:** %d\n", salesLog.Size()))
84 volGnot := ufmt.Sprintf("%d.%06d", totalVolume/1_000_000, totalVolume%1_000_000)
85 sb.WriteString(ufmt.Sprintf("**Total Volume:** %s GNOT\n", volGnot))
86 sb.WriteString(ufmt.Sprintf("**Active Offers:** %d\n", offers.Size()))
87 sb.WriteString(ufmt.Sprintf("**Platform Fee:** %s%%\n", feePctString()))
88 sb.WriteString(ufmt.Sprintf("**Max Royalty:** %d%%\n", MaxRoyaltyBPS/100))
89 return sb.String()
90}
91
92func renderSales() string {
93 var sb strings.Builder
94 sb.WriteString("# Recent Sales\n\n")
95 if salesLog.Size() == 0 {
96 sb.WriteString("*No sales yet.*\n")
97 return sb.String()
98 }
99
100 sb.WriteString("| Sale | Collection | Token | Price | Seller | Buyer |\n")
101 sb.WriteString("|------|-----------|-------|-------|--------|-------|\n")
102
103 count := 0
104 salesLog.ReverseIterate("", "", func(key string, val interface{}) bool {
105 s := val.(*Sale)
106 priceGnot := ufmt.Sprintf("%d.%06d", s.Price/1_000_000, s.Price%1_000_000)
107 sb.WriteString(ufmt.Sprintf("| %s | %s | %s | %s GNOT | %s | %s |\n",
108 key, truncPath(s.CollectionID), s.TokenID, priceGnot,
109 truncAddr(s.Seller), truncAddr(s.Buyer)))
110 count++
111 return count >= 20
112 })
113 return sb.String()
114}