Smart Contract
Wine
A.fb27085fbb495d1d.Wine
1// SPDX-License-Identifier: UNLICENSED
2
3import NonFungibleToken from 0x1d7e57aa55817448
4import MetadataViews from 0x1d7e57aa55817448
5
6pub contract Wine: NonFungibleToken {
7 // Emitted when the Wine contract is created
8 pub event ContractInitialized()
9
10 // Emitted when a new Set is created
11 pub event SetCreated(id: UInt64, name: String)
12 // Emitted when a Set is locked, meaning Set data cannot be updated
13 pub event SetLocked(id: UInt64, name: String)
14 // Emitted when a Set is unlocked, meaning Set data can be updated
15 pub event SetUnlocked(id: UInt64, name: String)
16 // Emitted when a Set is updated
17 pub event SetUpdated(id: UInt64, name: String)
18
19 // Emitted when a new Template is created
20 pub event TemplateCreated(id: UInt64, name: String)
21 // Emitted when a Template is locked, meaning Template data cannot be updated
22 pub event TemplateLocked(id: UInt64, name: String)
23 // Emitted when a Template is updated
24 pub event TemplateUpdated(id: UInt64, name: String)
25 // Emitted when a Template is added to a Set
26 pub event TemplateAddedToSet(id: UInt64, name: String, setID: UInt64, setName: String)
27
28 // Emitted when an NFT is minted
29 pub event Minted(id: UInt64, templateID: UInt64, setID: UInt64)
30 // Emitted when an NFT is withdrawn from a Collection
31 pub event Withdraw(id: UInt64, from: Address?)
32 // Emitted when an NFT is deposited into a Collection
33 pub event Deposit(id: UInt64, to: Address?)
34
35 pub let CollectionStoragePath: StoragePath
36 pub let CollectionPublicPath: PublicPath
37 pub let AdminStoragePath: StoragePath
38 pub let AdminPrivatePath: PrivatePath
39
40 // The total number of Wine NFT that have been minted
41 pub var totalSupply: UInt64
42 pub var nextTemplateID: UInt64
43 pub var nextSetID: UInt64
44
45 // Variable size dictionary of Template structs
46 access(self) var Templates: {UInt64: Template}
47
48 // Variable size dictionary of SetData structs
49 access(self) var SetsData: {UInt64: SetData}
50
51 // Variable size dictionary of Set resources
52 access(self) var sets: @{UInt64: Set}
53
54 // An Template is a Struct that holds data associated with a specific NFT
55 pub struct Template {
56 pub let id: UInt64
57
58 pub var name: String
59 pub var description: String
60 pub var image: String
61
62 pub var maxSupply: UInt64
63
64 pub var locked: Bool
65 pub var addedToSet: UInt64
66
67 access(self) var metadata: {String: AnyStruct}
68
69 init(id: UInt64, name: String, description: String, image: String, maxSupply: UInt64, metadata: {String: AnyStruct}){
70 pre {
71 maxSupply > 0: "Supply must be more than zero"
72 metadata.length != 0: "New template metadata cannot be empty"
73 }
74
75 self.id = id
76 self.name = name
77 self.description = description
78 self.image = image
79 self.metadata = metadata
80 self.maxSupply = maxSupply
81 self.locked = false
82 self.addedToSet = 0
83
84 Wine.nextTemplateID = Wine.nextTemplateID + 1
85
86 emit TemplateCreated(id: self.id, name: self.name)
87 }
88
89 pub fun updateName(newName: String) {
90 pre {
91 self.locked == false: "Cannot update name: template is locked"
92 }
93
94 self.name = newName
95 emit TemplateUpdated(id: self.id, name: self.name)
96 }
97
98 pub fun updateDescription(newDescription: String) {
99 pre {
100 self.locked == false: "Cannot update description: template is locked"
101 }
102
103 self.description = newDescription
104 emit TemplateUpdated(id: self.id, name: self.name)
105 }
106
107 pub fun updateImage(newImage: String) {
108 pre {
109 self.locked == false: "Cannot update image: template is locked"
110 }
111
112 self.image = newImage
113 emit TemplateUpdated(id: self.id, name: self.name)
114 }
115
116 pub fun updateMaxSupply(newMaxSupply: UInt64) {
117 pre {
118 self.locked == false: "Cannot update image: template is locked"
119 self.maxSupply > newMaxSupply: "Cannot reduce max supply"
120 }
121
122 self.maxSupply = newMaxSupply
123 emit TemplateUpdated(id: self.id, name: self.name)
124 }
125
126 pub fun updateMetadata(newMetadata: {String: AnyStruct}) {
127 pre {
128 self.locked == false: "Cannot update metadata: template is locked"
129 newMetadata.length != 0: "New template metadata cannot be empty"
130 }
131
132 self.metadata = newMetadata
133 emit TemplateUpdated(id: self.id, name: self.name)
134 }
135
136 pub fun markAddedToSet(setID: UInt64) {
137 pre {
138 self.addedToSet == 0: "Template is already to a set"
139 }
140
141 self.addedToSet = setID
142
143 let setName = Wine.SetsData[setID]!.name
144 emit TemplateAddedToSet(id: self.id, name: self.name, setID: setID, setName: setName)
145 }
146
147 pub fun lock() {
148 pre {
149 self.locked == false: "Template is already locked"
150 }
151
152 self.locked = true
153 emit TemplateLocked(id: self.id, name: self.name)
154 }
155
156 pub fun getMetadata(): {String: AnyStruct} {
157 return self.metadata
158 }
159 }
160
161 // An SetData is a Struct that holds data associated with a specific Set
162 pub struct SetData {
163 pub let id: UInt64
164
165 pub var name: String
166 pub var description: String
167 pub var image: String
168
169 access(self) var metadata: {String: AnyStruct}
170
171 init(id: UInt64, name: String, description: String, image: String, metadata: {String: AnyStruct}) {
172 self.id = id
173 self.name = name
174 self.description = description
175 self.image = image
176 self.metadata = metadata
177 }
178
179 pub fun getMetadata(): {String: AnyStruct} {
180 return self.metadata
181 }
182 }
183
184 // A resource that represents the Wine NFT
185 pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
186 pub let id: UInt64
187
188 pub let setID: UInt64
189 pub let templateID: UInt64
190 pub let editionNumber: UInt64
191 pub let serialNumber: UInt64
192 pub let mintingDate: UFix64
193
194 init(id: UInt64, templateID: UInt64, editionNumber: UInt64, serialNumber: UInt64) {
195 pre {
196 Wine.getTemplate(id: templateID) != nil: "Template not found"
197 }
198
199 let setID = Wine.getTemplate(id: templateID)!.addedToSet
200
201 self.id = id
202 self.setID = setID
203 self.templateID = templateID
204 self.editionNumber = editionNumber
205 self.serialNumber = serialNumber
206 self.mintingDate = getCurrentBlock().timestamp
207 }
208
209 pub fun getViews(): [Type] {
210 return [
211 Type<MetadataViews.Display>(),
212 Type<MetadataViews.Serial>(),
213 Type<MetadataViews.Royalties>(),
214 Type<MetadataViews.ExternalURL>(),
215 Type<MetadataViews.Editions>(),
216 Type<MetadataViews.Traits>(),
217 Type<MetadataViews.NFTCollectionData>(),
218 Type<MetadataViews.NFTCollectionDisplay>()
219 ]
220 }
221
222 pub fun resolveView(_ view: Type): AnyStruct? {
223 switch view {
224 case Type<MetadataViews.Display>():
225 let nftName = self.getTemplate().name.concat(" #").concat(self.editionNumber.toString())
226 return MetadataViews.Display(
227 name: nftName,
228 description: self.getTemplate().description,
229 thumbnail: MetadataViews.HTTPFile(
230 url: self.getTemplate().image
231 )
232 )
233 case Type<MetadataViews.Serial>():
234 return MetadataViews.Serial(
235 self.serialNumber
236 )
237 case Type<MetadataViews.Royalties>():
238 var royalties: [MetadataViews.Royalty] = []
239 return MetadataViews.Royalties(royalties)
240 case Type<MetadataViews.ExternalURL>():
241 return MetadataViews.ExternalURL(self.getExternalUrl())
242 case Type<MetadataViews.Editions>():
243 let template = Wine.Templates[self.templateID]!
244 let editionInfo = MetadataViews.Edition(
245 name: template.name,
246 number: self.editionNumber,
247 max: template.maxSupply
248 )
249 let editionList: [MetadataViews.Edition] = [editionInfo]
250 return MetadataViews.Editions(
251 editionList
252 )
253 case Type<MetadataViews.Traits>():
254 let excludedTraits = ["external_base_url"]
255 let traitsView = MetadataViews.dictToTraits(dict: self.getMetadata(), excludedNames: excludedTraits)
256
257 // mintingDate is a unix timestamp, we should mark it with a displayType so platforms know how to show it
258 let mintingDateTrait = MetadataViews.Trait(name: "minting_date", value: self.mintingDate, displayType: "Date", rarity: nil)
259 traitsView.addTrait(mintingDateTrait)
260
261 return traitsView
262 case Type<MetadataViews.NFTCollectionData>():
263 return MetadataViews.NFTCollectionData(
264 storagePath: Wine.CollectionStoragePath,
265 publicPath: Wine.CollectionPublicPath,
266 providerPath: /private/WineCollection,
267 publicCollection: Type<&Wine.Collection{Wine.NFTCollectionPublic}>(),
268 publicLinkedType: Type<&Wine.Collection{Wine.NFTCollectionPublic, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(),
269 providerLinkedType: Type<&Wine.Collection{Wine.NFTCollectionPublic, NonFungibleToken.CollectionPublic, NonFungibleToken.Provider, MetadataViews.ResolverCollection}>(),
270 createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
271 return <- Wine.createEmptyCollection()
272 })
273 )
274 case Type<MetadataViews.NFTCollectionDisplay>():
275 let setData = Wine.SetsData[self.setID]!
276 let squareImageUrl = setData.getMetadata()["image.media_type"] as! String?
277 return MetadataViews.NFTCollectionDisplay(
278 name: setData.name,
279 description: setData.description,
280 externalURL: MetadataViews.ExternalURL(
281 url: (setData.getMetadata()["external_url"] as! String?)!
282 ),
283 squareImage: MetadataViews.Media(
284 file: MetadataViews.HTTPFile(
285 url: setData.image
286 ),
287 mediaType: squareImageUrl ?? "image/jpeg"
288 ),
289 bannerImage: MetadataViews.Media(
290 file: MetadataViews.HTTPFile(
291 url: (setData.getMetadata()["banner_image.url"] as! String?)!
292 ),
293 mediaType: (setData.getMetadata()["banner_image.media_type"] as! String?)!
294 ),
295 socials: {
296 "twitter": MetadataViews.ExternalURL(
297 url: "https://twitter.com/cuveecollective"
298 ),
299 "instagram": MetadataViews.ExternalURL(
300 url: "https://twitter.com/cuveecollectivehq"
301 ),
302 "discord": MetadataViews.ExternalURL(
303 url: "https://cuveecollective.com/discord"
304 )
305 }
306 )
307 }
308
309 return nil
310 }
311
312 pub fun getSetData(): SetData {
313 return Wine.SetsData[self.setID]!
314 }
315
316 pub fun getTemplate(): Template {
317 return Wine.Templates[self.templateID]!
318 }
319
320 pub fun getMetadata(): {String: AnyStruct} {
321 return Wine.Templates[self.templateID]!.getMetadata()
322 }
323
324 pub fun getExternalUrl(): String {
325 let template = self.getTemplate()
326 let extBaseUrl = template.getMetadata()["external_base_url"] as! String?
327 return extBaseUrl!.concat("/").concat(template.id.toString())
328 }
329 }
330
331 pub resource interface NFTCollectionPublic {
332 pub fun deposit(token: @NonFungibleToken.NFT)
333 pub fun getIDs(): [UInt64]
334 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
335 pub fun borrowWine(id: UInt64): &Wine.NFT? {
336 post {
337 (result == nil) || (result?.id == id):
338 "Cannot borrow wine reference: the ID of the returned reference is incorrect"
339 }
340 }
341 }
342
343 pub resource Collection: NFTCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection {
344 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
345
346 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
347 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Missing NFT")
348 emit Withdraw(id: token.id, from: self.owner?.address)
349 return <-token
350 }
351
352 pub fun deposit(token: @NonFungibleToken.NFT) {
353 let token <- token as! @Wine.NFT
354 let id: UInt64 = token.id
355 let oldToken <- self.ownedNFTs[id] <- token
356 emit Deposit(id: id, to: self.owner?.address)
357 destroy oldToken
358 }
359
360 pub fun batchDeposit(collection: @Collection) {
361 let keys = collection.getIDs()
362 for key in keys {
363 self.deposit(token: <-collection.withdraw(withdrawID: key))
364 }
365 destroy collection
366 }
367
368 pub fun getIDs(): [UInt64] {
369 return self.ownedNFTs.keys
370 }
371
372 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
373 let ref = &self.ownedNFTs[id] as &NonFungibleToken.NFT?
374 return ref!
375 }
376
377 pub fun borrowWine(id: UInt64): &Wine.NFT? {
378 if self.ownedNFTs[id] != nil {
379 let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
380 return ref! as! &Wine.NFT
381 } else {
382 return nil
383 }
384 }
385
386 pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
387 let nft = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
388 let wineNFT = nft! as! &Wine.NFT
389 return wineNFT as &AnyResource{MetadataViews.Resolver}
390 }
391
392 destroy() {
393 destroy self.ownedNFTs
394 }
395
396 init() {
397 self.ownedNFTs <- {}
398 }
399 }
400
401 pub fun createEmptyCollection(): @NonFungibleToken.Collection {
402 return <- create Collection()
403 }
404
405 // A Set is special resource type that contains functions to mint Wine NFTs,
406 // add Templates, update Templates and Set metadata, and lock Sets and Templates.
407 pub resource Set {
408 pub let id: UInt64
409
410 pub var locked: Bool
411 pub var isPublic: Bool
412 pub var nextSerialNumber: UInt64
413
414 access(self) var templateIDs: [UInt64]
415 access(self) var templateSupplies: {UInt64: UInt64}
416
417 init(name: String, description: String, image: String, metadata: {String: AnyStruct}) {
418 pre {
419 metadata.length != 0: "Set metadata cannot be empty"
420 }
421
422 self.id = Wine.nextSetID
423
424 self.locked = false
425 self.isPublic = false
426 self.nextSerialNumber = 1
427
428 self.templateIDs = []
429 self.templateSupplies = {}
430
431 Wine.SetsData[self.id] = SetData(
432 id: self.id,
433 name: name,
434 description: description,
435 image: image,
436 metadata: metadata
437 )
438
439 Wine.nextSetID = Wine.nextSetID + 1
440
441 emit SetCreated(id: self.id, name: name)
442 }
443
444 pub fun updateImage(newImage: String) {
445 pre {
446 self.locked == false: "Cannot update image: set is locked"
447 }
448
449 let oldData = Wine.SetsData[self.id]!
450
451 Wine.SetsData[self.id] = SetData(
452 id: self.id,
453 name: oldData.name,
454 description: oldData.description,
455 image: newImage,
456 metadata: oldData.getMetadata()
457 )
458
459 emit SetUpdated(id: self.id, name: oldData.name)
460 }
461
462 pub fun updateMetadata(newMetadata: {String: AnyStruct}) {
463 pre {
464 self.locked == false: "Cannot update metadata: set is locked"
465 newMetadata.length != 0: "New set metadata cannot be empty"
466 }
467
468 let oldData = Wine.SetsData[self.id]!
469
470 Wine.SetsData[self.id] = SetData(
471 id: self.id,
472 name: oldData.name,
473 description: oldData.description,
474 image: oldData.image,
475 metadata: newMetadata
476 )
477
478 emit SetUpdated(id: self.id, name: oldData.name)
479 }
480
481 pub fun makePublic() {
482 pre {
483 self.isPublic == false: "Set is already public"
484 }
485
486 self.isPublic = true
487 }
488
489 pub fun makePrivate() {
490 pre {
491 self.isPublic == true: "Set is already private"
492 }
493
494 self.isPublic = false
495 }
496
497 pub fun addTemplate(id: UInt64) {
498 pre {
499 Wine.Templates[id] != nil:
500 "Template doesn't exist"
501 !self.locked:
502 "Cannot add template: set is locked"
503 !self.templateIDs.contains(id):
504 "Cannot add template: template is already added to the set"
505 !(Wine.Templates[id]!.addedToSet != 0):
506 "Cannot add template: template is already added to another set"
507 }
508
509 self.templateIDs.append(id)
510 self.templateSupplies[id] = 0
511
512 // This function will automatically emit TemplateAddedToSet event
513 Wine.Templates[id]!.markAddedToSet(setID: self.id)
514 }
515
516 pub fun addTemplates(templateIDs: [UInt64]) {
517 for templateID in templateIDs {
518 self.addTemplate(id: templateID)
519 }
520 }
521
522 pub fun lock() {
523 pre {
524 self.locked == false: "Set is already locked"
525 }
526
527 self.locked = true
528 emit SetLocked(id: self.id, name: Wine.SetsData[self.id]!.name)
529 }
530
531 pub fun unlock() {
532 pre {
533 self.locked == true: "Set is already unlocked"
534 }
535
536 self.locked = false
537 emit SetUnlocked(id: self.id, name: Wine.SetsData[self.id]!.name)
538 }
539
540 pub fun mintNFT(templateID: UInt64): @NFT {
541 let nextEditionNumber = self.templateSupplies[templateID]! + 1
542
543 if nextEditionNumber >= Wine.Templates[templateID]!.maxSupply {
544 panic("Supply unavailable")
545 }
546
547 let newNFT: @NFT <- create Wine.NFT(
548 id: Wine.totalSupply + 1,
549 templateID: templateID,
550 editionNumber: nextEditionNumber,
551 serialNumber: self.nextSerialNumber
552 )
553
554 Wine.totalSupply = Wine.totalSupply + 1
555 self.nextSerialNumber = self.nextSerialNumber + 1
556 self.templateSupplies[templateID] = self.templateSupplies[templateID]! + 1
557
558 emit Minted(id: newNFT.id, templateID: newNFT.templateID, setID: newNFT.setID)
559 return <- newNFT
560 }
561
562 pub fun updateTemplateName(id: UInt64, newName: String) {
563 pre {
564 Wine.Templates[id] != nil:
565 "Template doesn't exist"
566 self.templateIDs.contains(id):
567 "Cannot edit template: template is not part of this set"
568 !self.locked:
569 "Cannot edit template: set is locked"
570 }
571
572 // This function will automatically emit TemplateUpdated event
573 Wine.Templates[id]!.updateName(newName: newName)
574 }
575
576 pub fun updateTemplateDescription(id: UInt64, newDescription: String) {
577 pre {
578 Wine.Templates[id] != nil:
579 "Template doesn't exist"
580 self.templateIDs.contains(id):
581 "Cannot edit template: template is not part of this set"
582 !self.locked:
583 "Cannot edit template: set is locked"
584 }
585
586 // This function will automatically emit TemplateUpdated event
587 Wine.Templates[id]!.updateDescription(newDescription: newDescription)
588 }
589
590 pub fun updateTemplateImage(id: UInt64, newImage: String) {
591 pre {
592 Wine.Templates[id] != nil:
593 "Template doesn't exist"
594 self.templateIDs.contains(id):
595 "Cannot edit template: template is not part of this set"
596 !self.locked:
597 "Cannot edit template: set is locked"
598 }
599
600 // This function will automatically emit TemplateUpdated event
601 Wine.Templates[id]!.updateImage(newImage: newImage)
602 }
603
604 pub fun updateTemplateMaxSupply(id: UInt64, newMaxSupply: UInt64) {
605 pre {
606 Wine.Templates[id] != nil:
607 "Template doesn't exist"
608 self.templateIDs.contains(id):
609 "Cannot edit template: template is not part of this set"
610 !self.locked:
611 "Cannot edit template: set is locked"
612 }
613
614 // This function will automatically emit TemplateUpdated event
615 Wine.Templates[id]!.updateMaxSupply(newMaxSupply: newMaxSupply)
616 }
617
618 pub fun updateTemplateMetadata(id: UInt64, newMetadata: {String: AnyStruct}) {
619 pre {
620 Wine.Templates[id] != nil:
621 "Template doesn't exist"
622 self.templateIDs.contains(id):
623 "Cannot edit template: template is not part of this set"
624 !self.locked:
625 "Cannot edit template: set is locked"
626 }
627
628 // This function will automatically emit TemplateUpdated event
629 Wine.Templates[id]!.updateMetadata(newMetadata: newMetadata)
630 }
631
632 pub fun lockTemplate(id: UInt64) {
633 pre {
634 Wine.Templates[id] != nil:
635 "Template doesn't exist"
636 self.templateIDs.contains(id):
637 "Cannot lock template: template is not part of this set"
638 !self.locked:
639 "Cannot lock template: set is locked"
640 }
641
642 // This function will automatically emit TemplateLocked event
643 Wine.Templates[id]!.lock()
644 }
645
646 pub fun getMetadata(): {String: AnyStruct} {
647 return Wine.SetsData[self.id]!.getMetadata()
648 }
649
650 pub fun getTemplateIDs(): [UInt64] {
651 return self.templateIDs
652 }
653 }
654
655 pub resource Admin {
656 pub fun mintNFT(recipient: &{NonFungibleToken.CollectionPublic}, setID: UInt64, templateID: UInt64) {
657 let set = self.borrowSet(id: setID)
658 if (set.getTemplateIDs().length == 0){
659 panic("Set is empty")
660 }
661 recipient.deposit(token: <- set.mintNFT(templateID: templateID))
662 }
663
664 pub fun createTemplate(name: String, description: String, image: String, maxSupply: UInt64, metadata: {String: AnyStruct}): UInt64 {
665 let templateID = Wine.nextTemplateID
666
667 // This function will automatically emit TemplateCreated event
668 Wine.Templates[templateID] = Template(
669 id: templateID,
670 name: name,
671 description: description,
672 image: image,
673 maxSupply: maxSupply,
674 metadata: metadata
675 )
676
677 return templateID
678 }
679
680 pub fun updateTemplateName(id: UInt64, newName: String) {
681 pre {
682 Wine.Templates.containsKey(id) != nil:
683 "Template doesn't exits"
684 }
685
686 // This function will automatically emit TemplateUpdated event
687 Wine.Templates[id]!.updateName(newName: newName)
688 }
689
690 pub fun updateTemplateDescription(id: UInt64, newDescription: String) {
691 pre {
692 Wine.Templates.containsKey(id) != nil:
693 "Template doesn't exits"
694 }
695
696 // This function will automatically emit TemplateUpdated event
697 Wine.Templates[id]!.updateDescription(newDescription: newDescription)
698 }
699
700 pub fun updateTemplateImage(id: UInt64, newImage: String) {
701 pre {
702 Wine.Templates.containsKey(id) != nil:
703 "Template doesn't exits"
704 }
705
706 // This function will automatically emit TemplateUpdated event
707 Wine.Templates[id]!.updateImage(newImage: newImage)
708 }
709
710 pub fun updateTemplateMaxSupply(id: UInt64, newMaxSupply: UInt64) {
711 pre {
712 Wine.Templates.containsKey(id) != nil:
713 "Template doesn't exits"
714 }
715
716 // This function will automatically emit TemplateUpdated event
717 Wine.Templates[id]!.updateMaxSupply(newMaxSupply: newMaxSupply)
718 }
719
720 pub fun updateTemplateMetadata(id: UInt64, newMetadata: {String: String}) {
721 pre {
722 Wine.Templates.containsKey(id) != nil:
723 "Template doesn't exits"
724 }
725
726 // This function will automatically emit TemplateUpdated event
727 Wine.Templates[id]!.updateMetadata(newMetadata: newMetadata)
728 }
729
730 pub fun lockTemplate(id: UInt64) {
731 pre {
732 Wine.Templates.containsKey(id) != nil:
733 "Template doesn't exits"
734 }
735
736 // This function will automatically emit TemplateLocked event
737 Wine.Templates[id]!.lock()
738 }
739
740 pub fun createSet(name: String, description: String, image: String, metadata: {String: String}) {
741 var newSet <- create Set(
742 name: name,
743 description: description,
744 image: image,
745 metadata: metadata
746 )
747 Wine.sets[newSet.id] <-! newSet
748 }
749
750 pub fun borrowSet(id: UInt64): &Set {
751 pre {
752 Wine.sets[id] != nil: "Cannot borrow set: set doesn't exist"
753 }
754
755 let ref = &Wine.sets[id] as &Set?
756 return ref!
757 }
758
759 pub fun updateSetImage(id: UInt64, newImage: String) {
760 let set = self.borrowSet(id: id)
761 set.updateImage(newImage: newImage)
762 }
763
764 pub fun updateSetMetadata(id: UInt64, newMetadata: {String: AnyStruct}) {
765 let set = self.borrowSet(id: id)
766 set.updateMetadata(newMetadata: newMetadata)
767 }
768 }
769
770 pub fun getTemplate(id: UInt64): Wine.Template? {
771 return self.Templates[id]
772 }
773
774 pub fun getTemplates(): {UInt64: Wine.Template} {
775 return self.Templates
776 }
777
778 pub fun getSetIDs(): [UInt64] {
779 return self.sets.keys
780 }
781
782 pub fun getSetData(id: UInt64): Wine.SetData? {
783 return Wine.SetsData[id]
784 }
785
786 pub fun getSetsData(): {UInt64: Wine.SetData} {
787 return self.SetsData
788 }
789
790 pub fun getSetSize(id: UInt64): UInt64 {
791 pre {
792 self.sets[id] != nil: "Cannot borrow set: set doesn't exist"
793 }
794
795 let set = &self.sets[id] as &Set?
796
797 return set!.nextSerialNumber - 1
798 }
799
800 pub fun getTemplateIDsInSet(id: UInt64): [UInt64] {
801 pre {
802 self.sets[id] != nil: "Cannot borrow set: set doesn't exist"
803 }
804
805 let set = &self.sets[id] as &Set?
806 return set!.getTemplateIDs()
807 }
808
809 init() {
810 self.CollectionStoragePath = /storage/WineCollection
811 self.CollectionPublicPath = /public/WineCollection
812 self.AdminStoragePath = /storage/WineAdmin
813 self.AdminPrivatePath = /private/WineAdminUpgrade
814
815 self.totalSupply = 0
816 self.nextTemplateID = 1
817 self.nextSetID = 1
818 self.sets <- {}
819
820 self.SetsData = {}
821 self.Templates = {}
822
823 let admin <- create Admin()
824 self.account.save(<-admin, to: self.AdminStoragePath)
825
826 self.account.link<&Wine.Admin>(
827 self.AdminPrivatePath,
828 target: self.AdminStoragePath
829 ) ?? panic("Could not get a capability to the admin")
830
831 emit ContractInitialized()
832 }
833}
834