Smart Contract
BBCollectables
A.6d9326ab02640bc5.BBCollectables
1// import NonFungibleToken from 0x631e88ae7f1d7c20
2// import MetadataViews from 0x631e88ae7f1d7c20
3// import FungibleToken from 0x9a0766d93b6608b7
4// import PRNG from 0x2bf5575475144be3
5
6import NonFungibleToken from 0x1d7e57aa55817448
7import MetadataViews from 0x1d7e57aa55817448
8import ViewResolver from 0x1d7e57aa55817448
9
10// import "FungibleToken"
11
12// import "PRNG"
13
14access(all) contract BBCollectables: NonFungibleToken {
15
16 // pub let network: String
17
18 access(all) event ContractInitialized()
19
20 access(all) event CardCreated(cardID: UInt32, metadata: {String:String})
21 access(all) event PackCreated(packID: UInt32)
22
23 access(all) event CardAddedToPack(packID: UInt32, cardID: UInt32)
24 access(all) event CardRetiredFromPack(packID: UInt32, cardID: UInt32, numCards: UInt32)
25 access(all) event CardUnretiredFromPack(packID: UInt32, cardID: UInt32, numCards: UInt32)
26 access(all) event CardFinalized(cardID: UInt32)
27 access(all) event CardUnfinalized(cardID: UInt32)
28
29 access(all) event PackLocked(packID: UInt32)
30 access(all) event PackUnlocked(packID: UInt32)
31
32 access(all) event BlockPackMint(packID: UInt32)
33
34
35 access(all) event TicketMinted(packID: UInt32, serialNumber: UInt32)
36 access(all) event TicketSpent(id: UInt64, packID: UInt32, serialNumber: UInt32, content: [UInt32])
37 access(all) event TicketDestroyed(id: UInt64)
38
39 access(all) event BBNftMinted(BBNftID: UInt64, cardID: UInt32, packID: UInt32, serialNumber: UInt32)
40 access(all) event BBNftDestroyed(id: UInt64)
41
42
43 access(all) event Withdraw(id: UInt64, from: Address?)
44
45 access(all) event Deposit(id: UInt64, to: Address?)
46
47 access(all) let OrganiserName: String
48
49 access(all) let OrganiserStringIdentifier: String
50
51 access(all) let NftCollectionStoragePath: StoragePath
52 access(all) let NftCollectionPublicPath: PublicPath
53 access(all) let AdminStoragePath: StoragePath
54
55 access(self) var cardDatas: {UInt32: Card}
56
57 access(self) var packDatas: {UInt32: PackData}
58 access(self) var packs: @{UInt32: Pack}
59
60 access(all) var nextCardID: UInt32
61 access(all) var nextPackID: UInt32
62
63 access(all) var totalSupply: UInt64
64
65
66 access(all) struct Card {
67
68 access(all) let cardID: UInt32
69
70 access(all) var metadata: {String: String}
71
72 access(all) var packID: UInt32
73
74 access(all) var final: Bool
75
76 access(all) var finalizedTimestamp: UFix64
77
78 init(metadata: {String: String}) {
79 pre {
80 metadata.length != 0: "New Card metadata cannot be empty"
81 }
82 self.cardID = BBCollectables.nextCardID
83 // self.categories = categories
84 self.metadata = metadata
85
86 self.packID = 0
87
88 self.final = false
89
90 self.finalizedTimestamp = 0.0
91 }
92
93 access(contract) fun updateMetadata(newMetadata: {String: String}) {
94 pre {
95 self.final == false: "Cannot eddit finalized cards"
96 }
97 self.metadata = newMetadata // Modify the dictionary directly
98 }
99
100 access(contract) fun assignToPack(packID: UInt32) {
101 pre {
102 self.packID == 0: "Card already asigned to a pack"
103 }
104 self.packID = packID // Modify the dictionary directly
105 }
106
107 access(contract) fun finalizeCard() {
108 pre {
109 self.final == false: "Card already finalized"
110 }
111
112 self.final = true
113
114 self.finalizedTimestamp = getCurrentBlock().timestamp
115
116 emit CardFinalized(cardID: self.cardID)
117 }
118
119 access(contract) fun unfinalizeCard() {
120 pre {
121 self.final == true: "Card not yet finalized"
122 getCurrentBlock().timestamp - self.finalizedTimestamp < 604800.0: "Grace period expired"
123 }
124
125 self.final = false
126 self.finalizedTimestamp = 0.0
127
128 emit CardFinalized(cardID: self.cardID)
129 }
130 }
131
132 access(all) struct PackData {
133
134 access(all) let packID: UInt32
135
136 access(all) let name: String
137
138 init(name: String) {
139 pre {
140 name.length > 0: "New Pack name cannot be empty"
141 }
142 self.packID = BBCollectables.nextPackID
143 self.name = name
144 }
145 }
146
147 access(all) resource Pack {
148
149 access(all) var name: String
150
151 access(all) let packID: UInt32
152
153 // access(contract) var rarityDistribution: {String: UInt16}
154
155 access(contract) var cards: [UInt32]
156
157 access(contract) var retired: {UInt32: Bool}
158
159 access(all) var locked: Bool
160
161 access(contract) var mintCapPerCard: {UInt32: UInt32}
162
163 access(contract) var numberMintedPerCard: {UInt32: UInt32}
164
165 init(name: String) {
166 self.name = name
167 self.packID = BBCollectables.nextPackID
168 self.cards = []
169 self.retired = {}
170 self.locked = false
171 self.mintCapPerCard = {}
172 self.numberMintedPerCard = {}
173
174 BBCollectables.packDatas[self.packID] = PackData(name: name)
175 }
176
177 access(all) fun changeName(newName: String){
178 self.name = newName
179 }
180
181 access(all) fun addCard(cardID: UInt32, mintCap: UInt32) {
182
183 pre {
184 BBCollectables.cardDatas[cardID] != nil: "Cannot add the Card to Pack: Card doesn't exist"
185 !self.locked: "Cannot add the Card to the Pack after the Pack has been locked"
186 self.numberMintedPerCard[cardID] == nil: "The Card has already beed added to the Pack"
187 mintCap >= 0: "'maxCount' parameter must be 0 or higher"
188 }
189
190 self.cards.append(cardID)
191
192 self.retired[cardID] = false
193
194 self.mintCapPerCard[cardID] = mintCap
195
196 self.numberMintedPerCard[cardID] = 0
197
198 BBCollectables.cardDatas[cardID]!.assignToPack(packID: self.packID)
199
200 emit CardAddedToPack(packID: self.packID, cardID: cardID)
201 }
202
203 access(all) fun addCards(cardIDs: [UInt32], mintCaps: [UInt32]) {
204
205 var i = 0
206 while i < cardIDs.length {
207 self.addCard(cardID: cardIDs[i], mintCap: mintCaps[i])
208 i = i + 1
209 }
210 }
211
212
213 access(all) fun retireCard(cardID: UInt32) {
214 pre {
215 self.retired[cardID] != nil: "Cannot retire the Card: Card doesn't exist in this Pack!"
216 self.retired[cardID] == false: "Cannot retire the Card: Card already retired!"
217 !self.locked: "Cannot retire card: This Pack is locked."
218 }
219
220
221 if !self.retired[cardID]! {
222 self.retired[cardID] = true
223
224 emit CardRetiredFromPack(packID: self.packID, cardID: cardID, numCards: self.numberMintedPerCard[cardID]!)
225 }
226 }
227
228 access(all) fun unretireCard(cardID: UInt32) {
229 pre {
230 self.retired[cardID] != nil: "Cannot unretire the Card: Card doesn't exist in this Pack!"
231 self.retired[cardID] == true: "Cannot unretire the Card: Card must be retired!"
232 self.numberMintedPerCard[cardID]! < self.mintCapPerCard[cardID]! || self.mintCapPerCard[cardID]! == 0: "Cannot unretire the Card: Card has reached it's maximum mint cap!"
233 !self.locked: "Cannot unretire card: This Pack is locked."
234 }
235
236 if self.retired[cardID]! {
237 self.retired[cardID] = false
238
239 emit CardUnretiredFromPack(packID: self.packID, cardID: cardID, numCards: self.numberMintedPerCard[cardID]!)
240 }
241 }
242
243 access(all) fun retireAll() {
244 for card in self.cards {
245 self.retireCard(cardID: card)
246 }
247 }
248
249 access(all) fun lock() {
250 if !self.locked {
251 self.locked = true
252 emit PackLocked(packID: self.packID)
253 }
254 }
255
256 access(all) fun unlock() {
257 if self.locked {
258 self.locked = false
259 emit PackUnlocked(packID: self.packID)
260 }
261 }
262
263 access(all) fun mintBBNft(cardID: UInt32): @NFT {
264 pre {
265 self.retired[cardID] != nil: "Cannot mint the Card: This Card doesn't exist."
266 !self.retired[cardID]!: "Cannot mint the Card from this Pack: This Card has been retired."
267 self.numberMintedPerCard[cardID]! < self.mintCapPerCard[cardID]! || self.mintCapPerCard[cardID]! == 0: "Card has reached the maximum mint cap."
268 }
269
270 let numInCard = self.numberMintedPerCard[cardID]!
271
272 let newBBNft: @NFT <- create NFT(cardID: cardID,
273 packID: self.packID,
274 timestamp: getCurrentBlock().timestamp,
275 packIndex: UInt32(self.cards.firstIndex(of: cardID)!),
276 serialNumber: numInCard +1
277 )
278
279 self.numberMintedPerCard[cardID] = numInCard +1
280
281 if self.numberMintedPerCard[cardID]! >= self.mintCapPerCard[cardID]! && self.mintCapPerCard[cardID]! > 0 {
282 self.retireCard(cardID: cardID)
283 }
284
285 return <- newBBNft
286 }
287
288 access(all) fun batchMintBBNft(cardID: UInt32, quantity: UInt64): @Collection {
289 let newCollection <- create Collection()
290
291 var i: UInt64 = 0
292 while i < quantity {
293 newCollection.deposit(token: <-self.mintBBNft(cardID: cardID))
294 i = i +1
295 }
296
297 return <-newCollection
298 }
299
300 access(all) fun getCards(): [UInt32] {
301 return self.cards
302 }
303
304 access(all) fun getRetired(): {UInt32: Bool} {
305 return self.retired
306 }
307
308 access(all) fun getNumMintedPerCard(): {UInt32: UInt32} {
309 return self.numberMintedPerCard
310 }
311 }
312
313 access(all) struct QueryPackData {
314 access(all) let packID: UInt32
315 access(all) let name: String
316 access(all) var locked: Bool
317 access(self) var cards: &[UInt32]
318 access(self) var retired: &{UInt32: Bool}
319 access(self) var mintCapPerCard: &{UInt32: UInt32}
320 access(self) var numberMintedPerCard: &{UInt32: UInt32}
321
322
323 init(packID: UInt32) {
324 pre {
325 BBCollectables.packs[packID] != nil: "The Pack with the provided ID does not exist"
326 }
327
328 let pack= (&BBCollectables.packs[packID] as &Pack?)!
329 let packData = BBCollectables.packDatas[packID]!
330
331 self.packID = packID
332 self.name = packData.name
333 self.locked = pack.locked
334 self.cards = pack.cards
335 self.retired = pack.retired
336 self.mintCapPerCard = pack.mintCapPerCard
337 self.numberMintedPerCard = pack.numberMintedPerCard
338 }
339
340 access(all) fun getCards(): &[UInt32] {
341 return self.cards
342 }
343
344 access(all) fun getRetired(): &{UInt32: Bool} {
345 return self.retired
346 }
347
348 access(all) fun getNumberMintedPerCard(): &{UInt32: UInt32} {
349 return self.numberMintedPerCard
350 }
351 }
352
353 access(all) struct BBNftData {
354
355 access(all) let cardID: UInt32
356
357 access(all) let packID: UInt32
358
359 access(all) let timestamp: UFix64
360
361 access(all) let packIndex: UInt32
362
363 access(all) let serialNumber: UInt32
364
365
366 init(cardID: UInt32, packID: UInt32, timestamp: UFix64, packIndex:UInt32, serialNumber: UInt32) {
367 self.cardID = cardID
368 self.packID = packID
369 self.timestamp = timestamp
370 self.packIndex = packIndex
371 self.serialNumber = serialNumber
372 }
373 }
374
375 access(all) struct CustomMetadataView {
376
377 access(all) let fields: {String: AnyStruct}
378
379 init(fields: {String: AnyStruct}) {
380 self.fields = fields
381 }
382 }
383
384 access(all) resource NFT: NonFungibleToken.NFT {
385
386 access(all) let id: UInt64
387 access(all) let data: BBNftData
388
389 init(cardID: UInt32, packID: UInt32, timestamp: UFix64, packIndex: UInt32, serialNumber: UInt32) {
390
391 BBCollectables.totalSupply = BBCollectables.totalSupply +1
392
393 self.id = BBCollectables.totalSupply
394
395 self.data = BBNftData(cardID: cardID, packID: packID, timestamp: timestamp, packIndex: packIndex, serialNumber: serialNumber)
396
397 emit BBNftMinted(BBNftID: self.id, cardID: cardID, packID: self.data.packID, serialNumber: self.data.serialNumber)
398 }
399 access(all) event ResourceDestroyed(
400 id: UInt64 = self.id,
401 serialNumber: UInt32 = self.data.serialNumber,
402 cardID: UInt32 = self.data.cardID,
403 packID: UInt32 = self.data.packID
404 )
405
406 access(all) fun name(): String {
407 let cardName: String = BBCollectables.getCardMetaDataByField(cardID: self.data.cardID, field: "name") ?? ""
408 return cardName
409 }
410
411 access(all) fun description(): String {
412 let packName: String = BBCollectables.getPackName(packID: self.data.packID) ?? ""
413 let serialNumber: String = self.data.serialNumber.toString()
414 return "A pack "
415 .concat(packName)
416 .concat(" BBNft with serial number ")
417 .concat(serialNumber)
418 }
419
420 access(all) fun getCardURL(): String {
421 return "https://media.bluebite.tech/".concat(BBCollectables.OrganiserStringIdentifier).concat("/collectables/cards/").concat(BBCollectables.getCardMetaDataByField(cardID: self.data.cardID, field: "name")!).concat("/image.png")
422 }
423
424 access(all) fun getCardVideoURL(): String {
425 return "https://media.bluebite.tech/".concat(BBCollectables.OrganiserStringIdentifier).concat("/collectables/cards/").concat(BBCollectables.getCardMetaDataByField(cardID: self.data.cardID, field: "name")!).concat("/video.mp4")
426 }
427
428 access(all) fun mapCardData(dict: {String: AnyStruct}) : {String: AnyStruct} {
429 let cardMetadata = BBCollectables.getCardMetaData(cardID: self.data.cardID) ?? {}
430 for name in cardMetadata.keys {
431 let value = cardMetadata[name] ?? ""
432 if value != "" {
433 dict.insert(key: name, value)
434 }
435 }
436 return dict
437 }
438
439 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
440 return <- BBCollectables.createEmptyCollection(nftType: Type<@BBCollectables.NFT>())
441 }
442
443 access(all) view fun getViews(): [Type] {
444 return [
445 Type<MetadataViews.Display>(),
446 Type<CustomMetadataView>(),
447 // Type<MetadataViews.ExternalURL>(),
448 // Type<MetadataViews.NFTCollectionData>(),
449 // Type<MetadataViews.NFTCollectionDisplay>(),
450 Type<MetadataViews.Serial>(),
451 Type<MetadataViews.Traits>(),
452 Type<MetadataViews.Medias>()
453 ]
454 }
455
456 access(all) fun resolveView(_ view: Type): AnyStruct? {
457 switch view {
458 case Type<MetadataViews.Display>():
459 return MetadataViews.Display(
460 name: self.name(),
461 description: self.description(),
462 thumbnail: MetadataViews.HTTPFile(url: self.getCardURL())
463 )
464 case Type<CustomMetadataView>():
465 return CustomMetadataView(
466 fields: {
467 "name": BBCollectables.getCardMetaDataByField(cardID: self.data.cardID, field: "name"),
468 "description": BBCollectables.getCardMetaDataByField(cardID: self.data.cardID, field: "description"),
469 "rarity": BBCollectables.getCardMetaDataByField(cardID: self.data.cardID, field: "rarity"),
470 "date": BBCollectables.getCardMetaDataByField(cardID: self.data.cardID, field: "date"),
471
472 "media": [
473 MetadataViews.Media(
474 file: MetadataViews.HTTPFile(
475 url: self.getCardURL()
476 ),
477 mediaType: "image/png"
478 ),
479 MetadataViews.Media(
480 file: MetadataViews.HTTPFile(
481 url: self.getCardVideoURL()
482 ),
483 mediaType: "video/mp4"
484 )
485 ],
486
487 "cardID": self.data.cardID,
488 "packID": self.data.packID,
489 "timestamp": self.data.timestamp,
490 "packIndex": self.data.packIndex,
491 "serialNumber": self.data.serialNumber,
492 "numberMinted": BBCollectables.getPackData(packID: self.data.packID)!.getNumberMintedPerCard()[self.data.cardID]
493 }
494 )
495
496 case Type<MetadataViews.ExternalURL>():
497 return MetadataViews.ExternalURL(self.getCardURL())
498
499 case Type<MetadataViews.NFTCollectionData>():
500 return BBCollectables.resolveContractView(resourceType: nil, viewType: Type<MetadataViews.NFTCollectionData>())
501 case Type<MetadataViews.NFTCollectionDisplay>():
502 return BBCollectables.resolveContractView(resourceType: nil, viewType: Type<MetadataViews.NFTCollectionDisplay>())
503
504 case Type<MetadataViews.Serial>():
505 return MetadataViews.Serial(
506 UInt64(self.data.serialNumber)
507 )
508
509 case Type<MetadataViews.Traits>():
510 // sports radar team id
511 let excludedNames: [String] = ["timestamp"]
512 // non play specific traits
513 let traitDictionary: {String: AnyStruct} = {
514 "packName": BBCollectables.getPackName(packID: self.data.packID)
515 }
516 // add play specific data
517 let fullDictionary = self.mapCardData(dict: traitDictionary)
518 return MetadataViews.dictToTraits(dict: fullDictionary, excludedNames: excludedNames)
519
520 case Type<MetadataViews.Medias>():
521 return MetadataViews.Medias(
522 [
523 MetadataViews.Media(
524 file: MetadataViews.HTTPFile(
525 url: self.getCardURL()
526 ),
527 mediaType: "image/png"
528 ),
529 MetadataViews.Media(
530 file: MetadataViews.HTTPFile(
531 url: self.getCardVideoURL()
532 ),
533 mediaType: "video/mp4"
534 )
535 ]
536 )
537 }
538
539 return nil
540 }
541
542
543 }
544
545 access(all) resource Admin {
546
547 access(all) fun createCard( metadata: {String: String}, packID: UInt32, mintCap: UInt32): UInt32 {
548
549 pre {
550 metadata.containsKey("rarity") == true: "Metadata missing rarity field"
551 metadata.containsKey("name") == true: "Metadata missing name field"
552 metadata.containsKey("description") == true: "Metadata missing description field"
553 metadata.containsKey("date") == true: "Metadata missing date field"
554 }
555
556 for value in BBCollectables.cardDatas.values {
557 if value.metadata["name"] == metadata["name"] {
558 return 0
559 }
560 }
561
562 var newCard = Card(metadata: metadata)
563
564 let newID = newCard.cardID
565
566 BBCollectables.nextCardID = BBCollectables.nextCardID +1
567
568 BBCollectables.cardDatas[newID] = newCard
569
570 emit CardCreated(cardID: newCard.cardID, metadata: newCard.metadata)
571
572 self.borrowPack(packID: packID).addCard(cardID: newID, mintCap: mintCap)
573
574 return newID
575 }
576
577 access(all) fun editCard( cardID: UInt32, metadata: {String: String}) {
578
579 pre {
580 metadata.containsKey("rarity") == true: "Metadata missing rarity field"
581 metadata.containsKey("name") == true: "Metadata missing name field"
582 metadata.containsKey("description") == true: "Metadata missing description field"
583 metadata.containsKey("date") == true: "Metadata missing date field"
584 }
585
586 for key in BBCollectables.cardDatas.keys {
587 if key == cardID {
588 continue
589 }
590 if BBCollectables.cardDatas[key]!.metadata["name"] == metadata["name"] {
591 panic("Card name must be unique")
592 }
593 }
594
595 BBCollectables.cardDatas[cardID]!.updateMetadata(newMetadata: metadata)
596 }
597
598
599 access(all) fun updateCardMetadata(cardID: UInt32, newMetadata: {String: String}) {
600 let card = BBCollectables.cardDatas[cardID] ?? panic("Card does not exist")
601 card.updateMetadata(newMetadata: newMetadata)
602 }
603
604 access(all) fun finalizeCard(cardID: UInt32) {
605 let card = BBCollectables.cardDatas[cardID] ?? panic("Card does not exist")
606 card.finalizeCard()
607 }
608
609 access(all) fun unfinalizeCard(cardID: UInt32, newMetadata: {String: String}) {
610 let card = BBCollectables.cardDatas[cardID] ?? panic("Card does not exist")
611 card.unfinalizeCard()
612 }
613
614 access(all) fun createPack(name: String): UInt32 {
615
616 var newPack <- create Pack(name: name)
617
618 BBCollectables.nextPackID = BBCollectables.nextPackID +1
619
620 let newID = newPack.packID
621
622 emit PackCreated(packID: newPack.packID)
623
624 BBCollectables.packs[newID] <-! newPack
625
626 return newID
627 }
628
629 access(all) fun borrowPack(packID: UInt32): &Pack {
630 pre {
631 BBCollectables.packs[packID] != nil: "Cannot borrow Pack: The Pack doesn't exist"
632 }
633
634 return (&BBCollectables.packs[packID] as &Pack?)!
635 }
636
637 access(all) fun createNewAdmin(): @Admin {
638 return <-create Admin()
639 }
640 }
641
642 access(all) resource interface BBNftCollectionPublic : NonFungibleToken.CollectionPublic {
643 access(all) fun batchDeposit(tokens: @{NonFungibleToken.Collection})
644 access(all) fun borrowBBNft(id: UInt64): &BBCollectables.NFT? {
645 // If the result isn't nil, the id of the returned reference
646 // should be the same as the argument to the function
647 post {
648 (result == nil) || (result?.id == id):
649 "Cannot borrow Card reference: The ID of the returned reference is incorrect"
650 }
651 }
652 }
653
654 access(all) resource Collection: BBNftCollectionPublic, NonFungibleToken.Collection {
655
656 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
657
658 init() {
659 self.ownedNFTs <- {}
660 }
661
662 // Return a list of NFT types that this receiver accepts
663 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
664 let supportedTypes: {Type: Bool} = {}
665 supportedTypes[Type<@BBCollectables.NFT>()] = true
666 return supportedTypes
667 }
668
669 // Return whether or not the given type is accepted by the collection
670 // A collection that can accept any type should just return true by default
671 access(all) view fun isSupportedNFTType(type: Type): Bool {
672 if type == Type<@BBCollectables.NFT>() {
673 return true
674 }
675 return false
676 }
677
678 // Return the amount of NFTs stored in the collection
679 access(all) view fun getLength(): Int {
680 return self.ownedNFTs.length
681 }
682
683 // Create an empty Collection for TopShot NFTs and return it to the caller
684 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
685 return <- BBCollectables.createEmptyCollection(nftType: Type<@BBCollectables.NFT>())
686 }
687
688 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
689
690 let token <- self.ownedNFTs.remove(key: withdrawID)
691 ?? panic("Cannot withdraw: Card does not exist in the collection")
692
693 emit Withdraw(id: token.id, from: self.owner?.address)
694
695 return <-token
696 }
697
698 access(NonFungibleToken.Withdraw) fun batchWithdraw(ids: [UInt64]): @{NonFungibleToken.Collection} {
699 var batchCollection <- create Collection()
700
701 for id in ids {
702 batchCollection.deposit(token: <-self.withdraw(withdrawID: id))
703 }
704
705 return <-batchCollection
706 }
707 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
708
709
710 let token <- token as! @BBCollectables.NFT
711
712 let id = token.id
713
714 let oldToken <- self.ownedNFTs[id] <- token
715
716 if self.owner?.address != nil {
717 emit Deposit(id: id, to: self.owner?.address)
718 }
719
720 destroy oldToken
721 }
722
723 access(all) fun batchDeposit(tokens: @{NonFungibleToken.Collection}) {
724
725 let keys = tokens.getIDs()
726
727 for key in keys {
728 self.deposit(token: <-tokens.withdraw(withdrawID: key))
729 }
730
731 destroy tokens
732 }
733
734 access(all) view fun getIDs(): [UInt64] {
735 return self.ownedNFTs.keys
736 }
737
738 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
739 return &self.ownedNFTs[id]
740 }
741
742 access(all) view fun borrowBBNft(id: UInt64): &BBCollectables.NFT? {
743 return self.borrowNFT(id) as! &BBCollectables.NFT?
744 }
745
746 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
747 if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
748 // let BBNFT = nft as! &BBCollectables.NFT
749 return nft as &{ViewResolver.Resolver}
750 }
751 return nil
752 }
753 }
754
755 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
756 if nftType != Type<@BBCollectables.NFT>() {
757 panic("NFT type is not supported")
758 }
759 return <-create BBCollectables.Collection()
760 }
761
762 access(all) view fun getAllCards(): {UInt32: BBCollectables.Card} {
763 return BBCollectables.cardDatas
764 }
765
766
767 access(all) view fun getAllPacks(): {UInt32: BBCollectables.PackData} {
768 return BBCollectables.packDatas
769 }
770
771 access(all) view fun getCardMetaData(cardID: UInt32): {String: String}? {
772 return self.cardDatas[cardID]?.metadata
773 }
774
775 access(all) view fun getCard(cardID: UInt32): BBCollectables.Card? {
776 return self.cardDatas[cardID]
777 }
778
779 access(all) view fun getCardMetaDataByField(cardID: UInt32, field: String): String? {
780 if let card = BBCollectables.cardDatas[cardID] {
781 return card.metadata[field]
782 } else {
783 return nil
784 }
785 }
786
787 access(all) fun getPackData(packID: UInt32): QueryPackData? {
788 if BBCollectables.packs[packID] == nil {
789 return nil
790 } else {
791 return QueryPackData(packID: packID)
792 }
793 }
794
795 access(all) view fun getPackName(packID: UInt32): String? {
796 return BBCollectables.packDatas[packID]?.name
797 }
798
799 access(all) fun getPackIDsByName(packName: String): [UInt32]? {
800 var packIDs: [UInt32] = []
801
802 for packData in BBCollectables.packDatas.values {
803 if packName == packData.name {
804
805 packIDs.append(packData.packID)
806 }
807 }
808
809 if packIDs.length == 0 {
810 return nil
811 } else {
812 return packIDs
813 }
814 }
815
816 access(all) view fun getCardsInPack(packID: UInt32): [UInt32]? {
817
818 return BBCollectables.packs[packID]?.cards
819 }
820
821 access(all) view fun isPackLocked(packID: UInt32): Bool? {
822 return BBCollectables.packs[packID]?.locked
823 }
824
825 //------------------------------------------------------------
826 // Contract MetadataViews
827 //------------------------------------------------------------
828 access(all) view fun getContractViews(resourceType: Type?): [Type] {
829 return [Type<MetadataViews.NFTCollectionData>(), Type<MetadataViews.NFTCollectionDisplay>(), Type<MetadataViews.Royalties>()]
830 }
831
832 /// Resolve this contract's metadata views
833 access(all) view fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
834 post {
835 result == nil || result!.getType() == viewType: "The returned view must be of the given type or nil"
836 }
837 switch viewType {
838 case Type<MetadataViews.NFTCollectionData>():
839 return MetadataViews.NFTCollectionData(
840 storagePath: /storage/BBNFTCollection,
841 publicPath: /public/BBNFTCollection,
842 publicCollection: Type<&BBCollectables.Collection>(),
843 publicLinkedType: Type<&BBCollectables.Collection>(),
844 createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
845 return <-BBCollectables.createEmptyCollection(nftType: Type<@BBCollectables.NFT>())
846 })
847 )
848 case Type<MetadataViews.NFTCollectionDisplay>():
849 let bannerImage = MetadataViews.Media(
850 file: MetadataViews.HTTPFile(
851 url: "https://media.bluebite.tech/placeholder/collectables/banner.png"
852 ),
853 mediaType: "image/png"
854 )
855 let squareImage = MetadataViews.Media(
856 file: MetadataViews.HTTPFile(
857 url: "https://media.bluebite.tech/placeholder/collectables/square.png"
858 ),
859 mediaType: "image/png"
860 )
861
862 return MetadataViews.NFTCollectionDisplay(
863 name: "Bluebite Collectables Collection".concat(" - ").concat(BBCollectables.OrganiserName),
864 description: "Viva seus momentos - Feito com 💛 na Bluebite",
865 externalURL: MetadataViews.ExternalURL("https://media.bluebite.tech/"),
866 squareImage: squareImage,
867 bannerImage: bannerImage,
868 socials: {
869 "instagram": MetadataViews.ExternalURL("https://www.instagram.com/richmond_fc/")
870 }
871 )
872 }
873 return nil
874 }
875
876
877 init() {
878
879 // self.network = "testnet"
880
881 self.OrganiserName = "Urubus"
882
883 self.OrganiserStringIdentifier = "urubus"
884
885 self.cardDatas = {}
886 self.packDatas = {}
887 self.packs <- {}
888 self.nextCardID = 1
889 self.nextPackID = 1
890 self.totalSupply = 0
891
892 self.NftCollectionStoragePath = /storage/urubus
893 self.NftCollectionPublicPath = /public/urubus
894 self.AdminStoragePath = /storage/urubusAdmin
895
896 self.account.storage.save<@Collection>(<- create Collection(), to: self.NftCollectionStoragePath)
897
898 let cap = self.account.capabilities.storage.issue<&BBCollectables.Collection>(self.NftCollectionStoragePath)
899 self.account.capabilities.publish(cap, at: self.NftCollectionPublicPath)
900 // self.account.link<&BBCollectables.Collection{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>(self.NftCollectionPublicPath, target: self.NftCollectionStoragePath)
901
902 let adminResource: @BBCollectables.Admin <- create Admin()
903
904 self.account.storage.save<@Admin>(<- adminResource, to: self.AdminStoragePath)
905
906 emit ContractInitialized()
907
908
909 }
910}
911