read.gno
2.65 Kb · 89 lines
1package nsmarket
2
3import (
4 "strings"
5
6 "gno.land/p/nt/ufmt/v0"
7)
8
9// Reads for the site. Rows are ";"-separated records of
10// "label*domain,price,seller,listed,live" where `live` is false when the
11// listing has gone stale under it — the seller moved the name, let it
12// lapse, or revoked permission.
13//
14// Stale listings are REPORTED, not hidden and not silently deleted.
15// Hiding them makes a seller's page lie about what they have up; and
16// deleting them would mean a read function writing to storage, which is
17// how a query starts costing gas. Prune is the write that clears them.
18
19func row(tid string, l *Listing) string {
20 live := staleReason(marketAddr, tid, l) == ""
21 return ufmt.Sprintf("%s,%d,%s,%d,%t", tid, l.price, l.seller.String(), l.listed, live)
22}
23
24// GetListing returns one row, or "" when nothing is listed.
25func GetListing(tid string) string {
26 l := get(tid)
27 if l == nil {
28 return ""
29 }
30 return row(tid, l)
31}
32
33// ListForSale pages through everything on offer, cheapest first within a
34// page. `after` is the last token id of the previous page.
35func ListForSale(after string, limit int) (rows, next string) {
36 if limit <= 0 || limit > maxPage {
37 limit = maxPage
38 }
39 var out []string
40 var last string
41 listings.Iterate(after, "", func(key string, v any) bool {
42 if key == after {
43 return false // the cursor is exclusive
44 }
45 out = append(out, row(key, v.(*Listing)))
46 last = key
47 return len(out) >= limit
48 })
49 if len(out) < limit {
50 last = "" // the end; no cursor to hand back
51 }
52 return strings.Join(out, ";"), last
53}
54
55// ListingsBy is everything one wallet has up for sale. Walks the whole
56// tree because listings are keyed by token id, not by seller: a second
57// index would be a second thing to keep correct and a second thing the
58// seller pays storage for, to save a walk over a list that is small by
59// construction.
60func ListingsBy(seller address) string {
61 var out []string
62 listings.Iterate("", "", func(key string, v any) bool {
63 l := v.(*Listing)
64 if l.seller == seller {
65 out = append(out, row(key, l))
66 }
67 return false
68 })
69 return strings.Join(out, ";")
70}
71
72func CountListed() int64 { return int64(listings.Size()) }
73func CountSold() int64 { return sold }
74
75// Quote is what a buyer pays and what the seller receives, before
76// anybody signs anything. The fee is read live, so this is the same
77// arithmetic Buy will do rather than a copy of it that can drift.
78func Quote(tid string) (price, fee, toSeller int64) {
79 l := get(tid)
80 if l == nil {
81 return 0, 0, 0
82 }
83 f, s := FeeFor(l.price)
84 return l.price, f, s
85}
86
87// Version lets the site tell which shape it is talking to without
88// guessing from a function signature.
89func Version() string { return "v1" }