Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}