getters.gno
2.97 Kb · 93 lines
1package memba_nft_market_v3_1
2
3// v3.1 — structured read getters.
4//
5// These let the frontend read listings and offers STRUCTURALLY (full addresses,
6// deterministic format) instead of scraping the markdown Render(""), which truncated
7// addresses and capped at 50 rows. Output is one record per line, pipe-delimited, so
8// the client parses by split — no markdown regex, no truncation.
9
10import (
11 "strings"
12
13 "chain/runtime/unsafe"
14)
15
16// MaxPageSize bounds a single page so a getter can never iterate unboundedly (a
17// gas/DoS surface). The frontend pages with offset/limit.
18const MaxPageSize = 100
19
20// MarketAddress returns this engine realm's own address — the operator a seller
21// approves on the collection (SetApprovalForAll) and the address the collection
22// registers via RegisterMarket. Exposed so the frontend and the deploy ceremony can
23// read the deterministic address directly instead of hardcoding it.
24func MarketAddress() string { return unsafe.CurrentRealm().Address().String() }
25
26// ListingsCount returns the number of active listings (for pagination).
27func ListingsCount() int { return len(listingOrder) }
28
29// GetListingsPage returns a page of active listings, one per line:
30//
31// collectionID|tokenID|seller|price|createdBlk
32//
33// Addresses are FULL (never truncated). offset/limit window the insertion-ordered
34// listing set; limit is clamped to [1, MaxPageSize].
35func GetListingsPage(offset, limit int) string {
36 if offset < 0 {
37 offset = 0
38 }
39 if limit <= 0 || limit > MaxPageSize {
40 limit = MaxPageSize
41 }
42 n := len(listingOrder)
43 end := offset + limit
44 if end > n {
45 end = n
46 }
47
48 var sb strings.Builder
49 for i := offset; i < end; i++ {
50 v, ok := listings.Get(listingOrder[i])
51 if !ok {
52 continue
53 }
54 l := v.(*Listing)
55 sb.WriteString(l.CollectionID)
56 sb.WriteString("|")
57 sb.WriteString(l.TokenID)
58 sb.WriteString("|")
59 sb.WriteString(l.Seller.String())
60 sb.WriteString("|")
61 sb.WriteString(itoa(l.Price))
62 sb.WriteString("|")
63 sb.WriteString(itoa(l.CreatedBlk))
64 sb.WriteString("\n")
65 }
66 return sb.String()
67}
68
69// GetOffersForToken returns the active offers on one (collection, token), one per line:
70//
71// buyer|amount|createdBlk
72//
73// It uses a PREFIX-RANGE scan over the offer tree — offerKey is "collection:token:buyer",
74// so the range ["collection:token:", "collection:token;") reads only this token's
75// offers, never a full-tree scan. This is the read that finally lets the frontend wire
76// accept-offer and show a token's offers (no offers getter existed before v3.1).
77func GetOffersForToken(collectionID, tokenID string) string {
78 start := collectionID + ":" + tokenID + ":"
79 end := collectionID + ":" + tokenID + ";" // ';' (0x3b) is the byte after ':' (0x3a)
80
81 var sb strings.Builder
82 offers.Iterate(start, end, func(_ string, v interface{}) bool {
83 o := v.(*Offer)
84 sb.WriteString(o.Buyer.String())
85 sb.WriteString("|")
86 sb.WriteString(itoa(o.Amount))
87 sb.WriteString("|")
88 sb.WriteString(itoa(o.CreatedBlk))
89 sb.WriteString("\n")
90 return false
91 })
92 return sb.String()
93}