Smart Contract

MetaverseMarket

A.256599e1b091be12.MetaverseMarket

Deployed

5h ago
Mar 02, 2026, 06:17:16 AM UTC

Dependents

0 imports
1// NFT Price - Will it be changable?
2// NFT MaxSupply - Will it be changable?
3// DELETE LISTED NFT?
4// CREATE A FIELD TO DISPLAY - NO SUPPLY - ON A LIST?
5
6//SPDX-License-Identifier : CC-BY-NC-4.0
7
8// testnet 0x635e88ae7f1d7c20
9import NonFungibleToken from 0x1d7e57aa55817448
10import MetadataViews from 0x1d7e57aa55817448
11import FungibleToken from 0xf233dcee88fe0abe
12
13// MetaverseMarket
14// NFT for MetaverseMarket
15//
16pub contract MetaverseMarket: NonFungibleToken {
17
18    // Events
19    //
20    pub event ContractInitialized()
21    pub event Withdraw(id: UInt64, from: Address?)
22    pub event Deposit(id: UInt64, to: Address?)
23    pub event Minted(id: UInt64, typeID: UInt64, metadata: {String:String})
24    pub event BatchMinted(ids: [UInt64], typeID: [UInt64], metadata: {String:String})
25    pub event NFTBurned(id: UInt64)
26    pub event NFTsBurned(ids: [UInt64])
27    pub event CategoryCreated(categoryName: String)
28    pub event SubCategoryCreated(subCategoryName: String)
29
30    // Named Paths
31    //
32    pub let CollectionStoragePath: StoragePath
33    pub let CollectionPublicPath: PublicPath
34    pub let AdminStoragePath: StoragePath
35
36    // totalSupply
37    // The total number of MetaverseMarkets that have been minted
38    //
39    pub var totalSupply: UInt64
40
41    // List with all categories and respective code
42    access(self) var categoriesList: {UInt64 :String}
43
44    // {CategoryName: [NFT To Sell ID]}
45    access(self) var categoriesNFTsToSell: {UInt64: [UInt64]}
46
47    //LISTINGS
48
49    // Dictionary with NFT List Data
50    access(self) var nftsToSell: {UInt64: OzoneListToSellMetadata}
51
52
53    pub struct OzoneListToSellMetadata {
54      //List ID that will came from the backend, all NFTs from same list will have same listId
55      pub let listId: UInt64
56      pub let name: String
57      pub let description: String
58      pub let categoryId: UInt64
59      pub let creator: Address
60      pub let fileName: String
61      pub let format: String
62      pub let fileIPFS: String
63      pub var price: UFix64
64      pub let maxSupply: UInt64
65      pub var minted: UInt64
66
67      pub fun addMinted(){
68        self.minted = self.minted + (1 as UInt64)
69      }
70
71      pub fun changePrice(newPrice: UFix64){
72        self.price = newPrice
73      }
74
75      init(_listId: UInt64, _name: String, _description: String, _categoryId: UInt64, _creator: Address, _fileName: String, _format: String, _fileIPFS: String, _price: UFix64, _maxSupply: UInt64){
76        self.listId = _listId
77        self.name = _name
78        self.description = _description
79        self.categoryId = _categoryId
80        self.creator = _creator
81        self.fileName = _fileName
82        self.format = _format
83        self.fileIPFS = _fileIPFS
84        self.price = _price
85        self.maxSupply = _maxSupply
86        self.minted = 0
87      }
88    }
89
90    // NFT
91    // MetaverseMarket as an NFT
92    //
93    pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
94        // The token's ID
95        //NFT CONTRACT GLOBAL ID -> Current TotalSupply
96        pub let id: UInt64
97
98        //Current List minted(List TotalSupply)
99        pub let uniqueListId: UInt64
100
101        //List ID that will came from the backend, all NFTs from same list will have same listId
102        pub let listId: UInt64
103
104        pub let name: String
105
106        pub let description: String
107
108        pub let categoryId: UInt64
109
110        pub let creator: Address
111
112        pub let fileName: String
113
114        pub let format: String
115
116        pub let fileIPFS: String
117
118
119
120        pub fun getViews(): [Type] {
121            return [
122                Type<MetadataViews.Display>(),
123                Type<MetadataViews.NFTCollectionData>(),
124                Type<MetadataViews.Royalties>(),
125                Type<MetadataViews.ExternalURL>(),
126                Type<MetadataViews.NFTCollectionDisplay>(),
127                Type<MetadataViews.Serial>()
128            ]
129        }
130
131        pub fun resolveView(_ view: Type): AnyStruct? {
132            switch view {
133                case Type<MetadataViews.Display>():
134                    return MetadataViews.Display(
135                        name: self.name,
136                        description: self.description,
137                        thumbnail: MetadataViews.IPFSFile(
138                            cid: self.fileIPFS,
139                            path: nil
140                        )
141                    )
142                case Type<MetadataViews.NFTCollectionData>():
143                    return MetadataViews.NFTCollectionData(
144                        storagePath: MetaverseMarket.CollectionStoragePath,
145                        publicPath: MetaverseMarket.CollectionPublicPath,
146                        providerPath: /private/ProvenancedCollectionsV9,
147                        publicCollection: Type<&MetaverseMarket.Collection{MetaverseMarket.MetaverseMarketCollectionPublic}>(),
148                        publicLinkedType: Type<&MetaverseMarket.Collection{MetaverseMarket.MetaverseMarketCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver}>(),
149                        providerLinkedType: Type<&MetaverseMarket.Collection{MetaverseMarket.MetaverseMarketCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Provider}>(),
150                        createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
151                            return <-MetaverseMarket.createEmptyCollection()
152                        })
153                    )
154            }
155
156            return nil
157        }
158
159        // initializer
160        //
161        init(initID: UInt64, uniqueListId: UInt64, listId: UInt64, name: String, categoryId: UInt64, description: String , creator: Address, fileName: String, format: String, fileIPFS: String) {
162            self.id = initID
163            self.uniqueListId = uniqueListId
164            self.listId = listId
165            self.name = name
166            self.description = description
167            self.categoryId = categoryId
168            self.creator = creator
169            self.fileName = fileName
170            self.format = format
171            self.fileIPFS = fileIPFS
172
173        }
174
175        // If the NFT is burned, emit an event to indicate
176        // to outside observers that it has been destroyed
177        destroy() {
178            emit NFTBurned(id: self.id)
179        }
180    }
181
182    // This is the interface that users can cast their MetaverseMarket Collection as
183    // to allow others to deposit MetaverseMarket into their Collection. It also allows for reading
184    // the details of MetaverseMarket in the Collection.
185    pub resource interface MetaverseMarketCollectionPublic {
186        pub fun deposit(token: @NonFungibleToken.NFT)
187        pub fun getIDs(): [UInt64]
188        pub fun getNFTs(): &{UInt64: NonFungibleToken.NFT}
189        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
190        pub fun borrowMetaverseMarket(id: UInt64): &MetaverseMarket.NFT? {
191            // If the result isn't nil, the id of the returned reference
192            // should be the same as the argument to the function
193            post {
194                (result == nil) || (result?.id == id):
195                    "Cannot borrow MetaverseMarket reference: The ID of the returned reference is incorrect"
196            }
197        }
198    }
199
200    // Collection
201    // A collection of MetaverseMarket NFTs owned by an account
202    //
203    pub resource Collection: MetaverseMarketCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic {
204        // dictionary of NFT conforming tokens
205        // NFT is a resource type with an `UInt64` ID field
206        //
207        pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
208
209        // withdraw
210        // Removes an NFT from the collection and moves it to the caller
211        //
212        pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
213            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
214
215            emit Withdraw(id: token.id, from: self.owner?.address)
216
217            return <-token
218        }
219
220        // deposit
221        // Takes a NFT and adds it to the collections dictionary
222        // and adds the ID to the id array
223        //
224        pub fun deposit(token: @NonFungibleToken.NFT) {
225            let token <- token as! @MetaverseMarket.NFT
226
227            let id: UInt64 = token.id
228
229            // add the new token to the dictionary which removes the old one
230            let oldToken <- self.ownedNFTs[id] <- token
231
232            emit Deposit(id: id, to: self.owner?.address)
233
234            destroy oldToken
235        }
236
237        // getIDs
238        // Returns an array of the IDs that are in the collection
239        //
240        pub fun getIDs(): [UInt64] {
241            return self.ownedNFTs.keys
242        }
243
244        pub fun getNFTs(): &{UInt64: NonFungibleToken.NFT} {
245            return (&self.ownedNFTs as auth &{UInt64: NonFungibleToken.NFT}?)!
246            
247        }
248
249        // borrowNFT
250        // Gets a reference to an NFT in the collection
251        // so that the caller can read its metadata and call its methods
252        //
253        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
254            return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
255        }
256
257        // borrowMetaverseMarket
258        // Gets a reference to an NFT in the collection as a MetaverseMarket,
259        // exposing all of its fields (including the typeID).
260        // This is safe as there are no functions that can be called on the MetaverseMarket.
261        //
262        pub fun borrowMetaverseMarket(id: UInt64): &MetaverseMarket.NFT? {
263            if self.ownedNFTs[id] != nil {
264                let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
265                return ref as! &MetaverseMarket.NFT
266            } else {
267                return nil
268            }
269        }
270
271        // destructor
272        destroy() {
273            emit NFTsBurned(ids: self.ownedNFTs.keys)
274            destroy self.ownedNFTs
275        }
276
277        // initializer
278        //
279        init () {
280            self.ownedNFTs <- {}
281        }
282    }
283
284    // createEmptyCollection
285    // public function that anyone can call to create a new empty collection
286    //
287    pub fun createEmptyCollection(): @NonFungibleToken.Collection {
288        return <- create Collection()
289    }
290
291    // NFTAdmin
292    // Resource that an admin or something similar would own to be
293    // able to mint new NFTs
294    //
295	pub resource Admin {
296
297        pub fun createCategory(categoryId: UInt64, categoryName: String){
298
299            if UInt64(MetaverseMarket.categoriesList.length + 1) != categoryId {
300                panic("Category ID already exists")
301            }
302
303            MetaverseMarket.categoriesList[categoryId] = categoryName
304
305            MetaverseMarket.categoriesNFTsToSell[categoryId] = []
306
307            emit CategoryCreated(categoryName: categoryName)
308        }
309
310        pub fun createList(
311            listId: UInt64,
312            name: String,
313            description: String,
314            categoryId: UInt64,
315            creator: Address,
316            fileName: String,
317            format: String,
318            fileIPFS: String,
319            price: UFix64,
320            maxSupply: UInt64
321            ){
322
323            if UInt64(MetaverseMarket.nftsToSell.length + 1) != listId {
324                panic("NFT List ID already exists")
325            }
326
327            let list = OzoneListToSellMetadata(
328                _listId: listId,
329                _name: name,
330                _description: description,
331                _categoryId: categoryId,
332                _creator: creator,
333                _fileName: fileName,
334                _format: format,
335                _fileIPFS: fileIPFS,
336                _price: price,
337                _maxSupply: maxSupply
338            )
339
340            MetaverseMarket.nftsToSell[listId] = list
341
342            //Add the list to the categoriesNFTsToSell
343            MetaverseMarket.categoriesNFTsToSell[categoryId]!.append(listId)
344
345        }
346
347		// mintNFT
348        // Mints a new NFT with a new ID
349		// and deposit it in the recipients collection using their collection reference
350        //
351		pub fun mintNFT(recipient: &{NonFungibleToken.CollectionPublic}, payment: @FungibleToken.Vault, listedNftId: UInt64) {
352            pre{
353                MetaverseMarket.nftsToSell[listedNftId] != nil: "Listed ID does not exists!"
354                payment.balance == MetaverseMarket.nftsToSell[listedNftId]!.price: "Incorrect price!"
355                MetaverseMarket.nftsToSell[listedNftId]!.maxSupply != MetaverseMarket.nftsToSell[listedNftId]!.minted: "Max Supply reached!"
356            }
357
358            let list = MetaverseMarket.nftsToSell[listedNftId]!
359            MetaverseMarket.nftsToSell[listedNftId]!.addMinted()
360
361            // Get a reference to the recipient's Receiver
362            let receiverRef =  getAccount(list.creator)
363                                .getCapability(/public/flowTokenReceiver)
364                                .borrow<&{FungibleToken.Receiver}>()
365			                    ?? panic("Could not borrow receiver reference to the recipient's Vault")
366
367            // Get a reference to the recipient's Receiver
368            let royaltyReceiver = getAccount(MetaverseMarket.account.address)
369                                .getCapability(/public/flowTokenReceiver)
370                                .borrow<&{FungibleToken.Receiver}>()
371			                    ?? panic("Could not borrow receiver reference to the recipient's Vault")
372
373            let royalty <- payment.withdraw(amount: payment.balance * 0.1)
374
375
376            royaltyReceiver.deposit(from: <- royalty)
377            receiverRef.deposit(from: <- payment)
378
379
380
381			// deposit it in the recipient's account using their reference
382			recipient.deposit(token: <- create MetaverseMarket.NFT(
383                                        initID: MetaverseMarket.totalSupply,
384                                        uniqueListId: list.minted, 
385                                        listId: list.listId, 
386                                        name: list.name,
387                                        categoryId: list.categoryId,
388                                        description: list.description,
389                                        creator: list.creator,
390                                        fileName: list.fileName,
391                                        format: list.format,
392                                        fileIPFS: list.fileIPFS
393                                        ))
394
395            MetaverseMarket.totalSupply = MetaverseMarket.totalSupply + (1 as UInt64)
396		}
397
398        //TransferNft, mint and transfer to Account NFT
399        pub fun transferNFT(recipient: &{NonFungibleToken.CollectionPublic}, listedNftId: UInt64) {
400                pre{
401                    MetaverseMarket.nftsToSell[listedNftId] != nil: "Listed ID does not exists!"
402                    MetaverseMarket.nftsToSell[listedNftId]!.maxSupply != MetaverseMarket.nftsToSell[listedNftId]!.minted: "Max Supply reached!"
403                }
404
405                let list = MetaverseMarket.nftsToSell[listedNftId]!
406                MetaverseMarket.nftsToSell[listedNftId]!.addMinted()
407
408                // deposit it in the recipient's account using their reference
409                recipient.deposit(token: <- create MetaverseMarket.NFT(
410                                        initID: MetaverseMarket.totalSupply,
411                                        uniqueListId: list.minted, 
412                                        listId: list.listId, 
413                                        name: list.name,
414                                        categoryId: list.categoryId,
415                                        description: list.description,
416                                        creator: list.creator,
417                                        fileName: list.fileName,
418                                        format: list.format,
419                                        fileIPFS: list.fileIPFS
420                                        ))
421
422                MetaverseMarket.totalSupply = MetaverseMarket.totalSupply + (1 as UInt64)
423        }
424	}
425
426    
427
428    // fetch
429    // Get a reference to a MetaverseMarket from an account's Collection, if available.
430    // If an account does not have a MetaverseMarket.Collection, panic.
431    // If it has a collection but does not contain the itemID, return nil.
432    // If it has a collection and that collection contains the itemID, return a reference to that.
433    //
434    pub fun fetch(_ from: Address, itemID: UInt64): &MetaverseMarket.NFT? {
435        let collection = getAccount(from)
436            .getCapability(MetaverseMarket.CollectionPublicPath)
437            .borrow<&MetaverseMarket.Collection{MetaverseMarket.MetaverseMarketCollectionPublic}>()
438            ?? panic("Couldn't get collection")
439        // We trust MetaverseMarket.Collection.borowMetaverseMarket to get the correct itemID
440        // (it checks it before returning it).
441        return collection.borrowMetaverseMarket(id: itemID)
442    }
443
444    pub fun getAllNftsFromAccount(_ from: Address): &{UInt64: NonFungibleToken.NFT}? {
445        let collection = getAccount(from)
446            .getCapability(MetaverseMarket.CollectionPublicPath)
447            .borrow<&MetaverseMarket.Collection{MetaverseMarket.MetaverseMarketCollectionPublic}>()
448            ?? panic("Couldn't get collection")
449        return collection.getNFTs()
450    }
451
452    pub fun getCategories(): {UInt64:String} {
453        return MetaverseMarket.categoriesList
454    }
455
456    pub fun getCategoriesIds(): [UInt64] {
457        return MetaverseMarket.categoriesList.keys
458    }
459
460    pub fun getCategorieName(id: UInt64): String {
461        return MetaverseMarket.categoriesList[id] ?? panic("Category does not exists")
462    }
463
464    pub fun getCategoriesListLength(): UInt64 {
465        return UInt64(MetaverseMarket.categoriesList.length)
466    }
467
468    pub fun getNftToSellListLength(): UInt64{
469        return UInt64(MetaverseMarket.nftsToSell.length)
470    }
471
472    pub fun getCategoriesNFTsToSell(categoryId: UInt64): [UInt64]?{
473        return MetaverseMarket.categoriesNFTsToSell[categoryId]
474    }
475
476    pub fun getNftToSellData(listId: UInt64): OzoneListToSellMetadata? {
477         return MetaverseMarket.nftsToSell[listId]
478    }
479
480    pub fun getAllListToSell(): [UInt64]{
481        return MetaverseMarket.nftsToSell.keys
482    }
483
484    // initializer
485    //
486	init() {
487        // Set our named paths
488        self.CollectionStoragePath = /storage/NftMetaverseMarketCollectionVersionOne
489        self.CollectionPublicPath = /public/NftMetaverseMarketCollectionVersionOne
490        self.AdminStoragePath = /storage/metaverseMarketAdmin
491
492        self.categoriesList = {}
493
494        self.categoriesNFTsToSell = {}
495
496        self.nftsToSell = {}
497
498        // Initialize the total supply
499        self.totalSupply = 0
500
501        // Create a Admin resource and save it to storage
502        let admin <- create Admin()
503        self.account.save(<-admin, to: self.AdminStoragePath)
504
505        // Create and link collection to this account
506        self.account.save(<- self.createEmptyCollection(), to: self.CollectionStoragePath)
507        self.account.link<&MetaverseMarket.Collection{NonFungibleToken.CollectionPublic, MetaverseMarket.MetaverseMarketCollectionPublic}>(self.CollectionPublicPath, target: self.CollectionStoragePath)
508
509        emit ContractInitialized()
510	}
511}
512