Kind Realm (renderable)
Name gnft
Namespace gnoswap
Exported functions 17
Module gno.land/r/gnoswap/gnft
gno 0.9 gnft.gno gno
⧉
1 package gnft 2 3 import ( 4 "chain" 5 "errors" 6 7 "gno.land/p/nt/grc721/metadata/v0" 8 Approve (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, approved string, tid string) interface {Error func() string}
BalanceOf (owner string) (int64, interface {Error func() string})
Burn (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, tid string)
Exists (tid string) bool
GetApproved (tid string) (string, interface {Error func() string})
IsApprovedForAll (owner string, operator string) bool
Mint (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, to string, tid string) string
MustOwnerOf (tid string) string
Name () string
OwnerOf (tid string) (string, interface {Error func() string})
Render (path string) string
SetApprovalForAll (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, operator string, approved bool) interface {Error func() string}
SetTokenURI (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, tid string, tURI string) (bool, interface {Error func() string})
Symbol () string
TokenURI (tid string) (string, interface {Error func() string})
TotalSupply () int64
TransferFrom (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, from string, to string, tid string) interface {Error func() string}
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.
"gno.land/p/nt/grc721/v0"
9 "gno.land/p/nt/seqid/v0"
10 "gno.land/p/nt/ufmt/v0"
11 "gno.land/r/gnoswap/access/v1"
12
13 prabc "gno.land/p/gnoswap/rbac/v1"
14 _ "gno.land/r/gnoswap/rbac/v1"
15 )
16
17 var (
18 token *grc721.Token
19 ledger *grc721.PrivateLedger
20 meta *metadata.Metadata
21 metaLedger *metadata.Ledger
22 )
23
24 func init(cur realm) {
25 token, ledger = grc721.NewToken( "GNOSWAP NFT" , "GNFT" , seqid.ID( 0 ), cur)
26 meta, metaLedger = metadata.NewMetadata(ledger)
27 }
28
29 // Name returns the NFT collection name.
30 //
31 // Returns:
32 // - name: collection name
33 func Name() string {
34 return token.GetName()
35 }
36
37 // Symbol returns the NFT collection symbol.
38 //
39 // Returns:
40 // - symbol: collection symbol
41 func Symbol() string {
42 return token.GetSymbol()
43 }
44
45 // TotalSupply returns the total number of NFTs minted.
46 //
47 // Returns:
48 // - supply: number of NFTs minted by the collection
49 func TotalSupply() int64 {
50 return token.TotalSupply()
51 }
52
53 // TokenURI returns the metadata URI for the specified token ID.
54 // Parameter-format values (x1,y1,x2,y2,color1,color2) are rendered as a
55 // base64-encoded SVG data URI; other non-empty stored URIs are returned unchanged.
56 //
57 // Parameters:
58 // - tid: token ID whose metadata URI is requested
59 //
60 // Returns:
61 // - uri: stored URI, or a generated SVG data URI for parameter-format metadata
62 // - error: metadata lookup error when tid has no retrievable metadata
63 func TokenURI(tid grc721.TokenID) ( string , error ) {
64 stored, err := meta.TokenURI(tid)
65 if err != nil {
66 return "" , err
67 }
68
69 params, err := parseImageParams(stored)
70 if err == nil {
71 return params.generateImageURI(tid), nil
72 }
73
74 return stored, nil
75 }
76
77 // BalanceOf returns the number of NFTs owned by the specified address.
78 //
79 // Parameters:
80 // - owner: address whose NFT balance is queried
81 //
82 // Returns:
83 // - balance: number of NFTs owned by owner
84 // - error: token-ledger balance lookup error; an invalid owner address
85 // panics before the lookup
86 func BalanceOf(owner address) ( int64 , error ) {
87 assertIsValidAddress(owner)
88 return token.BalanceOf(owner)
89 }
90
91 // OwnerOf returns the owner address for the specified token ID.
92 //
93 // Parameters:
94 // - tid: token ID whose owner is requested
95 //
96 // Returns:
97 // - owner: current owner address
98 // - error: token-ledger error when tid does not exist or cannot be read
99 func OwnerOf(tid grc721.TokenID) (address, error ) {
100 return token.OwnerOf(tid)
101 }
102
103 // MustOwnerOf returns the owner address for the specified token ID.
104 // It panics if the token ID is invalid.
105 //
106 // Parameters:
107 // - tid: token ID whose owner is requested
108 //
109 // Returns:
110 // - owner: current owner address; panics when tid is invalid or absent
111 func MustOwnerOf(tid grc721.TokenID) address {
112 ownerAddr, err := token.OwnerOf(tid)
113 checkErr(err)
114 return ownerAddr
115 }
116
117 // SetTokenURI sets the metadata URI for the specified token.
118 //
119 // Parameters:
120 // - cur: Current realm context; callers use cross(cur) when crossing into this realm.
121 // - tid: token ID whose metadata URI is replaced
122 // - tURI: non-empty metadata URI or parameter-format image description
123 //
124 // Returns:
125 // - updated: true after the URI is stored and re-read successfully
126 // - error: nil on success; validation and storage failures panic before a
127 // non-nil error can be returned
128 //
129 // Only callable by position contract.
130 func SetTokenURI(cur realm, tid grc721.TokenID, tURI string ) ( bool , error ) {
131 caller := cur.Previous().Address()
132 access.AssertIsPosition(caller)
133
134 assertIsNonEmptyTokenURI(tURI)
135 assertIsValidTokenURI(tid)
136
137 checkErr(setTokenURI( 0 , cur, tid, tURI))
138
139 return true , nil
140 }
141
142 // TransferFrom transfers a token from one address to another.
143 //
144 // Parameters:
145 // - cur: Current realm context; callers use cross(cur) when crossing into this realm.
146 // - from: current owner address
147 // - to: recipient address
148 // - tid: token ID to transfer
149 //
150 // Returns:
151 // - error: nil after a successful transfer; invalid addresses, authorization,
152 // ownership, or ledger failures panic through checkTransferErr
153 //
154 // Permission model:
155 // - Tokens held by the staker contract (i.e. currently staked) can only be
156 // moved by the staker itself; the underlying staked LP position is
157 // non-transferable.
158 // - Otherwise, ownership and approval are enforced by the GRC721 layer
159 // (owner / approved-for-token / approved-for-all).
160 func TransferFrom(cur realm, from, to address, tid grc721.TokenID) error {
161 assertFromIsValidAddress(from)
162 assertToIsValidAddress(to)
163 caller := cur.Previous().Address()
164 assertIsAllowedTransfer(caller, tid)
165
166 err := ledger.TransferFrom(caller, from, to, tid)
167 checkTransferErr(err, caller, from, to, tid)
168 return nil
169 }
170
171 // Approve grants permission to transfer a specific token ID to another address.
172 //
173 // Parameters:
174 // - cur: Current realm context; callers use cross(cur) when crossing into this realm.
175 // - approved: address to approve
176 // - tid: token ID to approve for transfer
177 //
178 // Returns:
179 // - error: nil after approval is stored; invalid addresses, ownership, or
180 // ledger failures panic through checkApproveErr
181 func Approve(cur realm, approved address, tid grc721.TokenID) error {
182 assertIsValidAddress(approved)
183
184 caller := cur.Previous().Address()
185 err := ledger.Approve(caller, approved, tid)
186 checkApproveErr(err, caller, approved, tid)
187 return nil
188 }
189
190 // SetApprovalForAll enables/disables operator approval for all tokens.
191 //
192 // Parameters:
193 // - cur: Current realm context; callers use cross(cur) when crossing into this realm.
194 // - operator: address to set approval for
195 // - approved: true to approve, false to revoke
196 //
197 // Returns:
198 // - error: nil after the operator approval is stored; ledger failures panic
199 // before a non-nil error can be returned
200 func SetApprovalForAll(cur realm, operator address, approved bool ) error {
201 assertIsValidAddress(operator)
202
203 checkErr(ledger.SetApprovalForAll(cur.Previous().Address(), operator, approved))
204 return nil
205 }
206
207 // GetApproved returns approved address for token ID.
208 //
209 // Parameters:
210 // - tid: token ID whose per-token approval is requested
211 //
212 // Returns:
213 // - approved: address approved for tid
214 // - error: token-ledger error if tid does not exist or approval cannot be read
215 func GetApproved(tid grc721.TokenID) (address, error ) {
216 return token.GetApproved(tid)
217 }
218
219 // IsApprovedForAll checks if operator can manage all owner's tokens.
220 //
221 // Parameters:
222 // - owner: token owner address
223 // - operator: operator address to check
224 //
225 // Returns:
226 // - approved: true when operator is approved for every token owned by owner
227 func IsApprovedForAll(owner, operator address) bool {
228 return token.IsApprovedForAll(owner, operator)
229 }
230
231 // Mint creates new NFT and transfers it to to.
232 //
233 // Parameters:
234 // - cur: Current realm context; callers use cross(cur) when crossing into this realm.
235 // - to: recipient address
236 // - tid: token ID to mint
237 //
238 // Returns:
239 // - tokenID: minted token ID
240 //
241 // Only callable by position contract.
242 func Mint(cur realm, to address, tid grc721.TokenID) grc721.TokenID {
243 caller := cur.Previous().Address()
244 access.AssertIsPosition(caller)
245
246 positionAddr := access.MustGetAddress(prabc.ROLE_POSITION.String())
247 checkErr(ledger.Mint(positionAddr, tid))
248
249 // Store only the gradient parameters instead of full base64 SVG to reduce storage costs.
250 // Parameters are converted to full SVG on read via TokenURI().
251 imageParams := genImageParamsString(generateRandInstance())
252 checkErr(setTokenURI( 0 , cur, tid, imageParams))
253
254 checkErr(ledger.TransferFrom(positionAddr, positionAddr, to, tid))
255
256 return tid
257 }
258
259 // Exists checks if token ID exists.
260 //
261 // Parameters:
262 // - tid: token ID to check
263 //
264 // Returns:
265 // - exists: true when the ledger can resolve an owner for tid; false otherwise
266 func Exists(tid grc721.TokenID) bool {
267 _, err := token.OwnerOf(tid)
268 return err == nil
269 }
270
271 // Burn removes a specific token ID.
272 //
273 // Parameters:
274 // - cur: Current realm context; callers use cross(cur) when crossing into this realm.
275 // - tid: token ID to burn
276 //
277 // Only callable by position.
278 func Burn(cur realm, tid grc721.TokenID) {
279 caller := cur.Previous().Address()
280 access.AssertIsPosition(caller)
281
282 checkErr(ledger.Burn(tid))
283 }
284
285 // Render returns the HTML representation of the NFT.
286 //
287 // Parameters:
288 // - path: render path; the empty path selects the collection home page
289 //
290 // Returns:
291 // - html: collection HTML for the home path, or "404\n" for unsupported paths
292 func Render(path string ) string {
293 if path == "" {
294 return token.RenderHome()
295 }
296 return "404\n"
297 }
298
299 // setTokenURI sets the metadata URI for a specific token ID.
300 func setTokenURI(_ int , rlm realm, tid grc721.TokenID, tURI string ) error {
301 if !rlm.IsCurrent() {
302 return errors.New(errSpoofedRealm)
303 }
304
305 previousRealm := rlm.Previous()
306 previousAddr := previousRealm.Address()
307
308 err := metaLedger.SetTokenURI(tid, tURI)
309 if err != nil {
310 return makeErrorWithDetails(err.Error(), ufmt.Sprintf( "token id (%s)" , tid))
311 }
312 tokenURI, err := TokenURI(tid)
313 if err != nil {
314 return makeErrorWithDetails(err.Error(), ufmt.Sprintf( "token id (%s)" , tid))
315 }
316
317 chain.Emit(
318 "SetTokenURI" ,
319 "prevAddr" , previousAddr.String(),
320 "prevRealm" , previousRealm.PkgPath(),
321 "tokenId" , string (tid),
322 "tokenURI" , tokenURI,
323 )
324
325 return nil
326 }
327