Smart Contract

YoungBoysBern

A.20187093790b9aef.YoungBoysBern

Deployed

16h ago
Feb 28, 2026, 02:29:49 AM UTC

Dependents

0 imports
1/*
2    Description: 
3
4    authors: Joseph Djenandji, Matthew Balazsi, Jennifer McIntyre
5    
6*/
7
8// import NonFungibleToken from "./NonFungibleToken.cdc"
9// import FungibleToken from "./FungibleToken.cdc"
10// import MetadataViews from "./MetadataViews.cdc"
11
12// for emulator
13// import NonFungibleToken from "0xNonFungibleToken"
14// import ViewResolver from "0xViewResolver"
15// import MetadataViews from "0xMetadataViews"
16
17// for tests
18// import NonFungibleToken from NonFungibleToken
19// import MetadataViews from MetadataViews
20
21// for testnet
22// import NonFungibleToken from 0x631e88ae7f1d7c20
23// import MetadataViews from 0x631e88ae7f1d7c20
24// import ViewResolver from 0x631e88ae7f1d7c20
25
26// for mainnet
27import NonFungibleToken from 0x1d7e57aa55817448
28import MetadataViews from 0x1d7e57aa55817448
29import ViewResolver from 0x1d7e57aa55817448
30
31
32access(all) contract YoungBoysBern: NonFungibleToken {
33
34    // -----------------------------------------------------------------------
35    // Contract Events
36    // -----------------------------------------------------------------------
37
38    // Emitted when the contract is created
39    access(all) event ContractInitialized()
40
41    // Emitted when a new Edition struct is created
42    access(all) event EditionCreated(id: UInt32, name: String, printingLimit: UInt32?)
43
44    // Emitted when Edition Metadata is updated
45    access(all) event EditionMetadaUpdated(editionID: UInt32)
46
47
48    // default royalties
49    access(all) event DefaultRoyaltiesUpdated(name: String, cut: UFix64)
50
51    // remove default royalty
52    access(all) event DefaultRoyaltyRemoved(name: String)
53
54    // royalties for edition
55    access(all) event RoyaltiesForEditionUpdated(editionID: UInt32, name: String, cut: UFix64)
56
57    // remove royalty for edition
58    access(all) event RoyaltiesForEditionRemoved(editionID: UInt32, name: String)
59
60
61    // RevertRoyaltiesForEditionToDefault when the admin clears the specific royalties for that edition, to revert back to default royalties
62    access(all) event RevertRoyaltiesForEditionToDefault(editionID: UInt32)
63
64
65
66    // Emitted when a new item was minted
67    access(all) event ItemMinted(itemID:UInt64, merchantID: UInt32, editionID: UInt32, editionNumber: UInt32)
68
69    // Item related events 
70    //
71    // Emitted when an Item is withdrawn from a Collection
72    access(all) event Withdraw(id: UInt64, from: Address?)
73    // Emitted when an Item is deposited into a Collection
74    access(all) event Deposit(id: UInt64, to: Address?)
75    // Emitted when an Item is destroyed
76    access(all) event ItemDestroyed(id: UInt64)
77
78
79    // Named paths
80    //
81    access(all) let CollectionStoragePath: StoragePath
82    access(all) let CollectionPublicPath: PublicPath
83    access(all) let AdminStoragePath: StoragePath
84
85
86    // -----------------------------------------------------------------------
87    // YoungBoysBern contract-level fields.
88    // These contain actual values that are stored in the smart contract.
89    // -----------------------------------------------------------------------
90
91    // Variable size dictionary of Editions resources
92    access(self) var editions: @{UInt32: Edition}
93
94
95    // the default royalties
96    access(self) var defaultRoyalties: {String: MetadataViews.Royalty}
97
98    // If a specific NFT requires their own royalties, 
99    // the default royalties can be overwritten in this dictionary.
100    access(all) var royaltiesForSpecificEdition:  {UInt32: {String: MetadataViews.Royalty}}
101
102
103    // The ID that is used to create Admins. 
104    // Every Admins should have a unique identifier.
105    access(all) var nextAdminID: UInt32
106
107    
108
109    // The ID that is used to create Editions. 
110    // Every time an Edition is created, nextEditionID is assigned 
111    // to the edition and then is incremented by 1.
112    access(all) var nextEditionID: UInt32
113
114
115
116    // The total number of NFTs that have been created for this smart contract
117    // Because NFTs can be destroyed, it doesn't necessarily mean that this
118    // reflects the total number of NFTs in existence, just the number that
119    // have been minted to date. Also used as global nft IDs for minting.
120    access(all) var totalSupply: UInt64
121
122    // -----------------------------------------------------------------------
123    // YoungBoysBern contract-level Composite Type definitions
124    // -----------------------------------------------------------------------
125    // These are just *definitions* for Types that this contract
126    // and other accounts can use. These definitions do not contain
127    // actual stored values, but an instance (or object) of one of these Types
128    // can be created by this contract that contains stored values.
129    // -----------------------------------------------------------------------
130   
131
132    // EditionData is a struct definition to have all of the same fields as the Edition resource.
133    // it can be used to publicly read Edition data
134
135    access(all) struct EditionData {  
136        access(all) let editionID: UInt32  
137        access(all) let merchantID: UInt32  
138        access(all) let name: String  
139        access(all) var items: [UInt64]  
140        access(all) var metadata: {String: String}
141        access(all) var numberOfItemsMinted: UInt32
142        access(all) var printingLimit: UInt32?
143        
144        init(editionID: UInt32) {
145
146             if YoungBoysBern.editions[editionID] == nil {
147                panic("the editionID was not found")
148            }
149            let editionToRead = (&YoungBoysBern.editions[editionID] as &Edition?)!
150
151            self.editionID = editionID
152            self.metadata = (YoungBoysBern.editions[editionID]?.metadata ?? {}) 
153            self.merchantID = editionToRead.merchantID
154            self.name = editionToRead.name
155            self.printingLimit = editionToRead.printingLimit
156            self.numberOfItemsMinted=editionToRead.numberOfItemsMinted
157            self.items=YoungBoysBern.editions[editionID]?.items ?? []
158        }
159    }
160    // Edition is a Ressource that holds metadata associated 
161    // with a specific NFT
162    //
163    // NFTs will all reference an Edition as the owner of
164    // its metadata. The Editions are publicly accessible, so anyone can
165    // read the metadata associated with a specific EditionID
166    //
167    access(all) resource Edition {
168
169        // The unique ID for the Edition
170        access(all) let editionID: UInt32
171
172        // The ID of the merchant that owns the edition
173        access(all) let merchantID: UInt32
174
175        // Stores all the metadata about the edition as a string mapping
176        // This is not the long term way NFT metadata will be stored. It's a temporary
177        // construct while we figure out a better way to do metadata.
178        //
179        access(all) let metadata: {String: String}
180
181        // Array of items that are a part of this collection.
182        // When an item is added to the collection, its ID gets appended here.
183        access(contract) var items: [UInt64]
184
185        // The number of items minted in this collection.
186        // When an item is added to the collection, the numberOfItems is incremented by 1
187        // It will be used to identify the editionNumber of an item
188        // if the edition is open (printingLimit=nil), we can keep minting new items
189        // if the edition is limited (printingLimit!=nil), we can keep minting items until we reach printingLimit
190        access(all) var numberOfItemsMinted: UInt32
191
192
193        // the limit of items that can be minted. For open editions, this value should be set to nil.
194        access(all) var printingLimit: UInt32?
195
196        // the name of the edition
197        access(all) var name: String
198
199        init(merchantID: UInt32, metadata: {String: String}, name: String, printingLimit:UInt32?) {
200            pre {
201                metadata.length != 0: "Metadata cannot be empty"
202                name!=nil: "Name is undefined"
203            }
204            self.editionID = YoungBoysBern.nextEditionID
205            self.merchantID = merchantID
206            self.metadata = metadata
207            self.name = name
208            self.printingLimit = printingLimit
209            self.numberOfItemsMinted=0
210            self.items = []
211
212            
213            // Increment the ID so that it isn't used again
214            YoungBoysBern.nextEditionID = YoungBoysBern.nextEditionID + (1 as UInt32)
215
216            emit EditionCreated(id: self.editionID, name: self.name, printingLimit: self.printingLimit)
217        }
218
219
220        // mintItem mints a new Item and returns the newly minted Item
221        // 
222        // Pre-Conditions:
223        // If the edition is limited the number of items minted in the edition must be strictly less than the printing limit
224        //
225        // Returns: The NFT that was minted
226        // 
227        access(all) fun mintItem(): @NFT {
228            pre {
229                (self.numberOfItemsMinted < (self.printingLimit ?? (4294967295 as UInt32)  )): "We have reached the printing limit for this edition"
230            }
231
232            // Gets the number of Itms that have been minted for this Edition
233            // to use as this Item's edition number
234            let numMinted = self.numberOfItemsMinted + (1 as UInt32)
235
236            // Mint the new item
237            let newItem: @NFT <- create NFT(merchantID: self.merchantID, editionID: self.editionID, editionNumber: numMinted)
238
239
240            // Add the Item to the array of items
241            self.items.append(newItem.id)                            
242
243            // Increment the count of Items
244            self.numberOfItemsMinted = numMinted 
245
246            return <-newItem
247        }
248
249        // batchMintItems mints an arbitrary quantity of Items 
250        // and returns them as a Collection
251        // Be sure there are enough 
252        //
253        // Parameters: quantity: The quantity of Items to be minted
254        //
255        // Returns: Collection object that contains all the Items that were minted
256        //
257        access(all) fun batchMintItems(quantity: UInt32): @Collection {
258           
259            pre {
260                ((self.numberOfItemsMinted+quantity)<=(self.printingLimit ?? (4294967295 as UInt32))): "We have reached the printing limit for this edition"
261            }
262
263            let newCollection <- create Collection()
264
265            var i: UInt32 = 0
266            while i < quantity {
267                newCollection.deposit(token: <-self.mintItem())
268                i = i + (1 as UInt32)
269            }
270
271            return <-newCollection
272        }
273
274        // updateMetadata updates the metadata
275        //
276        // Parameters: 
277        //
278        // updates: a dictionary of key - values that is requested to be appended
279        //
280        // suffix: If the metadata already contains an attribute with a given key, this value should still be kept 
281        // for posteriority. Therefore, the old value to be replaced will be stored in a metadata entry with key = key+suffix. 
282        // This can offer some reassurance to the NFT owner that the metadata will never disappear.
283        // 
284        // Returns: the EditionID
285        //
286        access(all) fun updateMetadata(updates: {String:String}, suffix: String): UInt32 {
287           
288
289
290            // prevalidation 
291            // if metadata[key] exists and metadata[key+suffix] exists, we have a clash.
292            for key in updates.keys {
293
294                let newKey = key.concat(suffix)
295
296                if self.metadata[key] != nil && self.metadata[newKey]!=nil {
297                    var errorMsg = "attributes "
298                    errorMsg = errorMsg.concat(key).concat(" and ").concat(newKey).concat(" are already defined")
299                    panic(errorMsg)
300                }
301                    
302
303            }
304
305            // execution
306            for key in updates.keys {
307
308                let newKey = key.concat(suffix)
309
310                if self.metadata[key] != nil {
311                    self.metadata[newKey] = self.metadata[key]    
312                }
313                self.metadata[key] = updates[key]
314                
315            }
316
317
318            emit EditionMetadaUpdated(editionID: self.editionID)
319            
320            // Return the EditionID and return it
321            return self.editionID
322        }
323
324    }
325
326    // The struct representing an NFT Item data
327    access(all) struct ItemData {
328
329
330        // The ID of the merchant 
331        access(all) let merchantID: UInt32
332
333        // The ID of the edition that the NFT comes from
334        access(all) let editionID: UInt32
335
336        // The number of the NFT within the edition
337        access(all) let editionNumber: UInt32
338
339
340
341        init(merchantID: UInt32, editionID: UInt32, editionNumber: UInt32) {
342            self.merchantID = merchantID
343            self.editionID = editionID
344            self.editionNumber = editionNumber
345        }
346
347    }
348
349    // The resource that represents the Item NFTs
350    //
351    access(all) resource NFT: NonFungibleToken.NFT {
352
353        // Global unique item ID
354        access(all) let id: UInt64
355
356        // Struct of the metadata
357        access(all) let data: ItemData
358
359
360        init(merchantID: UInt32, editionID: UInt32, editionNumber: UInt32) {
361            
362            pre{
363                editionID > (0 as UInt32): "editionID cannot be 0"
364                editionNumber > (0 as UInt32): "editionNumber cannot be 0"
365            }
366            // Increment the global Item IDs
367            YoungBoysBern.totalSupply = YoungBoysBern.totalSupply + (1 as UInt64)
368
369            self.id = YoungBoysBern.totalSupply
370
371            // Set the metadata struct
372            self.data = ItemData(merchantID: merchantID, editionID: editionID, editionNumber: editionNumber)
373
374            
375            emit ItemMinted(itemID: self.id, merchantID: merchantID, editionID: editionID, editionNumber: editionNumber)
376        }
377
378        access(all) view fun getData(): ItemData {
379            return self.data
380        }
381
382                /// createEmptyCollection creates an empty Collection
383        /// and returns it to the caller so that they can own NFTs
384        /// @{NonFungibleToken.Collection}
385        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
386            return <-YoungBoysBern.createEmptyCollection(nftType: Type<@YoungBoysBern.NFT>())
387        }
388
389
390        access(all) view fun getViews(): [Type] {
391            return [
392                Type<MetadataViews.Display>(),
393                Type<MetadataViews.Royalties>(),
394                Type<MetadataViews.Editions>(),
395                Type<MetadataViews.ExternalURL>(),
396                Type<MetadataViews.NFTCollectionData>(),
397                Type<MetadataViews.NFTCollectionDisplay>(),
398                Type<MetadataViews.Serial>(),
399                Type<MetadataViews.Traits>()
400            ]
401        }
402
403
404        access(all) fun resolveView(_ view: Type): AnyStruct? {
405            switch view {
406                case Type<MetadataViews.Display>():
407                    let edition = EditionData(editionID: self.data.editionID);
408                    return MetadataViews.Display(
409                        name: edition.name,
410                        description: edition.metadata["description"] ?? "",
411                        thumbnail: MetadataViews.HTTPFile(
412                            url: edition.metadata["thumbnail"] ?? ""
413                        )
414                    )
415                case Type<MetadataViews.Editions>():
416                    let edition = EditionData(editionID: self.data.editionID);
417                    let maxNumber = edition.printingLimit ?? nil
418                    var max: UInt64? = nil;
419                    if maxNumber != nil {
420                     max = UInt64(maxNumber!)
421                    }
422                      
423
424                    let editionInfo = MetadataViews.Edition(name: edition.name, number: UInt64(self.data.editionNumber), max:max)
425                    let editionList: [MetadataViews.Edition] = [editionInfo]
426                    return MetadataViews.Editions(
427                        editionList
428                    )
429                
430                case Type<MetadataViews.ExternalURL>():
431                    return MetadataViews.ExternalURL("https://www.bscyb.ch/")
432
433
434                case Type<MetadataViews.Royalties>():
435                    let royaltiesDictionary = YoungBoysBern.royaltiesForSpecificEdition[self.data.editionID] ?? YoungBoysBern.defaultRoyalties 
436                    var royalties: [MetadataViews.Royalty] = []
437                    for royaltyName in royaltiesDictionary.keys {
438                        royalties.append(royaltiesDictionary[royaltyName]!)
439                    }
440                  return MetadataViews.Royalties(royalties)
441                
442                case Type<MetadataViews.NFTCollectionDisplay>():                    
443                    return MetadataViews.NFTCollectionDisplay(
444                        name: "YoungBoysBern",
445                        description: "YoungBoysBern Contract",
446                        externalURL: MetadataViews.ExternalURL("https://www.bscyb.ch/"),
447                        squareImage: MetadataViews.Media(
448                            file: MetadataViews.HTTPFile(
449                                url: "https://dkuxa1i6sgo8h.cloudfront.net/BSC-Young-Boys/BSC_Young_Boys_logo.png"
450                            ),
451                            mediaType: "image/png"
452                        ),
453                        bannerImage: MetadataViews.Media(
454                            file: MetadataViews.HTTPFile(
455                                url: "https://dkuxa1i6sgo8h.cloudfront.net/BSC-Young-Boys/BSC_Young_Boys_logo.png"
456                            ),
457                            mediaType: "image/png"
458                        ),
459                        socials: {}
460                    )
461                
462                case Type<MetadataViews.NFTCollectionData>():
463                    return  MetadataViews.NFTCollectionData(
464                        storagePath: YoungBoysBern.CollectionStoragePath,
465                        publicPath: YoungBoysBern.CollectionPublicPath,
466                        publicCollection: Type<&YoungBoysBern.Collection>(),
467                        publicLinkedType: Type<&YoungBoysBern.Collection>(),
468                        createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
469                            return <-YoungBoysBern.createEmptyCollection(nftType: Type<@YoungBoysBern.NFT>())
470                        })
471                    )
472
473
474                case Type<MetadataViews.Traits>():
475                    // exclude essential metadata to keep unique traits
476                    let excludedTraits = ["name", "description", "externalUrl", "squareImage", "squareImageType", "bannerImage", "bannerImageType", "thumbnail", "thumbnailType"]
477
478                    let edition = EditionData(editionID: self.data.editionID);
479                    let metadata = edition.metadata;
480
481                    metadata.insert(key: "editionID", edition.editionID.toString());
482                    metadata.insert(key: "merchantID", edition.merchantID.toString());
483
484                    let traitsView = MetadataViews.dictToTraits(dict: metadata, excludedNames: excludedTraits)
485                    
486                    return traitsView
487
488
489                case Type<MetadataViews.Serial>():
490                    return MetadataViews.Serial(
491                        UInt64(self.data.editionNumber)
492                    )
493                
494
495            }
496
497            return nil
498        }
499
500
501      
502
503    }
504
505     access(all) view fun getContractViews(resourceType: Type?): [Type] {
506        return []
507    }
508
509     access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
510 
511        return nil
512     }
513
514
515    // Admin is a special authorization resource that 
516    // allows the owner to perform important functions to modify the 
517    // various aspects of the Editions and Items
518    //
519    access(all) resource Admin {
520
521        access(all) let id: UInt32
522        // createEdition creates a new Edition struct 
523        // and stores it in the Editions dictionary in the contract
524        //
525
526        init(id: UInt32) {
527            self.id = id
528        }
529
530        // createEdition creates a new Edition resource and stores it
531        // in the editions mapping in the contract
532        //
533        // Parameters: 
534        //  merchantID: The ID of the merchant
535        //  metadata: the associated data
536        //  name: The name of the Edition
537        //  printingLimit: We can only mint this quantity of NFTs. If printingLimit is nil there is no limit (theoretically UInt32.max)
538        //
539        access(all) fun createEdition(merchantID: UInt32, metadata: {String: String}, name: String, printingLimit: UInt32?) {
540            // Create the new Edition
541            var newEdition <- create Edition(merchantID:merchantID, metadata: metadata, name: name, printingLimit:printingLimit)
542            let newID = newEdition.editionID
543
544            // Store it in the contract storage
545            YoungBoysBern.editions[newID] <-! newEdition
546
547        }
548
549
550        // borrowEdition returns a reference to an edition in the YoungBoysBern
551        // contract so that the admin can call methods on it
552        //
553        // Parameters: editionID: The ID of the Edition that you want to
554        // get a reference to
555        //
556        // Returns: A reference to the Edition with all of the fields
557        // and methods exposed
558        //
559        access(all) fun borrowEdition(editionID: UInt32): &Edition {
560            pre {
561                YoungBoysBern.editions[editionID] != nil: "Cannot borrow Edition: it does not exist"
562            }
563            
564            // Get a reference to the Edition and return it
565            return (&YoungBoysBern.editions[editionID] as &Edition?)!
566        }
567
568        // updateEditionMetadata returns a reference to an edition in the YoungBoysBern
569        // contract so that the admin can call methods on it
570        //
571        // Parameters: 
572        // editionID: The ID of the Edition that you want to update
573        //
574        // updates: a dictionary of key - values that is requested to be appended
575        //
576        // suffix: If the metadata already contains an attribute with a given key, this value should still be kept 
577        // for posteriority. Therefore, the old value to be replaced will be stored in a metadata entry with key = key+suffix. 
578        // This can offer some reassurance to the NFT owner that the metadata will never disappear.
579        // 
580        // Returns: the EditionID
581        //
582        access(all) fun updateEditionMetadata(editionID: UInt32, updates: {String:String}, suffix: String): UInt32 {
583            pre {
584                YoungBoysBern.editions[editionID] != nil: "Cannot borrow Edition: it does not exist"
585            }
586 
587            let editionRef = &YoungBoysBern.editions[editionID] as &Edition?
588            editionRef!.updateMetadata(updates: updates, suffix: suffix)
589            
590            // Return the EditionID and return it
591            return editionID
592        }
593
594
595        // set default royalties
596        access(all) fun setDefaultRoyaltyByName(name: String, royalty: MetadataViews.Royalty) {
597            YoungBoysBern.defaultRoyalties[name] = royalty;
598            // verify total
599            let totalCut = YoungBoysBern.getDefaultRoyaltyTotalRate()
600            assert(totalCut <= 1.0, message: "Sum of cutInfos multipliers should not be greater than 1.0")
601            emit DefaultRoyaltiesUpdated(name: name, cut: royalty.cut)
602        }
603
604        access(all) fun removeDefaultRoyaltyByName(name: String) {
605
606            if !YoungBoysBern.defaultRoyalties.containsKey(name) {
607
608                var errorMsg = "Default Royalty with name [" 
609                errorMsg = errorMsg.concat(name).concat("] does not exist")
610                panic(errorMsg)
611            }
612
613            YoungBoysBern.defaultRoyalties.remove(key: name);
614            emit DefaultRoyaltyRemoved(name: name)
615        }
616
617        // set royalties for edition
618        access(all) fun setEditionRoyaltyByName( editionID: UInt32, name: String, royalty: MetadataViews.Royalty) {
619            
620            if !YoungBoysBern.royaltiesForSpecificEdition.containsKey(editionID) {
621                YoungBoysBern.royaltiesForSpecificEdition.insert(key:editionID, {})
622            }
623            //let royaltiesForSpecificEdition = YoungBoysBern.royaltiesForSpecificEdition[editionID]!
624            //royaltiesForSpecificEdition.insert(key: name, royalty);
625            YoungBoysBern.royaltiesForSpecificEdition[editionID]!.insert(key: name, royalty);
626             let totalCut = YoungBoysBern.getEditionRoyaltyTotalRate(editionID:editionID)
627            assert(totalCut <= 1.0, message: "Sum of cutInfos multipliers should not be greater than 1.0")
628
629            emit RoyaltiesForEditionUpdated(editionID: editionID, name: name, cut: royalty.cut)
630        }
631
632        // remove royalty for edition
633        access(all) fun removeEditionRoyaltyByName( editionID: UInt32, name: String) {
634            
635            if !YoungBoysBern.royaltiesForSpecificEdition.containsKey(editionID) {
636                var errorMsg = "Royalty specific to editionID" 
637                errorMsg = errorMsg.concat(editionID.toString()).concat(" does not exist")
638                panic(errorMsg)
639            }
640            let royaltiesForSpecificEdition = YoungBoysBern.royaltiesForSpecificEdition[editionID]!
641            if !royaltiesForSpecificEdition.containsKey(name) {
642                var errorMsg = "Royalty specific to editionID" 
643                errorMsg = errorMsg.concat(editionID.toString()).concat(" with the name[").concat(name).concat("] does not exist")
644                panic(errorMsg)
645            }
646            YoungBoysBern.royaltiesForSpecificEdition[editionID]!.remove(key: name);
647            emit RoyaltiesForEditionRemoved(editionID: editionID, name: name)
648        }
649
650       access(all) fun revertRoyaltiesForEditionToDefault(editionID: UInt32){
651            if !YoungBoysBern.royaltiesForSpecificEdition.containsKey(editionID){
652                var errorMsg = "Royalty for editionID "
653                errorMsg = errorMsg.concat(editionID.toString()).concat("  does not exist")
654                panic(errorMsg)
655            } 
656                
657
658            YoungBoysBern.royaltiesForSpecificEdition.remove(key: editionID)
659            emit RevertRoyaltiesForEditionToDefault(editionID: editionID)
660       }
661
662
663
664
665        // createNewAdmin creates a new Admin resource
666        //
667        access(all) fun createNewAdmin(): @Admin {
668            
669
670            let newID = YoungBoysBern.nextAdminID
671             // Increment the ID so that it isn't used again
672            YoungBoysBern.nextAdminID = YoungBoysBern.nextAdminID + (1 as UInt32)
673
674            return <-create Admin(id: newID)
675        }
676
677    }
678
679
680
681    // This is the interface that users can cast their YoungBoysBern Collection as
682    // to allow others to deposit YoungBoysBerns into their Collection. It also allows for reading
683    // the IDs of YoungBoysBerns in the Collection.
684    access(all) resource interface YoungBoysBernCollectionPublic {
685       
686        
687    }
688
689
690
691    // Collection is a resource that every user who owns NFTs 
692    // will store in their account to manage their NFTS
693    //
694    access(all) resource Collection: NonFungibleToken.Collection, YoungBoysBernCollectionPublic { 
695        // Dictionary of YoungBoysBern conforming tokens
696        // NFT is a resource type with a UInt64 ID field
697        access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
698        // access(all) var ownedNFTs: @{UInt64: YoungBoysBern.NFT}
699
700        init() {
701            self.ownedNFTs <- {}
702        }
703
704
705
706
707        // withdraw removes a YoungBoysBern from the Collection and moves it to the caller
708        //
709        // Parameters: withdrawID: The ID of the NFT 
710        // that is to be removed from the Collection
711        //
712        // returns: @NonFungibleToken.NFT the token that was withdrawn
713        access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
714
715            // Remove the nft from the Collection
716            let token <- self.ownedNFTs.remove(key: withdrawID) 
717                ?? panic("Cannot withdraw: YoungBoysBern does not exist in the collection")
718
719            emit Withdraw(id: token.id, from: self.owner?.address)
720            
721            // Return the withdrawn token
722            return <-token
723        }
724
725        // batchWithdraw withdraws multiple tokens and returns them as a Collection
726        //
727        // Parameters: ids: An array of IDs to withdraw
728        //
729        // Returns: @NonFungibleToken.Collection: A collection that contains
730        //                                        the withdrawn YoungBoysBern items
731        //
732        access(NonFungibleToken.Withdraw) fun batchWithdraw(ids: [UInt64]): @{NonFungibleToken.Collection} {
733            // Create a new empty Collection
734            var batchCollection <- create Collection()
735            
736            // Iterate through the ids and withdraw them from the Collection
737            for id in ids {
738
739                let token <-self.withdraw(withdrawID: id)
740
741                batchCollection.deposit(token: <-token)
742            }
743            
744            // Return the withdrawn tokens
745            return <-batchCollection
746        }
747
748                 /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
749        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
750            let supportedTypes: {Type: Bool} = {}
751            supportedTypes[Type<@YoungBoysBern.NFT>()] = true
752            return supportedTypes
753        }
754
755        /// Returns whether or not the given type is accepted by the collection
756        /// A collection that can accept any type should just return true by default
757        access(all) view fun isSupportedNFTType(type: Type): Bool {
758            return type == Type<@YoungBoysBern.NFT>()
759        }
760
761        /// Gets the amount of NFTs stored in the collection
762        access(all) view fun getLength(): Int {
763            return self.ownedNFTs.length
764        }
765
766        // deposit takes a YoungBoysBern and adds it to the Collections dictionary
767        //
768        // Paramters: token: the NFT to be deposited in the collection
769        //
770        access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
771            
772            // Cast the deposited token as a YoungBoysBern NFT to make sure
773            // it is the correct type
774            let token <- token as! @YoungBoysBern.NFT
775
776            // Get the token's ID
777            let id = token.id
778
779            // Add the new token to the dictionary
780            let oldToken <- self.ownedNFTs[id] <- token
781
782            // Only emit a deposit event if the Collection 
783            // is in an account's storage
784            if self.owner?.address != nil {
785                emit Deposit(id: id, to: self.owner?.address)
786            }
787
788            // Destroy the empty old token that was "removed"
789            destroy oldToken
790        }
791
792        // batchDeposit takes a Collection object as an argument
793        // and deposits each contained NFT into this Collection
794        access(all) fun batchDeposit(tokens: @{NonFungibleToken.Collection}) {
795
796            // Get an array of the IDs to be deposited
797            let keys = tokens.getIDs()
798
799            // Iterate through the keys in the collection and deposit each one
800            for key in keys {
801                self.deposit(token: <-tokens.withdraw(withdrawID: key))
802            }
803
804            // Destroy the empty Collection
805            destroy tokens
806        }
807
808        // getIDs returns an array of the IDs that are in the Collection
809        access(all) view fun getIDs(): [UInt64] {
810            return self.ownedNFTs.keys
811        }
812
813        // borrowNFT Returns a borrowed reference to a YoungBoysBern in the Collection
814        // so that the caller can read its ID
815        //
816        // Parameters: id: The ID of the NFT to get the reference for
817        //
818        // Returns: A reference to the NFT
819        //
820        // Note: This only allows the caller to read the ID of the NFT,
821        // not any YoungBoysBern specific data. Please use borrowYoungBoysBern to 
822        // read YoungBoysBern data.
823        //
824         access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
825            return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
826        }
827
828
829      
830
831       /// Borrow the view resolver for the specified NFT ID
832        access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
833            if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
834                return nft as &{ViewResolver.Resolver}
835            }
836            return nil
837        }
838
839        /// createEmptyCollection creates an empty Collection of the same type
840        /// and returns it to the caller
841        /// @return A an empty collection of the same type
842        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
843            return <-YoungBoysBern.createEmptyCollection(nftType: Type<@YoungBoysBern.NFT>())
844        }
845    }
846
847
848
849    // -----------------------------------------------------------------------
850    // YoungBoysBern contract-level function definitions
851    // -----------------------------------------------------------------------
852
853    // createEmptyCollection creates a new, empty Collection object so that
854    // a user can store it in their account storage.
855    // Once they have a Collection in their storage, they are able to receive
856    // YoungBoysBerns in transactions.
857    //
858    access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
859        return <- create YoungBoysBern.Collection()
860    }
861
862    access(all) fun createEmptyYoungBoysBernCollection(): @YoungBoysBern.Collection {
863        return <-create YoungBoysBern.Collection()
864    }
865
866    // getDefaultRoyalties returns the default royalties
867    access(all) fun getDefaultRoyalties(): {String: MetadataViews.Royalty} {
868        return self.defaultRoyalties
869    }
870
871    // getDefaultRoyalties returns the default royalties
872    access(all) fun getDefaultRoyaltyNames(): [String] {
873        return self.defaultRoyalties.keys
874    }
875
876    // getDefaultRoyalties returns the default royalties
877    access(all) fun getDefaultRoyaltyByName(name: String): MetadataViews.Royalty? {
878        return self.defaultRoyalties[name]
879    }
880
881    // getDefaultRoyalties returns the default royalties total rate
882    access(all) fun getDefaultRoyaltyTotalRate(): UFix64 {
883        var cut = 0.0
884        for name in self.defaultRoyalties.keys {
885            cut=cut+self.defaultRoyalties[name]!.cut
886        }
887
888        return cut;
889    }
890
891
892
893
894
895    // getRoyaltiesForEdition returns the royalties set for a specific edition, that overrides the default
896    access(all) fun getEditionRoyalties(editionID: UInt32): {String: MetadataViews.Royalty} {
897        return self.royaltiesForSpecificEdition[editionID] ?? self.defaultRoyalties
898    }
899
900    // getRoyaltiesForEdition returns the royalties set for a specific edition, that overrides the default
901    access(all) fun getEditionRoyaltyNames(editionID: UInt32): [String] {
902        let royalties = YoungBoysBern.getEditionRoyalties(editionID: editionID)
903        return royalties.keys
904    }
905
906     // getRoyaltiesForEdition returns the royalties set for a specific edition, that overrides the default
907    access(all) fun getEditionRoyaltyByName(editionID: UInt32, name: String): MetadataViews.Royalty {
908        let royaltiesForSpecificEdition = YoungBoysBern.getEditionRoyalties(editionID: editionID)
909        return royaltiesForSpecificEdition[name]!
910    }
911
912    // getDefaultRoyalties returns the default royalties total rate
913    access(all) fun getEditionRoyaltyTotalRate(editionID: UInt32): UFix64 {
914        let royalties = YoungBoysBern.getEditionRoyalties(editionID: editionID)
915        var cut = 0.0
916        for name in royalties.keys {
917            cut=cut+royalties[name]!.cut
918        }
919
920        return cut;
921    }
922
923
924    // -----------------------------------------------------------------------
925    // initialization function
926    // -----------------------------------------------------------------------
927    //
928    init() {
929        // Initialize contract fields
930        self.editions <- {}
931        self.nextEditionID = 1
932        self.totalSupply = 0
933        self.defaultRoyalties = {}
934        self.royaltiesForSpecificEdition = {}
935
936
937        self.CollectionStoragePath = /storage/YoungBoysBernCollection
938        self.CollectionPublicPath = /public/YoungBoysBernCollection
939        self.AdminStoragePath = /storage/YoungBoysBernItemAdmin
940
941        // Put a new Collection in storage
942        self.account.storage.save<@Collection>(<- create Collection(), to: self.CollectionStoragePath)
943
944        // Create a public capability for the Collection
945        // self.account.link<&{YoungBoysBernCollectionPublic}>(self.CollectionPublicPath, target: self.CollectionStoragePath)
946        let collectionCap = self.account.capabilities.storage.issue<&YoungBoysBern.Collection>(self.CollectionStoragePath)
947        self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
948
949        // Put the admin ressource in storage
950        self.account.storage.save<@Admin>(<- create Admin(id: 1), to: self.AdminStoragePath)
951        self.nextAdminID = 2
952
953        emit ContractInitialized()
954    }
955
956
957}
958    
959