reads.gno
5.38 Kb · 186 lines
1package core
2
3import (
4 "chain"
5 "strings"
6
7 "gno.land/p/nt/ufmt/v0"
8
9 "gno.land/p/g19dzk54hhsdc3gllpksuj6gu4a3e6fl8cr6rn4w/sinopia/safe/v1"
10 "gno.land/p/g19dzk54hhsdc3gllpksuj6gu4a3e6fl8cr6rn4w/sinopia/types/v1"
11)
12
13// Every function in this file is read-only (I-12: no exported non-crossing
14// mutator). Lists are paginated with limit <= MaxPageSize (RA L-4).
15
16// SelfAddress is core's package address, for the deploy-time cross-check
17// against scripts/pkgaddr.py (RA H-5).
18func SelfAddress() address { return chain.PackageAddress(selfPath) }
19
20func CollectionCount() int64 { return collCount }
21
22// MintedTotal counts every token ever minted, burned ones included (OA B4).
23func MintedTotal(cid string) int64 { return mustCollection(cid).minted() }
24
25// MintedBy is the lifetime mint counter of addr in cid (OA B3, I-9).
26func MintedBy(cid string, addr address) int64 { return mintedBy(mustCollection(cid), addr) }
27
28// Info is the typed collection view for other realms.
29func Info(cid string) types.CollectionInfo {
30 c := mustCollection(cid)
31 info := types.CollectionInfo{
32 ID: c.id,
33 Name: c.name,
34 Symbol: c.symbol,
35 Description: c.description,
36 Creator: c.creator,
37 Minter: c.minter,
38 EngineID: c.engineID,
39 Params: c.params,
40 State: stateAt(c, height()),
41 MaxSupply: c.maxSupply,
42 Minted: c.minted(),
43 Reserved: c.reserved,
44 StartHeight: c.startHeight,
45 EndHeight: c.endHeight,
46 RoyaltyBps: c.royaltyBps,
47 }
48 if c.prov != nil {
49 info.RevealDeadline = revealDeadline(c)
50 info.Badge = c.prov.badge
51 }
52 return info
53}
54
55// PrimaryPayees returns a copy of the frozen primary-sale split.
56func PrimaryPayees(cid string) []types.Payee {
57 return append([]types.Payee{}, mustCollection(cid).primaryPayees...)
58}
59
60// FeeConfig is the typed fee view minters and markets settle with.
61func FeeConfig() types.Fees { return fees }
62
63func Beacon() address { return beacon }
64
65func Admin() address { return admin }
66
67func IsMinter(path string) bool {
68 v := minters.Get(path)
69 return v != nil && !v.(*minterRecord).deprecated
70}
71
72// Collection is the collection record as JSON.
73func Collection(cid string) string {
74 w := &safe.JSONWriter{}
75 writeCollection(w, mustCollection(cid))
76 return w.String()
77}
78
79func Collections(offset, limit int64) string {
80 w := &safe.JSONWriter{}
81 w.BeginArray()
82 collections.IterateByOffset(int(offset), int(clampLimit(limit)), func(_ string, v any) bool {
83 writeCollection(w, v.(*collection))
84 return false
85 })
86 w.EndArray()
87 return w.String()
88}
89
90func CollectionsByCreator(creator address, offset, limit int64) string {
91 w := &safe.JSONWriter{}
92 w.BeginArray()
93 prefix := creator.String() + ":"
94 skipped, written, want := int64(0), int64(0), clampLimit(limit)
95 byCreator.Iterate(prefix, prefix+"\xff", func(_ string, v any) bool {
96 if skipped < offset {
97 skipped++
98 return false
99 }
100 writeCollection(w, mustCollection(v.(string)))
101 written++
102 return written >= want
103 })
104 w.EndArray()
105 return w.String()
106}
107
108// Fees is the fee configuration and its hard caps as JSON.
109func Fees() string {
110 w := &safe.JSONWriter{}
111 w.BeginObject()
112 w.IntField("createFee", fees.CreateFee)
113 w.IntField("primaryBps", fees.PrimaryBps)
114 w.IntField("secondaryBps", fees.SecondaryBps)
115 w.StrField("treasury", fees.Treasury.String())
116 w.IntField("createFeeCap", CreateFeeCap)
117 w.IntField("protocolFeeCapBps", ProtocolFeeCapBps)
118 w.IntField("royaltyCapBps", RoyaltyCapBps)
119 w.EndObject()
120 return w.String()
121}
122
123// PendingOps is the timelock queue as JSON.
124func PendingOps() string {
125 w := &safe.JSONWriter{}
126 w.BeginArray()
127 ops.Iterate("", "", func(_ string, v any) bool {
128 p := v.(*pendingOp)
129 w.BeginObject()
130 w.StrField("id", itoa(p.id))
131 w.StrField("op", p.op)
132 w.StrField("arg", p.arg)
133 w.IntField("proposed", p.proposed)
134 w.IntField("earliest", earliestExecution(p))
135 w.EndObject()
136 return false
137 })
138 w.EndArray()
139 return w.String()
140}
141
142func writeCollection(w *safe.JSONWriter, c *collection) {
143 h := height()
144 w.BeginObject()
145 w.StrField("cid", c.id)
146 w.StrField("name", c.name)
147 w.StrField("symbol", c.symbol)
148 w.StrField("description", c.description)
149 w.StrField("creator", c.creator.String())
150 w.StrField("engine", c.engineID)
151 w.StrField("params", c.params)
152 w.StrField("minter", c.minter)
153 w.StrField("state", stateAt(c, h).String())
154 w.IntField("maxSupply", c.maxSupply)
155 w.IntField("minted", c.minted())
156 w.IntField("reserved", c.reserved)
157 w.IntField("royaltyBps", c.royaltyBps)
158 w.StrField("royaltyAddress", royaltyAddress(c.id).String())
159 w.StrField("primaryPayees", safe.FormatPayees(c.primaryPayees))
160 w.StrField("royaltyPayees", safe.FormatPayees(c.royaltyPayees))
161 w.IntField("startHeight", c.startHeight)
162 w.IntField("endHeight", c.endHeight)
163 w.IntField("createdHeight", c.createdHeight)
164 w.StrField("token", c.token.ID())
165 if c.prov != nil {
166 w.IntField("revealDeadline", revealDeadline(c))
167 w.BoolField("useBeacon", c.useBeacon)
168 w.StrField("badge", c.prov.badge)
169 }
170 w.EndObject()
171}
172
173func clampLimit(limit int64) int64 {
174 if limit <= 0 || limit > MaxPageSize {
175 return MaxPageSize
176 }
177 return limit
178}
179
180// Render stays minimal in the immutable realm; the browsable gallery is the
181// private, re-deployable gallery realm (design §2.5.7).
182func Render(path string) string {
183 gallery := strings.TrimPrefix(strings.TrimSuffix(selfPath, "/core")+"/gallery", "gno.land")
184 return ufmt.Sprintf("# Collections ledger\n\n%d collections, %d engines. Browse them in the [gallery](%s).\n",
185 collCount, engineCount, gallery)
186}