Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

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" }