Smart Contract

TheFabricantPrimalRave

A.7752ea736384322f.TheFabricantPrimalRave

Deployed

3d ago
Feb 25, 2026, 03:08:52 PM UTC

Dependents

2 imports
1import TheFabricantMetadataViewsV2 from 0x7752ea736384322f
2
3import ViewResolver from 0x1d7e57aa55817448
4
5import MetadataViews from 0x1d7e57aa55817448
6
7import NonFungibleToken from 0x1d7e57aa55817448
8
9import TheFabricantNFTStandardV2 from 0x7752ea736384322f
10
11import RevealableV2 from 0x7752ea736384322f
12
13import CoCreatableV2 from 0x7752ea736384322f
14
15import TheFabricantAccessList from 0x7752ea736384322f
16
17import FungibleToken from 0xf233dcee88fe0abe
18
19import FlowToken from 0x1654653399040a61
20
21import PrimalRaveVariantMintLimits from 0x7752ea736384322f
22
23access(all)
24contract TheFabricantPrimalRave: NonFungibleToken, TheFabricantNFTStandardV2, RevealableV2{ 
25	
26	// -----------------------------------------------------------------------
27	// Paths
28	// -----------------------------------------------------------------------
29	access(all)
30	let TheFabricantPrimalRaveCollectionStoragePath: StoragePath
31	
32	access(all)
33	let TheFabricantPrimalRaveCollectionPublicPath: PublicPath
34	
35	access(all)
36	let TheFabricantPrimalRaveProviderStoragePath: PrivatePath
37	
38	access(all)
39	let TheFabricantPrimalRavePublicMinterStoragePath: StoragePath
40	
41	access(all)
42	let TheFabricantPrimalRaveAdminStoragePath: StoragePath
43	
44	access(all)
45	let TheFabricantPrimalRavePublicMinterPublicPath: PublicPath
46	
47	// -----------------------------------------------------------------------
48	// Contract Events
49	// -----------------------------------------------------------------------
50	// Event that emitted when the NFT contract is initialized
51	//
52	access(all)
53	event ContractInitialized()
54	
55	access(all)
56	event ItemMintedAndTransferred(uuid: UInt64, id: UInt64, name: String, description: String, collection: String, editionNumber: UInt64, originalRecipient: Address, license: MetadataViews.License?, nftMetadataId: UInt64)
57	
58	access(all)
59	event ItemRevealed(uuid: UInt64, id: UInt64, name: String, description: String, collection: String, editionNumber: UInt64, originalRecipient: Address, license: MetadataViews.License?, nftMetadataId: UInt64, externalURL: MetadataViews.ExternalURL, coCreatable: Bool, coCreator: Address)
60	
61	access(all)
62	event TraitRevealed(nftUuid: UInt64, id: UInt64, trait: String)
63	
64	access(all)
65	event IsTraitRevealableV2Updated(nftUuid: UInt64, id: UInt64, trait: String, isRevealableV2: Bool)
66	
67	access(all)
68	event MintPaymentSplitDeposited(address: Address, price: UFix64, amount: UFix64, nftUuid: UInt64)
69	
70	access(all)
71	event ItemDestroyed(uuid: UInt64, id: UInt64, name: String, description: String, collection: String)
72	
73	access(all)
74	event PublicMinterCreated(uuid: UInt64, name: String, description: String, collection: String, path: String)
75	
76	access(all)
77	event PublicMinterIsOpenAccessChanged(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool)
78	
79	access(all)
80	event PublicMinterIsAccessListOnly(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool)
81	
82	access(all)
83	event PublicMinterMintingIsOpen(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool)
84	
85	access(all)
86	event PublicMinterSetAccessListId(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool, accessListId: UInt64)
87	
88	access(all)
89	event PublicMinterSetPaymentAmount(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool, paymentAmount: UFix64)
90	
91	access(all)
92	event PublicMinterSetMinterMintLimit(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool, minterMintLimit: UInt64?)
93	
94	access(all)
95	event AdminResourceCreated(uuid: UInt64, adminAddress: Address)
96	
97	access(all)
98	event AdminPaymentReceiverCapabilityChanged(address: Address, paymentType: Type)
99	
100	access(all)
101	event AdminSetMaxSupply(maxSupply: UInt64)
102	
103	access(all)
104	event AdminSetVariantSupply(variantId: UInt64, name: String, supply: UInt64)
105	
106	access(all)
107	event AdminSetVariantPaymentAmount(variantId: UInt64, name: String, paymentAmount: UFix64)
108	
109	access(all)
110	event AdminSetMintableVariants(mintableVariants: [UInt64])
111	
112	access(all)
113	event AdminSetAddressMintLimit(addressMintLimit: UInt64)
114	
115	access(all)
116	event AdminSetCollectionId(collectionId: String)
117	
118	access(all)
119	event AdminSetBaseURI(baseURI: String)
120	
121	// Event that is emitted when a token is withdrawn,
122	// indicating the owner of the collection that it was withdrawn from.
123	//
124	// If the collection is not in an account's storage, `from` will be `nil`.
125	//
126	access(all)
127	event Withdraw(id: UInt64, from: Address?)
128	
129	// Event that emitted when a token is deposited to a collection.
130	//
131	// It indicates the owner of the collection that it was deposited to.
132	//
133	access(all)
134	event Deposit(id: UInt64, to: Address?)
135	
136	// -----------------------------------------------------------------------
137	// Contract State
138	// -----------------------------------------------------------------------
139	// NOTE: This is updated anywhere ownership of the nft is changed - on minting and therefore on deposit
140	access(contract)
141	var nftIdsToOwner:{ UInt64: Address}
142	
143	access(contract)
144	var publicMinterPaths:{ UInt64: String}
145	
146	// NOTE: this is contract-level so all minters can access it.
147	// Keeps track of the number of times an address has minted
148	access(contract)
149	var addressMintCount:{ Address: UInt64}
150	
151	// Receives payment for minting
152	access(contract)
153	var paymentReceiverCap: Capability<&{FungibleToken.Receiver}>?
154	
155	access(contract)
156	var nftMetadata:{ UInt64:{ RevealableV2.RevealableMetadata}}
157	
158	// The total number of tokens of this type in existence
159	// NOTE: All public minters use totalSupply to assign the next
160	// id and edition number. Each public minter has a minterMintLimit property
161	// that defines the max no. of mints a pM can do. 
162	access(all)
163	var totalSupply: UInt64
164	
165	// NOTE: The max number of NFTs in this collection that will ever be minted
166	// Init as nil if there is no max. 
167	access(all)
168	var maxSupply: UInt64?
169	
170	// NOTE: Max mints per address
171	access(all)
172	var addressMintLimit: UInt64?
173	
174	//NOTE: uuid of collection added to NFT and used by BE
175	access(all)
176	var collectionId: String?
177	
178	access(contract)
179	var baseTokenURI: String?
180	
181	// The variant info for each variant
182	access(contract)
183	var variants:{ UInt64: VariantInfo}
184	
185	// The variants that this contract is able to mint
186	access(contract)
187	var mintableVariants: [UInt64]
188	
189	// -----------------------------------------------------------------------
190	// VariantInfo Struct
191	// -----------------------------------------------------------------------
192	// Contains the information about a variant that is used in minting and on FE/BE etc.
193	// The info contained in this struct is used to populate the NFT metadata
194	access(all)
195	struct VariantInfo{ 
196		// id of the variant that is used in minting and on FE/BE etc
197		access(all)
198		let id: UInt64
199		
200		// name of the variant
201		access(all)
202		var name: String
203		
204		// variant description
205		access(all)
206		var description: String
207		
208		// price of the variant
209		access(all)
210		var paymentAmount: UFix64
211		
212		// max number of mints for this variant
213		access(all)
214		var supply: UInt64
215		
216		// total number of mints for this variant (ie current number of mints)
217		access(all)
218		var totalSupply: UInt64
219		
220		init(id: UInt64, name: String, description: String, paymentAmount: UFix64, supply: UInt64){ 
221			self.id = id
222			self.name = name
223			self.description = description
224			self.paymentAmount = paymentAmount
225			self.supply = supply
226			self.totalSupply = 0
227		}
228		
229		access(all)
230		fun incrementTotalSupply(){ 
231			self.totalSupply = self.totalSupply + 1
232		}
233		
234		access(all)
235		fun canMintSupply(): Bool{ 
236			return self.totalSupply <= self.supply
237		}
238		
239		access(all)
240		fun setPaymentAmount(paymentAmount: UFix64){ 
241			self.paymentAmount = paymentAmount
242		}
243		
244		access(all)
245		fun setSupply(supply: UInt64){ 
246			self.supply = supply
247		}
248	}
249	
250	// -----------------------------------------------------------------------
251	// RevealableV2 Metadata Struct
252	// -----------------------------------------------------------------------
253	access(all)
254	struct RevealableMetadata: RevealableV2.RevealableMetadata{ 
255		
256		//NOTE: totalSupply value of attached NFT, therefore edition number. 
257		access(all)
258		let id: UInt64
259		
260		// NOTE: !IMPORTANT! nftUuid is the uuid of the associated nft.
261		// This RevealableMetadata struct should be stored in the nftMetadata dict under this
262		// value. This is because the uuid is used across contracts for identification purposes
263		access(all)
264		let nftUuid: UInt64 // uuid of NFT
265		
266		
267		// NOTE: Name of NFT. 
268		// Will be combined with the edition number on the application
269		// Doesn't include the edition number.
270		access(all)
271		var name: String
272		
273		access(all)
274		var description: String //Display
275		
276		
277		// NOTE: Thumbnail, which is needed for the Display view, should be set using one of the
278		// media properties
279		//access(all) let thumbnail: String //Display
280		access(all)
281		let collection: String // Name of collection eg The Fabricant > Season 3 > Wholeland > XXories Originals
282		
283		
284		// Stores the metadata that describes this particular creation,
285		// but is not part of a characteristic eg mainImage, video etc
286		access(all)
287		var metadata:{ String: AnyStruct}
288		
289		// This is where the user-chosed characteristics live. This represents
290		// the data that in older contracts, would've been separate NFTs.		
291		access(all)
292		var characteristics:{ String:{ CoCreatableV2.Characteristic}}
293		
294		access(all)
295		var rarity: UFix64?
296		
297		access(all)
298		var rarityDescription: String?
299		
300		// NOTE: Media is not implemented in the struct because MetadataViews.Medias
301		// is not mutable, so can't be updated. In addition, each 
302		// NFT collection might have a different number of image/video properties.
303		// Instead, the NFT should implement a function that rolls up the props
304		// into a MetadataViews.Medias struct
305		//access(all) let media: MetadataViews.Medias //Media
306		access(all)
307		let license: MetadataViews.License? //License
308		
309		
310		access(all)
311		let externalURL: MetadataViews.ExternalURL //ExternalURL
312		
313		
314		access(all)
315		let coCreatable: Bool
316		
317		access(all)
318		let coCreator: Address
319		
320		access(all)
321		var isRevealed: Bool?
322		
323		// id and editionNumber might not be the same in the nft...
324		access(all)
325		let editionNumber: UInt64 //Edition
326		
327		
328		access(all)
329		let maxEditionNumber: UInt64?
330		
331		access(all)
332		let royalties: MetadataViews.Royalties //Royalty
333		
334		
335		access(all)
336		let royaltiesTFMarketplace: TheFabricantMetadataViewsV2.Royalties
337		
338		access(contract)
339		var revealableTraits:{ String: Bool}
340		
341		access(all)
342		fun getRevealableTraits():{ String: Bool}{ 
343			return self.revealableTraits
344		}
345		
346		//NOTE: Customise
347		//NOTE: This should be updated for each campaign contract!
348		// Called by the Admin to reveal the traits for this NFT.
349		// Should contain a switch function that knows how to modify
350		// the properties of this struct. Should check that the trait
351		// being revealed is allowed to be modified.
352		access(contract)
353		fun revealTraits(traits: [{RevealableV2.RevealableTrait}]){ 
354			var i = 0
355			while i < traits.length{ 
356				let RevealableTrait = traits[i]
357				let traitName = RevealableTrait.name
358				let traitValue = RevealableTrait.value
359				switch traitName{ 
360					case "mainImage":
361						assert(self.checkRevealableTrait(traitName: traitName)!, message: "UnRevealableV2 trait passed in - please ensure trait can be revealed: ".concat(traitName))
362						self.updateMetadata(key: traitName, value: traitValue)
363					case "video":
364						assert(self.checkRevealableTrait(traitName: traitName)!, message: "UnRevealableV2 trait passed in - please ensure trait can be revealed: ".concat(traitName))
365						self.updateMetadata(key: traitName, value: traitValue)
366					default:
367						panic("UnRevealableV2 trait passed in - please ensure trait can be revealed: ".concat(traitName))
368				}
369				i = i + 1
370			}
371			self.isRevealed = true
372		}
373		
374		access(contract)
375		fun updateMetadata(key: String, value: AnyStruct){ 
376			self.metadata[key] = value
377		}
378		
379		// Called by the nft owner to modify if a trait can be 
380		// revealed or not - used to revoke admin access
381		access(all)
382		fun updateIsTraitRevealable(key: String, value: Bool){ 
383			self.revealableTraits[key] = value
384		}
385		
386		access(all)
387		fun checkRevealableTrait(traitName: String): Bool?{ 
388			if let RevealableV2 = self.revealableTraits[traitName]{ 
389				return RevealableV2
390			}
391			return nil
392		}
393		
394		init(id: UInt64, nftUuid: UInt64, name: String, description: String, collection: String, metadata:{ String: AnyStruct}, characteristics:{ String:{ CoCreatableV2.Characteristic}}, license: MetadataViews.License?, externalURL: MetadataViews.ExternalURL, coCreatable: Bool, coCreator: Address, editionNumber: UInt64, maxEditionNumber: UInt64?, revealableTraits:{ String: Bool}, royalties: MetadataViews.Royalties, royaltiesTFMarketplace: TheFabricantMetadataViewsV2.Royalties){ 
395			self.id = id
396			self.nftUuid = nftUuid
397			self.name = name
398			self.description = description
399			self.collection = collection
400			self.metadata = metadata
401			self.characteristics = characteristics
402			self.rarity = nil
403			self.rarityDescription = nil
404			self.license = license
405			self.externalURL = externalURL
406			self.coCreatable = coCreatable
407			self.coCreator = coCreator
408			//NOTE: Customise
409			// This should be nil if the nft can't be revealed!
410			self.isRevealed = true
411			self.editionNumber = editionNumber
412			self.maxEditionNumber = maxEditionNumber
413			self.revealableTraits = revealableTraits
414			self.royalties = royalties
415			self.royaltiesTFMarketplace = royaltiesTFMarketplace
416		}
417	}
418	
419	// -----------------------------------------------------------------------
420	// Trait Struct
421	// -----------------------------------------------------------------------
422	// Used by txs to target traits/characteristics to be revealed
423	access(all)
424	struct Trait: RevealableV2.RevealableTrait{ 
425		access(all)
426		let name: String
427		
428		access(all)
429		let value: AnyStruct
430		
431		init(name: String, value: AnyStruct){ 
432			self.name = name
433			self.value = value
434		}
435	}
436	
437	// -----------------------------------------------------------------------
438	// NFT Resource
439	// -----------------------------------------------------------------------
440	// Restricted scope for borrowTheFabricantPrimalRave() in Collection.
441	// Ensures that the returned NFT ref is read only.
442	access(all)
443	resource interface PublicNFT{ 
444		access(all)
445		fun getFullName(): String
446		
447		access(all)
448		fun getEditions(): MetadataViews.Editions
449		
450		access(all)
451		fun getMedias(): MetadataViews.Medias
452		
453		access(all)
454		fun getTraits(): MetadataViews.Traits?
455		
456		access(all)
457		view fun getRarity(): MetadataViews.Rarity?
458		
459		access(all)
460		fun getExternalRoyalties(): MetadataViews.Royalties
461		
462		access(all)
463		fun getTFRoyalties(): TheFabricantMetadataViewsV2.Royalties
464		
465		access(all)
466		fun getMetadata():{ String: AnyStruct}
467		
468		access(all)
469		fun getCharacteristics():{ String:{ CoCreatableV2.Characteristic}}?
470		
471		access(all)
472		fun getDisplay(): MetadataViews.Display
473		
474		access(all)
475		fun getCollectionData(): MetadataViews.NFTCollectionData
476		
477		access(all)
478		fun getCollectionDisplay(): MetadataViews.NFTCollectionDisplay
479		
480		access(all)
481		fun getNFTView(): MetadataViews.NFTView
482		
483		access(all)
484		fun getViews(): [Type]
485		
486		access(all)
487		fun resolveView(_ view: Type): AnyStruct?
488	}
489	
490	access(all)
491	resource NFT: TheFabricantNFTStandardV2.TFNFT, NonFungibleToken.NFT, ViewResolver.Resolver, PublicNFT{ 
492		access(all)
493		let id: UInt64
494		
495		// NOTE: Ensure that the name for the nft is correct. This 
496		// will be shown to users. It should not include the edition number.
497		access(contract)
498		let collectionId: String
499		
500		access(contract)
501		let editionNumber: UInt64 //Edition
502		
503		
504		access(contract)
505		let maxEditionNumber: UInt64?
506		
507		access(contract)
508		let originalRecipient: Address
509		
510		access(contract)
511		let license: MetadataViews.License?
512		
513		access(contract)
514		let nftMetadataId: UInt64
515		
516		access(all)
517		fun getFullName(): String{ 
518			return ((TheFabricantPrimalRave.nftMetadata[self.nftMetadataId]!).name!).concat(" #".concat(self.editionNumber.toString()))
519		}
520		
521		// NOTE: This is important for Edition view
522		access(all)
523		fun getEditionName(): String{ 
524			return (TheFabricantPrimalRave.nftMetadata[self.nftMetadataId]!).collection
525		}
526		
527		access(all)
528		fun getEditions(): MetadataViews.Editions{ 
529			// NOTE: In this case, id != edition number
530			let edition = MetadataViews.Edition(name: (TheFabricantPrimalRave.nftMetadata[self.nftMetadataId]!).collection, number: self.editionNumber, max: self.maxEditionNumber)
531			return MetadataViews.Editions([edition])
532		}
533		
534		//NOTE: Customise
535		//NOTE: This will be different for each campaign, determined by how
536		// many media files there are and their keys in metadata! Pay attention
537		// to where the media files are stored and therefore accessed
538		access(all)
539		fun getMedias(): MetadataViews.Medias{ 
540			let nftMetadata = TheFabricantPrimalRave.nftMetadata[self.id]!
541			let mainImage = nftMetadata.metadata["mainImage"]! as! String
542			// NOTE: This assumes that when the shoeShape characteristic is created
543			// in the update_shoe_shapes_char tx, the value property is created as a dictionary
544			let video = nftMetadata.metadata["video"]! as! String
545			let mainImageMedia = MetadataViews.Media(file: MetadataViews.HTTPFile(url: mainImage), mediaType: "image/png")
546			let videoMedia = MetadataViews.Media(file: MetadataViews.HTTPFile(url: video), mediaType: "video/mp4")
547			return MetadataViews.Medias([mainImageMedia, videoMedia])
548		}
549		
550		// NOTE: Customise
551		access(all)
552		fun getImages():{ String: String}{ 
553			let nftMetadata = TheFabricantPrimalRave.nftMetadata[self.id]!
554			let mainImage = nftMetadata.metadata["mainImage"]! as! String
555			return{ "mainImage": mainImage}
556		}
557		
558		// NOTE: Customise
559		access(all)
560		fun getVideos():{ String: String}{ 
561			let nftMetadata = TheFabricantPrimalRave.nftMetadata[self.id]!
562			let mainVideo = nftMetadata.metadata["video"]! as! String
563			return{ "mainVideo": mainVideo}
564		}
565		
566		// NOTE: Customise
567		// What are the traits that you want external marketplaces
568		// to display?
569		access(all)
570		fun getTraits(): MetadataViews.Traits?{ 
571			return nil
572		}
573		
574		access(all)
575		view fun getRarity(): MetadataViews.Rarity?{ 
576			return nil
577		}
578		
579		access(all)
580		fun getExternalRoyalties(): MetadataViews.Royalties{ 
581			let nftMetadata = TheFabricantPrimalRave.nftMetadata[self.id]!
582			return nftMetadata.royalties
583		}
584		
585		access(all)
586		fun getTFRoyalties(): TheFabricantMetadataViewsV2.Royalties{ 
587			let nftMetadata = TheFabricantPrimalRave.nftMetadata[self.id]!
588			return nftMetadata.royaltiesTFMarketplace
589		}
590		
591		access(all)
592		fun getMetadata():{ String: AnyStruct}{ 
593			return (TheFabricantPrimalRave.nftMetadata[self.id]!).metadata
594		}
595		
596		//NOTE: This is not a CoCreatableV2 NFT, so no characteristics are present
597		access(all)
598		fun getCharacteristics():{ String:{ CoCreatableV2.Characteristic}}?{ 
599			return nil
600		}
601		
602		access(all)
603		fun getRevealableTraits():{ String: Bool}?{ 
604			return (TheFabricantPrimalRave.nftMetadata[self.id]!).getRevealableTraits()
605		}
606		
607		//NOTE: The first file in medias will be the thumbnail.
608		// Maybe put a file type check in here to ensure it is 
609		// an image?
610		access(all)
611		fun getDisplay(): MetadataViews.Display{ 
612			return MetadataViews.Display(name: self.getFullName(), description: (TheFabricantPrimalRave.nftMetadata[self.nftMetadataId]!).description, thumbnail: self.getMedias().items[0].file)
613		}
614		
615		access(all)
616		fun getCollectionData(): MetadataViews.NFTCollectionData{ 
617			return MetadataViews.NFTCollectionData(storagePath: TheFabricantPrimalRave.TheFabricantPrimalRaveCollectionStoragePath, publicPath: TheFabricantPrimalRave.TheFabricantPrimalRaveCollectionPublicPath, publicCollection: Type<&TheFabricantPrimalRave.Collection>(), publicLinkedType: Type<&TheFabricantPrimalRave.Collection>(), createEmptyCollectionFunction: fun (): @{NonFungibleToken.Collection}{ 
618					return <-TheFabricantPrimalRave.createEmptyCollection(nftType: Type<@TheFabricantPrimalRave.Collection>())
619				})
620		}
621		
622		//NOTE: Customise
623		// NOTE: Update this function with the collection display image
624		// and TF socials
625		access(all)
626		fun getCollectionDisplay(): MetadataViews.NFTCollectionDisplay{ 
627			let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://primalrave-collection-display.s3.eu-central-1.amazonaws.com/images/primalrave_square.png"), mediaType: "image/png")
628			let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://primalrave-collection-display.s3.eu-central-1.amazonaws.com/images/primalrave_banner.png"), mediaType: "image/png")
629			return MetadataViews.NFTCollectionDisplay(name: self.getEditionName(), description: "An exploration of the self through a club night, this collection takes inspiration from a secret rave in the forest. Elements of Dutch traditional dress in combination with 90s gabber aesthetic create a fresh narrative on what it means to explore your identity in a club night. ", externalURL: (TheFabricantPrimalRave.nftMetadata[self.id]!).externalURL, squareImage: squareImage, bannerImage: bannerImage, socials:{ "twitter": MetadataViews.ExternalURL("https://twitter.com/thefabricant"), "instagram": MetadataViews.ExternalURL("https://www.instagram.com/the_fab_ric_ant/"), "facebook": MetadataViews.ExternalURL("https://www.facebook.com/thefabricantdesign/"), "artstation": MetadataViews.ExternalURL("https://www.artstation.com/thefabricant"), "behance": MetadataViews.ExternalURL("https://www.behance.net/thefabricant"), "linkedin": MetadataViews.ExternalURL("https://www.linkedin.com/company/the-fabricant"), "sketchfab": MetadataViews.ExternalURL("https://sketchfab.com/thefabricant"), "clolab": MetadataViews.ExternalURL("https://www.clo3d.com/en/clollab/thefabricant"), "tiktok": MetadataViews.ExternalURL("@digital_fashion"), "discord": MetadataViews.ExternalURL("https://discord.com/channels/692039738751713280/778601303013195836")})
630		}
631		
632		access(all)
633		fun getNFTView(): MetadataViews.NFTView{ 
634			return MetadataViews.NFTView(id: self.id, uuid: self.uuid, display: self.getDisplay(), externalURL: (TheFabricantPrimalRave.nftMetadata[self.id]!).externalURL, collectionData: self.getCollectionData(), collectionDisplay: self.getCollectionDisplay(), royalties: (TheFabricantPrimalRave.nftMetadata[self.id]!).royalties, traits: self.getTraits())
635		}
636		
637		access(all) view
638		fun getViews(): [Type] { 
639			let viewArray: [Type] = [Type<TheFabricantMetadataViewsV2.TFNFTIdentifierV1>(), Type<TheFabricantMetadataViewsV2.TFNFTSimpleView>(), Type<MetadataViews.NFTView>(), Type<MetadataViews.Display>(), Type<MetadataViews.Editions>(), Type<MetadataViews.Serial>(), Type<MetadataViews.Royalties>(), Type<MetadataViews.Medias>(), Type<MetadataViews.ExternalURL>(), Type<MetadataViews.NFTCollectionData>(), Type<MetadataViews.NFTCollectionDisplay>(), Type<MetadataViews.Traits>()]
640			return viewArray
641		}
642		
643		access(all)
644		fun resolveView(_ view: Type): AnyStruct?{ 
645			switch view{ 
646				case Type<TheFabricantMetadataViewsV2.TFNFTIdentifierV1>():
647					return TheFabricantMetadataViewsV2.TFNFTIdentifierV1(uuid: self.uuid, id: self.id, name: self.getFullName(), collection: (TheFabricantPrimalRave.nftMetadata[self.nftMetadataId]!).collection, editions: self.getEditions(), address: (self.owner!).address, originalRecipient: self.originalRecipient)
648				case Type<TheFabricantMetadataViewsV2.TFNFTSimpleView>():
649					return TheFabricantMetadataViewsV2.TFNFTSimpleView(
650				    uuid: self.uuid, 
651				    id: self.id, 
652				    name: self.getFullName(), 
653				    description: (TheFabricantPrimalRave.nftMetadata[self.nftMetadataId]!).description, 
654				    collection: (TheFabricantPrimalRave.nftMetadata[self.nftMetadataId]!).collection, 
655				    collectionId: TheFabricantPrimalRave.collectionId!,
656				    metadata: self.getMetadata(), 
657				    media: self.getMedias(), 
658				    images: self.getImages(), 
659				    videos: self.getVideos(), 
660				    externalURL: (TheFabricantPrimalRave.nftMetadata[self.id]!).externalURL, 
661				    rarity: self.getRarity(), 
662				    traits: self.getTraits(), 
663				    characteristics: self.getCharacteristics(), 
664				    coCreatable: (TheFabricantPrimalRave.nftMetadata[self.id]!).coCreatable, 
665				    coCreator: (TheFabricantPrimalRave.nftMetadata[self.id]!).coCreator,  
666				    isRevealed: (TheFabricantPrimalRave.nftMetadata[self.id]!).isRevealed, 
667				    editions: self.getEditions(), 
668				    originalRecipient: self.originalRecipient, 
669				    royalties: (TheFabricantPrimalRave.nftMetadata[self.id]!).royalties, 
670				    royaltiesTFMarketplace: (TheFabricantPrimalRave.nftMetadata[self.id]!).royaltiesTFMarketplace, 
671				    revealableTraits: self.getRevealableTraits(), 
672				    address: self.owner!.address
673				)
674				case Type<MetadataViews.NFTView>():
675					return self.getNFTView()
676				case Type<MetadataViews.Display>():
677					return self.getDisplay()
678				case Type<MetadataViews.Editions>():
679					return self.getEditions()
680				case Type<MetadataViews.Serial>():
681					return self.id
682				case Type<MetadataViews.Royalties>():
683					return TheFabricantPrimalRave.nftMetadata[self.id]?.royalties
684				case Type<MetadataViews.Medias>():
685					return self.getMedias()
686				case Type<MetadataViews.License>():
687					return self.license
688				case Type<MetadataViews.ExternalURL>():
689					return TheFabricantPrimalRave.nftMetadata[self.id]?.externalURL
690				case Type<MetadataViews.NFTCollectionData>():
691					return self.getCollectionData()
692				case Type<MetadataViews.NFTCollectionDisplay>():
693					return self.getCollectionDisplay()
694				case Type<MetadataViews.Rarity>():
695					return self.getRarity()
696				case Type<MetadataViews.Traits>():
697					return self.getTraits()
698			}
699			return nil
700		}
701		
702		access(all)
703		fun updateIsTraitRevealable(key: String, value: Bool){ 
704			let nftMetadata = TheFabricantPrimalRave.nftMetadata[self.id]!
705			nftMetadata.updateIsTraitRevealable(key: key, value: value)
706			TheFabricantPrimalRave.nftMetadata[self.id] = nftMetadata
707			emit IsTraitRevealableV2Updated(nftUuid: nftMetadata.nftUuid, id: nftMetadata.id, trait: key, isRevealableV2: value)
708		}
709		
710		access(all)
711		fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
712			return <-create Collection()
713		}
714		
715		init(variantId: UInt64, originalRecipient: Address, license: MetadataViews.License?){ 
716			assert(TheFabricantPrimalRave.collectionId != nil, message: "Ensure that Admin has set collectionId in the contract")
717			
718			// Increment the total number of NFTs minted in the contract
719			TheFabricantPrimalRave.totalSupply = TheFabricantPrimalRave.totalSupply + 1
720			self.id = TheFabricantPrimalRave.totalSupply
721			self.collectionId = TheFabricantPrimalRave.collectionId!
722			(			 
723			 // Increment the number minted for this variant
724			 TheFabricantPrimalRave.variants[variantId]!).incrementTotalSupply()
725			
726			// Set nft edition number
727			self.editionNumber = (TheFabricantPrimalRave.variants[variantId]!).totalSupply
728			// max edition number is specific to the variant
729			self.maxEditionNumber = (TheFabricantPrimalRave.variants[variantId]!).supply
730			self.originalRecipient = originalRecipient
731			self.license = license
732			self.nftMetadataId = self.id
733		}
734	}
735	
736	// -----------------------------------------------------------------------
737	// Collection Resource
738	// -----------------------------------------------------------------------
739	access(all)
740	resource interface TheFabricantPrimalRaveCollectionPublic{ 
741		access(all)
742		fun borrowTheFabricantPrimalRave(id: UInt64): &TheFabricantPrimalRave.NFT?
743		
744		access(all)
745		fun deposit(token: @{NonFungibleToken.NFT})
746		
747		access(all)
748		fun getIDs(): [UInt64]
749		
750		access(all)
751		view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
752
753		access(all) 
754		view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}?
755	}
756	
757	access(all)
758	resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, NonFungibleToken.CollectionPublic, TheFabricantPrimalRaveCollectionPublic, ViewResolver.ResolverCollection{ 
759		
760		// Dictionary to hold the NFTs in the Collection
761		access(all)
762		var ownedNFTs: @{UInt64:{ NonFungibleToken.NFT}}
763		
764		access(all)
765		view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}?{ 
766			let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
767			let TheFabricantPrimalRave = nft as! &TheFabricantPrimalRave.NFT
768			return TheFabricantPrimalRave as &{ViewResolver.Resolver}
769		}
770		
771		// withdraw removes an NFT from the collection and moves it to the caller
772		access(NonFungibleToken.Withdraw)
773		fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT}{ 
774			// Remove the nft from the Collection
775			let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Cannot withdraw: NFT does not exist in the collection")
776			emit Withdraw(id: token.id, from: self.owner?.address)
777			
778			// Return the withdrawn token
779			return <-token
780		}
781		
782		// deposit takes an NFT and adds it to the collections dictionary
783		// and adds the ID to the id array
784		access(all)
785		fun deposit(token: @{NonFungibleToken.NFT}){ 
786			// By ensuring self.owner.address is not nil we keep the nftIdsToOwner dict 
787			// up to date.
788			pre{ 
789				self.owner?.address != nil:
790					"The Collection resource must be stored in a users account"
791			}
792			
793			// Cast the deposited token as  NFT to make sure
794			// it is the correct type
795			let token <- token as! @NFT
796			
797			// Get the token's ID
798			let id = token.id
799			
800			// Add the new token to the dictionary
801			let oldToken <- self.ownedNFTs[id] <- token
802			TheFabricantPrimalRave.nftIdsToOwner[id] = (self.owner!).address
803			emit Deposit(id: id, to: self.owner?.address)
804			
805			// Destroy the empty old token that was "removed"
806			destroy oldToken
807		}
808		
809		// getIDs returns an array of the IDs that are in the collection
810		access(all)
811		view fun getIDs(): [UInt64]{ 
812			return self.ownedNFTs.keys
813		}
814		
815		// Returns a borrowed reference to an NFT in the collection
816		// so that the caller can read data and call methods from it
817		access(all)
818		view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?{ 
819			return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
820		}
821		
822		access(all)
823		fun borrowTheFabricantPrimalRave(id: UInt64): &TheFabricantPrimalRave.NFT?{ 
824			if self.ownedNFTs[id] != nil{ 
825				// Create an authorized reference to allow downcasting
826				let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
827				return ref as! &TheFabricantPrimalRave.NFT
828			}
829			return nil
830		}
831		
832		/// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
833        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
834            let supportedTypes: {Type: Bool} = {}
835            supportedTypes[Type<@TheFabricantPrimalRave.NFT>()] = true
836            return supportedTypes
837        }
838
839        /// Returns whether or not the given type is accepted by the collection
840        /// A collection that can accept any type should just return true by default
841        access(all) view fun isSupportedNFTType(type: Type): Bool {
842            return type == Type<@TheFabricantPrimalRave.NFT>()
843        }
844
845		/// Gets the amount of NFTs stored in the collection
846    	access(all) view fun getLength(): Int {
847    	    return self.ownedNFTs.length
848    	}
849
850		
851		access(all)
852		fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
853			return <-create Collection()
854		}
855		
856		// If a transaction destroys the Collection object,
857		// All the NFTs contained within are also destroyed!
858		//
859		init(){ 
860			self.ownedNFTs <-{} 
861		}
862	}
863	
864	// -----------------------------------------------------------------------
865	// Admin Resource
866	// -----------------------------------------------------------------------
867	access(all)
868	resource Admin{ 
869		access(all)
870		fun setPublicReceiverCap(paymentReceiverCap: Capability<&{FungibleToken.Receiver}>){ 
871			TheFabricantPrimalRave.paymentReceiverCap = paymentReceiverCap
872			emit AdminPaymentReceiverCapabilityChanged(address: paymentReceiverCap.address, paymentType: paymentReceiverCap.getType())
873		}
874		
875		access(all)
876		fun setBaseURI(baseURI: String){ 
877			TheFabricantPrimalRave.baseTokenURI = baseURI
878			emit AdminSetBaseURI(baseURI: baseURI)
879		}
880		
881		// The max supply determines the maximum number of NFTs that can be minted from this contract
882		access(all)
883		fun setMaxSupply(maxSupply: UInt64){ 
884			TheFabricantPrimalRave.maxSupply = maxSupply
885			emit AdminSetMaxSupply(maxSupply: maxSupply)
886		}
887		
888		access(all)
889		fun setAddressMintLimit(addressMintLimit: UInt64){ 
890			TheFabricantPrimalRave.addressMintLimit = addressMintLimit
891			emit AdminSetAddressMintLimit(addressMintLimit: addressMintLimit)
892		}
893		
894		access(all)
895		fun setCollectionId(collectionId: String){ 
896			TheFabricantPrimalRave.collectionId = collectionId
897			emit AdminSetCollectionId(collectionId: collectionId)
898		}
899		
900		// Sets the supply for each variant.
901		access(all)
902		fun setVariantSupply(supplyDict:{ UInt64: UInt64}){ 
903			let keys = supplyDict.keys
904			let values = supplyDict.values
905			let variantKeys = TheFabricantPrimalRave.variants.keys
906			while keys.length > 0{ 
907				let key = keys.removeFirst()
908				let value = values.removeFirst()
909				assert(variantKeys.contains(key), message: "Variant does not exist")
910				(TheFabricantPrimalRave.variants[key]!).setSupply(supply: value)
911				emit AdminSetVariantSupply(variantId: key, name: (TheFabricantPrimalRave.variants[key]!).name, supply: value)
912			}
913			// Update maxSupply
914			let variants = TheFabricantPrimalRave.variants.values
915			var i = 0
916			var sum: UInt64 = 0
917			while i < variants.length{ 
918				sum = sum + variants[i].supply
919				i = i + 1
920			}
921			TheFabricantPrimalRave.maxSupply = sum
922			emit AdminSetMaxSupply(maxSupply: sum)
923		}
924		
925		access(all)
926		fun setVariantPaymentAmount(priceDict:{ UInt64: UFix64}){ 
927			let keys = priceDict.keys
928			let values = priceDict.values
929			let variantKeys = TheFabricantPrimalRave.variants.keys
930			while keys.length > 0{ 
931				let key = keys.removeFirst()
932				let value = values.removeFirst()
933				assert(variantKeys.contains(key), message: "Variant does not exist")
934				(TheFabricantPrimalRave.variants[key]!).setPaymentAmount(paymentAmount: value)
935				emit AdminSetVariantPaymentAmount(variantId: key, name: (TheFabricantPrimalRave.variants[key]!).name, paymentAmount: value)
936			}
937		}
938		
939		access(all)
940		fun setMintableVariants(mintableVariants: [UInt64]){ 
941			TheFabricantPrimalRave.mintableVariants = mintableVariants
942			emit AdminSetMintableVariants(mintableVariants: mintableVariants)
943		}
944		
945		//NOTE: Customise
946		// mint not:
947		// address mint limit for variant has been hit √
948		// total maxSupply has been hit √
949		// maxSupply for variant has been hit √
950		// minting isn't open (!isOpen) √
951		// variant is not mintable √
952		// baseURI is not set √
953		// mint if:
954		// openAccess √
955		// OR address on access list √
956		// Output:
957		// NFT √
958		// nftMetadata √
959		// update mints per address √
960		// update total supply for variant √
961		//NOTE: !Used for CC payments via MoonPay!
962		access(all)
963		fun distributeDirectlyViaAccessList(receiver: &{NonFungibleToken.CollectionPublic}, publicMinterPathString: String, variantId: UInt64){ 
964			
965			// Ensure that the maximum supply of nfts for this contract has not been hit
966			if TheFabricantPrimalRave.maxSupply != nil{ 
967				assert(TheFabricantPrimalRave.totalSupply + 1 <= TheFabricantPrimalRave.maxSupply!, message: "Max supply for NFTs has been hit")
968			}
969			
970			// Check that address has not minted the maximum number of NFTs for this variant
971			assert(PrimalRaveVariantMintLimits.checkAddressCanMintVariant(address: (receiver.owner!).address, variantId: variantId), message: "Address has already minted the maximum for this variant")
972			
973			// Get the publicMinter details so we can apply all the correct props to the NFT
974			//NOTE: Therefore relies on a pM having been created
975			let publicPath = PublicPath(identifier: publicMinterPathString) ?? panic("Failed to construct public path from path string: ".concat(publicMinterPathString))
976			let publicMinterCap = getAccount((self.owner!).address).capabilities.get<&TheFabricantPrimalRave.PublicMinter>(publicPath).borrow() ?? panic("Couldn't get publicMinter ref or pathString is wrong: ".concat(publicMinterPathString))
977			let publicMinterDetails = publicMinterCap.getPublicMinterDetails()
978			
979			//Confirm that minting is open on the publicMinter
980			let isOpen = publicMinterDetails["isOpen"] as! Bool?
981			assert(isOpen!, message: "Minting is not open!")
982			
983			//Check that the address has access via the access list. If isOpenAccess, then anyone can mint.
984			let isOpenAccess = publicMinterDetails["isOpenAccess"] as! Bool?
985			let accessListId = publicMinterDetails["accessListId"] as! UInt64?
986			if !isOpenAccess!{ 
987				assert(TheFabricantAccessList.checkAccessForAddress(accessListDetailsId: accessListId!, address: (receiver.owner!).address), message: "User address is not on the access list and so cannot mint.")
988			}
989			
990			// Create the NFT
991			let license = publicMinterDetails["license"] as! MetadataViews.License?
992			let nft <- create NFT(variantId: variantId, originalRecipient: (receiver.owner!).address, license: license)
993			let name = publicMinterDetails["name"] as! String?
994			let description = publicMinterDetails["description"] as! String?
995			let collection = publicMinterDetails["collection"] as! String?
996			let externalURL = publicMinterDetails["externalURL"] as! MetadataViews.ExternalURL?
997			let coCreatable = publicMinterDetails["coCreatable"] as! Bool?
998			let revealableTraits = publicMinterDetails["revealableTraits"] as!{ String: Bool}?
999			let royalties = publicMinterDetails["royalties"] as! MetadataViews.Royalties?
1000			let royaltiesTFMarketplace = publicMinterDetails["royaltiesTFMarketplace"] as! TheFabricantMetadataViewsV2.Royalties?
1001			
1002			//Create the nftMetadata
1003			TheFabricantPrimalRave.createNftMetadata(id: nft.id, nftUuid: nft.uuid, variantId: variantId, collection: collection!, characteristics:{} , license: nft.license, externalURL: externalURL!, coCreatable: coCreatable!, coCreator: (receiver.owner!).address, editionNumber: nft.editionNumber, maxEditionNumber: nft.maxEditionNumber, revealableTraits: revealableTraits!, royalties: royalties!, royaltiesTFMarketplace: royaltiesTFMarketplace!)
1004			
1005			//NOTE: Event is emitted here and not in nft init because
1006			// data is split between RevealableMetadata and nft,
1007			// so not all event data is accessible during nft init
1008			emit ItemMintedAndTransferred(uuid: nft.uuid, id: nft.id, name: (TheFabricantPrimalRave.nftMetadata[nft.nftMetadataId]!).name, description: (TheFabricantPrimalRave.nftMetadata[nft.nftMetadataId]!).description, collection: (TheFabricantPrimalRave.nftMetadata[nft.nftMetadataId]!).collection, editionNumber: nft.editionNumber, originalRecipient: nft.originalRecipient, license: nft.license, nftMetadataId: nft.nftMetadataId)
1009			receiver.deposit(token: <-nft)
1010			
1011			// Increment the number of mints that an address has
1012			if TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address] != nil{ 
1013				TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address] = TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address]! + 1
1014			} else{ 
1015				TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address] = 1
1016			}
1017			
1018			// Increment the number of mints for this variant
1019			PrimalRaveVariantMintLimits.incrementVariantMintsForAddress(address: (receiver.owner!).address, variantId: variantId)
1020		}
1021		
1022		// NOTE: It is in the public minter that you would create the restrictions
1023		// for minting. 
1024		access(all)
1025		fun createPublicMinter(name: String, description: String, collection: String, license: MetadataViews.License?, externalURL: MetadataViews.ExternalURL, coCreatable: Bool, revealableTraits:{ String: Bool}, minterMintLimit: UInt64?, royalties: MetadataViews.Royalties, royaltiesTFMarketplace: TheFabricantMetadataViewsV2.Royalties, paymentAmount: UFix64, paymentType: Type, paymentSplit: MetadataViews.Royalties?, typeRestrictions: [Type], accessListId: UInt64){ 
1026			pre{ 
1027				TheFabricantPrimalRave.paymentReceiverCap != nil:
1028					"Please set the paymentReceiverCap before creating a minter"
1029			}
1030			let publicMinter: @TheFabricantPrimalRave.PublicMinter <- create PublicMinter(name: name, description: description, collection: collection, license: license, externalURL: externalURL, coCreatable: coCreatable, revealableTraits: revealableTraits, minterMintLimit: minterMintLimit, royalties: royalties, royaltiesTFMarketplace: royaltiesTFMarketplace, paymentAmount: paymentAmount, paymentType: paymentType, paymentSplit: paymentSplit, typeRestrictions: typeRestrictions, accessListId: accessListId)
1031			
1032			// Save path: name_collection_uuid
1033			// Link the Public Minter to a Public Path of the admin account
1034			let publicMinterStoragePath = StoragePath(identifier: publicMinter.path)
1035			let publicMinterPublicPath = PublicPath(identifier: publicMinter.path)
1036			TheFabricantPrimalRave.account.storage.save(<-publicMinter, to: publicMinterStoragePath!)
1037		}
1038		
1039		access(all)
1040		fun revealTraits(nftMetadataId: UInt64, traits: [{RevealableV2.RevealableTrait}]){ 
1041			let nftMetadata = TheFabricantPrimalRave.nftMetadata[nftMetadataId]! as! TheFabricantPrimalRave.RevealableMetadata
1042			nftMetadata.revealTraits(traits: traits)
1043			TheFabricantPrimalRave.nftMetadata[nftMetadataId] = nftMetadata
1044			
1045			// Event should be emitted in resource, not struct
1046			var i = 1
1047			while i < traits.length{ 
1048				let traitName = traits[i].name
1049				let traitValue = traits[i].value
1050				emit TraitRevealed(nftUuid: nftMetadata.nftUuid, id: nftMetadata.id, trait: traitName)
1051				i = i + 1
1052			}
1053			emit ItemRevealed(uuid: nftMetadata.nftUuid, id: nftMetadata.id, name: nftMetadata.name, description: nftMetadata.description, collection: nftMetadata.collection, editionNumber: nftMetadata.editionNumber, originalRecipient: nftMetadata.coCreator, license: nftMetadata.license, nftMetadataId: nftMetadata.id, externalURL: nftMetadata.externalURL, coCreatable: nftMetadata.coCreatable, coCreator: nftMetadata.coCreator)
1054		}
1055		
1056		init(adminAddress: Address){ 
1057			emit AdminResourceCreated(uuid: self.uuid, adminAddress: adminAddress)
1058		}
1059	}
1060	
1061	// -----------------------------------------------------------------------
1062	// PublicMinter Resource
1063	// -----------------------------------------------------------------------
1064	// NOTE: The public minter is exposed via a capability to allow the public
1065	// to mint the NFT so long as they meet the criteria.
1066	// It is in the public minter that the various mint functions would be exposed
1067	// such as paid mint etc.
1068	// Every contract has to manage its own minting via the PublicMinter.
1069	//NOTE: Customise
1070	// Update the mint functions
1071	access(all)
1072	resource interface Minter{ 
1073		access(all)
1074		fun mintUsingAccessList(receiver: &{NonFungibleToken.CollectionPublic}, payment: @{FungibleToken.Vault}, variantId: UInt64)
1075		
1076		access(all)
1077		fun getPublicMinterDetails():{ String: AnyStruct}
1078	}
1079	
1080	access(all)
1081	resource PublicMinter: TheFabricantNFTStandardV2.TFNFTPublicMinter, Minter{ 
1082		access(all)
1083		var path: String
1084		
1085		access(all)
1086		var isOpen: Bool
1087		
1088		access(all)
1089		var isAccessListOnly: Bool
1090		
1091		access(all)
1092		var isOpenAccess: Bool
1093		
1094		// NOTE: Remove these as required and update the NFT props and 
1095		// resolveView to reflect this, so that views that this nft
1096		// does not display are not provided
1097		// Name of nft, not campaign. This will be combined with the edition number
1098		access(all)
1099		let name: String
1100		
1101		access(all)
1102		let description: String
1103		
1104		access(all)
1105		let collection: String
1106		
1107		access(all)
1108		let license: MetadataViews.License?
1109		
1110		access(all)
1111		let externalURL: MetadataViews.ExternalURL
1112		
1113		access(all)
1114		let coCreatable: Bool
1115		
1116		access(all)
1117		let revealableTraits:{ String: Bool}
1118		
1119		// NOTE: The max number of mints this pM can do (eg multiple NFTs, a different minter for each one. Each NFT has a max number of mints allowed).
1120		access(all)
1121		var minterMintLimit: UInt64?
1122		
1123		access(all)
1124		var numberOfMints: UInt64
1125		
1126		access(all)
1127		let royalties: MetadataViews.Royalties
1128		
1129		access(all)
1130		let royaltiesTFMarketplace: TheFabricantMetadataViewsV2.Royalties
1131		
1132		access(all)
1133		var paymentAmount: UFix64
1134		
1135		access(all)
1136		let paymentType: Type
1137		
1138		// paymentSplit: How much each address gets paid on minting of NFT
1139		access(all)
1140		let paymentSplit: MetadataViews.Royalties?
1141		
1142		access(all)
1143		var typeRestrictions: [Type]?
1144		
1145		access(all)
1146		var accessListId: UInt64
1147		
1148		access(all)
1149		fun changeIsOpenAccess(isOpenAccess: Bool){ 
1150			self.isOpenAccess = isOpenAccess
1151			emit PublicMinterIsOpenAccessChanged(uuid: self.uuid, name: self.name, description: self.description, collection: self.collection, path: self.path, isOpenAccess: self.isOpenAccess, isAccessListOnly: self.isAccessListOnly, isOpen: self.isOpen)
1152		}
1153		
1154		access(all)
1155		fun changeIsAccessListOnly(isAccessListOnly: Bool){ 
1156			self.isAccessListOnly = isAccessListOnly
1157			emit PublicMinterIsAccessListOnly(uuid: self.uuid, name: self.name, description: self.description, collection: self.collection, path: self.path, isOpenAccess: self.isOpenAccess, isAccessListOnly: self.isAccessListOnly, isOpen: self.isOpen)
1158		}
1159		
1160		access(all)
1161		fun changeMintingIsOpen(isOpen: Bool){ 
1162			self.isOpen = isOpen
1163			emit PublicMinterMintingIsOpen(uuid: self.uuid, name: self.name, description: self.description, collection: self.collection, path: self.path, isOpenAccess: self.isOpenAccess, isAccessListOnly: self.isAccessListOnly, isOpen: self.isOpen)
1164		}
1165		
1166		access(all)
1167		fun setAccessListId(accessListId: UInt64){ 
1168			self.accessListId = accessListId
1169			emit PublicMinterSetAccessListId(uuid: self.uuid, name: self.name, description: self.description, collection: self.collection, path: self.path, isOpenAccess: self.isOpenAccess, isAccessListOnly: self.isAccessListOnly, isOpen: self.isOpen, accessListId: self.accessListId)
1170		}
1171		
1172		access(all)
1173		fun setPaymentAmount(amount: UFix64){ 
1174			self.paymentAmount = amount
1175			emit PublicMinterSetPaymentAmount(uuid: self.uuid, name: self.name, description: self.description, collection: self.collection, path: self.path, isOpenAccess: self.isOpenAccess, isAccessListOnly: self.isAccessListOnly, isOpen: self.isOpen, paymentAmount: self.paymentAmount)
1176		}
1177		
1178		access(all)
1179		fun setMinterMintLimit(minterMintLimit: UInt64){ 
1180			self.minterMintLimit = minterMintLimit
1181			emit PublicMinterSetMinterMintLimit(uuid: self.uuid, name: self.name, description: self.description, collection: self.collection, path: self.path, isOpenAccess: self.isOpenAccess, isAccessListOnly: self.isAccessListOnly, isOpen: self.isOpen, minterMintLimit: self.minterMintLimit)
1182		}
1183		
1184		// The owner of the pM can access this via borrow in tx.
1185		access(all)
1186		fun updateTypeRestrictions(types: [Type]){ 
1187			self.typeRestrictions = types
1188		}
1189		
1190		//NOTE: Customise
1191		// mint not:
1192		// address mint limit for variant has been hit √
1193		// maxMint for this address has been hit √
1194		// total maxSupply has been hit √
1195		// maxSupply for variant has been hit √
1196		// minting isn't open (!isOpen) √
1197		// payment is insufficient √
1198		// minterMintLimit is hit √
1199		// variant is not mintable √
1200		// baseURI is not set √
1201		// mint if:
1202		// openAccess √
1203		// OR address on access list √
1204		// Output:
1205		// NFT √
1206		// nftMetadata √
1207		// update mints per address √
1208		// update total supply for variant √
1209		access(all)
1210		fun mintUsingAccessList(receiver: &{NonFungibleToken.CollectionPublic}, payment: @{FungibleToken.Vault}, variantId: UInt64){ 
1211			pre{ 
1212				self.isOpen:
1213					"Minting is not currently open!"
1214				payment.isInstance(self.paymentType):
1215					"payment vault is not requested fungible token"
1216				TheFabricantPrimalRave.paymentReceiverCap != nil:
1217					"Payment Receiver Cap must be set for minting!"
1218			}
1219			post{ 
1220				receiver.getIDs().length == before(receiver.getIDs().length) + 1:
1221					"Minted NFT must be deposited into Collection"
1222			}
1223			assert(payment.balance == (TheFabricantPrimalRave.variants[variantId]!).paymentAmount, message: "Payment amount is incorrect")
1224			
1225			// Check that address has not minted the maximum number of NFTs for this variant
1226			assert(PrimalRaveVariantMintLimits.checkAddressCanMintVariant(address: (receiver.owner!).address, variantId: variantId), message: "Address has already minted the maximum for this variant")
1227			
1228			// Total number of mints by this pM
1229			self.numberOfMints = self.numberOfMints + 1
1230			
1231			// Ensure that minterMintLimit for this pM has not been hit
1232			if self.minterMintLimit != nil{ 
1233				assert(self.numberOfMints <= self.minterMintLimit!, message: "Maximum number of mints for this public minter has been hit")
1234			}
1235			
1236			// Ensure that the maximum supply of nfts for this contract has not been hit
1237			if TheFabricantPrimalRave.maxSupply != nil{ 
1238				assert(TheFabricantPrimalRave.totalSupply + 1 <= TheFabricantPrimalRave.maxSupply!, message: "Max supply for NFTs has been hit")
1239			}
1240			
1241			// Ensure user hasn't minted more NFTs from this contract than allowed
1242			if TheFabricantPrimalRave.addressMintLimit != nil{ 
1243				if TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address] != nil{ 
1244					assert(TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address]! < TheFabricantPrimalRave.addressMintLimit!, message: "User has already minted the maximum allowance per address!")
1245				}
1246			}
1247			
1248			// Check that the address has access via the access list. If isOpenAccess, then anyone can mint.
1249			if !self.isOpenAccess{ 
1250				assert(TheFabricantAccessList.checkAccessForAddress(accessListDetailsId: self.accessListId, address: (receiver.owner!).address), message: "User address is not on the access list and so cannot mint.")
1251			}
1252			
1253			// Settle Payment ONLY if variant is not free
1254			if (TheFabricantPrimalRave.variants[variantId]!).paymentAmount != 0.0{ 
1255				if let _paymentSplit = self.paymentSplit{ 
1256					var i = 0
1257					let splits = _paymentSplit.getRoyalties()
1258					while i < splits.length{ 
1259						let split = splits[i]
1260						let receiver = split.receiver
1261						let cut = split.cut
1262						let paymentAmount = self.paymentAmount * cut
1263						if let wallet = receiver.borrow(){ 
1264							let pay <- payment.withdraw(amount: paymentAmount)
1265							emit MintPaymentSplitDeposited(address: (wallet.owner!).address, price: self.paymentAmount, amount: pay.balance, nftUuid: self.uuid)
1266							wallet.deposit(from: <-pay)
1267						}
1268						i = i + 1
1269					}
1270				}
1271			}
1272			if payment.balance != 0.0 || payment.balance == 0.0{ 
1273				// pay rest to TF
1274				emit MintPaymentSplitDeposited(address: (TheFabricantPrimalRave.paymentReceiverCap!).address, price: self.paymentAmount, amount: payment.balance, nftUuid: self.uuid)
1275			}
1276			((			  // Deposit has to occur outside of above if statement as resource must be moved or destroyed
1277			  TheFabricantPrimalRave.paymentReceiverCap!).borrow()!).deposit(from: <-payment)
1278			let nft <- create NFT(variantId: variantId, originalRecipient: (receiver.owner!).address, license: self.license)
1279			TheFabricantPrimalRave.createNftMetadata(id: nft.id, nftUuid: nft.uuid, variantId: variantId, collection: self.collection, characteristics:{} , license: nft.license, externalURL: self.externalURL, coCreatable: self.coCreatable, coCreator: (receiver.owner!).address, editionNumber: nft.editionNumber, maxEditionNumber: nft.maxEditionNumber, revealableTraits: self.revealableTraits, royalties: self.royalties, royaltiesTFMarketplace: self.royaltiesTFMarketplace)
1280			
1281			//NOTE: Event is emitted here and not in nft init because
1282			// data is split between RevealableMetadata and nft,
1283			// so not all event data is accessible during nft init
1284			emit ItemMintedAndTransferred(uuid: nft.uuid, id: nft.id, name: (TheFabricantPrimalRave.nftMetadata[nft.nftMetadataId]!).name, description: (TheFabricantPrimalRave.nftMetadata[nft.nftMetadataId]!).description, collection: (TheFabricantPrimalRave.nftMetadata[nft.nftMetadataId]!).collection, editionNumber: nft.editionNumber, originalRecipient: nft.originalRecipient, license: self.license, nftMetadataId: nft.nftMetadataId)
1285			receiver.deposit(token: <-nft)
1286			
1287			// Increment the number of mints that an address has
1288			if TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address] != nil{ 
1289				TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address] = TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address]! + 1
1290			} else{ 
1291				TheFabricantPrimalRave.addressMintCount[(receiver.owner!).address] = 1
1292			}
1293			
1294			// Increment the number of mints for this variant
1295			PrimalRaveVariantMintLimits.incrementVariantMintsForAddress(address: (receiver.owner!).address, variantId: variantId)
1296		}
1297		
1298		access(all)
1299		fun getPublicMinterDetails():{ String: AnyStruct}{ 
1300			let ret:{ String: AnyStruct} ={} 
1301			ret["name"] = self.name
1302			ret["uuid"] = self.uuid
1303			ret["path"] = self.path
1304			ret["isOpen"] = self.isOpen
1305			ret["isAccessListOnly"] = self.isAccessListOnly
1306			ret["isOpenAccess"] = self.isOpenAccess
1307			ret["description"] = self.description
1308			ret["collection"] = self.collection
1309			ret["collectionId"] = TheFabricantPrimalRave.collectionId
1310			ret["license"] = self.license
1311			ret["externalURL"] = self.externalURL
1312			ret["coCreatable"] = self.coCreatable
1313			ret["revealableTraits"] = self.revealableTraits
1314			ret["minterMintLimit"] = self.minterMintLimit
1315			ret["numberOfMints"] = self.numberOfMints
1316			ret["royalties"] = self.royalties
1317			ret["royaltiesTFMarketplace"] = self.royaltiesTFMarketplace
1318			ret["paymentAmount"] = self.paymentAmount
1319			ret["paymentType"] = self.paymentType
1320			ret["paymentSplit"] = self.paymentSplit
1321			ret["typeRestrictions"] = self.typeRestrictions
1322			ret["accessListId"] = self.accessListId
1323			return ret
1324		}
1325		
1326		init(name: String, description: String, collection: String, license: MetadataViews.License?, externalURL: MetadataViews.ExternalURL, coCreatable: Bool, revealableTraits:{ String: Bool}, minterMintLimit: UInt64?, royalties: MetadataViews.Royalties, royaltiesTFMarketplace: TheFabricantMetadataViewsV2.Royalties, paymentAmount: UFix64, paymentType: Type, paymentSplit: MetadataViews.Royalties?, typeRestrictions: [Type], accessListId: UInt64){ 
1327			
1328			// Create and save path: name_collection_uuid
1329			let pathString = "TheFabricantNFTPublicMinter_TheFabricantPrimalRave_".concat(self.uuid.toString())
1330			TheFabricantPrimalRave.publicMinterPaths[self.uuid] = pathString
1331			self.path = pathString
1332			self.isOpen = false
1333			self.isAccessListOnly = true
1334			self.isOpenAccess = false
1335			self.name = name
1336			self.description = description
1337			self.collection = collection
1338			self.license = license
1339			self.externalURL = externalURL
1340			self.coCreatable = coCreatable
1341			self.revealableTraits = revealableTraits
1342			self.minterMintLimit = minterMintLimit
1343			self.numberOfMints = 0
1344			self.royalties = royalties
1345			self.royaltiesTFMarketplace = royaltiesTFMarketplace
1346			self.paymentAmount = paymentAmount
1347			self.paymentType = paymentType
1348			self.paymentSplit = paymentSplit
1349			self.typeRestrictions = typeRestrictions
1350			self.accessListId = accessListId
1351			emit PublicMinterCreated(uuid: self.uuid, name: name, description: description, collection: collection, path: self.path)
1352		}
1353	}
1354	
1355	// -----------------------------------------------------------------------
1356	// Private Utility Functions
1357	// -----------------------------------------------------------------------
1358	//NOTE: Customise
1359	// This function generates the metadata for the minted nft.
1360	access(contract)
1361	fun createNftMetadata(id: UInt64, nftUuid: UInt64, variantId: UInt64, collection: String, characteristics:{ String:{ CoCreatableV2.Characteristic}}, license: MetadataViews.License?, externalURL: MetadataViews.ExternalURL, coCreatable: Bool, coCreator: Address, editionNumber: UInt64, maxEditionNumber: UInt64?, revealableTraits:{ String: Bool}, royalties: MetadataViews.Royalties, royaltiesTFMarketplace: TheFabricantMetadataViewsV2.Royalties){ 
1362		pre{ 
1363			TheFabricantPrimalRave.baseTokenURI != nil:
1364				"Base URI must be set to mint an NFT!"
1365		}
1366		assert(TheFabricantPrimalRave.mintableVariants.contains(variantId), message: "Variant is not mintable")
1367		assert((TheFabricantPrimalRave.variants[variantId]!).canMintSupply(), message: "Variant has hit max supply for variant")
1368		
1369		// Get variant specific metadata
1370		let name: String = (TheFabricantPrimalRave.variants[variantId]!).name
1371		let description: String = (TheFabricantPrimalRave.variants[variantId]!).description
1372		var metadata:{ String: String} ={ "mainImage": (TheFabricantPrimalRave.baseTokenURI!).concat("/").concat(variantId.toString()).concat(".png"), "video": (TheFabricantPrimalRave.baseTokenURI!).concat("/").concat(variantId.toString()).concat(".mp4")}
1373		let mD = RevealableMetadata(id: id, nftUuid: nftUuid, name: name, description: description, collection: collection, metadata: metadata, characteristics: characteristics, license: license, externalURL: externalURL, coCreatable: coCreatable, coCreator: coCreator, editionNumber: editionNumber, maxEditionNumber: maxEditionNumber, revealableTraits: revealableTraits, royalties: royalties, royaltiesTFMarketplace: royaltiesTFMarketplace)
1374		TheFabricantPrimalRave.nftMetadata[id] = mD
1375	}
1376	
1377	access(self)
1378	fun nftsCanBeUsedForMint(receiver: &{NonFungibleToken.CollectionPublic}, refs: [&{NonFungibleToken.NFT}], typeRestrictions: [Type]): Bool{ 
1379		assert(typeRestrictions.length != 0, message: "There are no type restrictions for this promotion")
1380		var i = 0
1381		while i < refs.length{ 
1382			if typeRestrictions.contains(refs[i].getType()) && (receiver.owner!).address == (refs[i].owner!).address{ 
1383				return true
1384			}
1385			i = i + 1
1386		}
1387		return false
1388	}
1389	
1390	// -----------------------------------------------------------------------
1391	// Public Utility Functions
1392	// -----------------------------------------------------------------------
1393	// createEmptyCollection creates an empty Collection
1394	// and returns it to the caller so that they can own NFTs
1395	access(all)
1396	fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection}{ 
1397		return <-create Collection()
1398	}
1399	
1400	access(all)
1401	fun getPublicMinterPaths():{ UInt64: String}{ 
1402		return TheFabricantPrimalRave.publicMinterPaths
1403	}
1404	
1405	access(all)
1406	fun getNftIdsToOwner():{ UInt64: Address}{ 
1407		return TheFabricantPrimalRave.nftIdsToOwner
1408	}
1409	
1410	access(all)
1411	fun getMaxSupply(): UInt64?{ 
1412		return TheFabricantPrimalRave.maxSupply
1413	}
1414	
1415	access(all)
1416	fun getTotalSupply(): UInt64{ 
1417		return TheFabricantPrimalRave.totalSupply
1418	}
1419	
1420	access(all)
1421	fun getCollectionId(): String?{ 
1422		return TheFabricantPrimalRave.collectionId
1423	}
1424	
1425	access(all)
1426	fun getNftMetadatas():{ UInt64:{ RevealableV2.RevealableMetadata}}{ 
1427		return self.nftMetadata
1428	}
1429	
1430	access(all)
1431	fun getVariantInfo(variantId: UInt64): VariantInfo?{ 
1432		return TheFabricantPrimalRave.variants[variantId]
1433	}
1434	
1435	access(all)
1436	fun getVariants():{ UInt64: VariantInfo}{ 
1437		return TheFabricantPrimalRave.variants
1438	}
1439	
1440	access(all)
1441	fun getVariantSupplies():{ UInt64:{ String: UInt64}}{ 
1442		var ret:{ UInt64:{ String: UInt64}} ={} 
1443		var i: UInt64 = 1
1444		while i <= UInt64(TheFabricantPrimalRave.variants.length){ 
1445			ret[i] ={ "maxSupply": (TheFabricantPrimalRave.variants[i]!).supply, "totalSupply": (TheFabricantPrimalRave.variants[i]!).totalSupply}
1446			i = i + 1
1447		}
1448		return ret
1449	}
1450	
1451	access(all)
1452	fun getMintableVariants(): [UInt64]{ 
1453		return TheFabricantPrimalRave.mintableVariants
1454	}
1455	
1456	access(all)
1457	fun getPaymentCap(): Address?{ 
1458		return TheFabricantPrimalRave.paymentReceiverCap?.address
1459	}
1460	
1461	access(all)
1462	fun getBaseUri(): String?{ 
1463		return TheFabricantPrimalRave.baseTokenURI
1464	}
1465
1466	access(all)
1467	view fun getContractViews(resourceType: Type?): [Type]{ 
1468		return []
1469	}
1470
1471	access(all)
1472	view fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct?{ 
1473		return nil
1474	}
1475	
1476	// -----------------------------------------------------------------------
1477	// Contract Init
1478	// -----------------------------------------------------------------------
1479	init(){ 
1480		self.totalSupply = 0
1481		self.publicMinterPaths ={} 
1482		self.collectionId = nil
1483		self.nftIdsToOwner ={} 
1484		self.addressMintCount ={} 
1485		self.paymentReceiverCap = nil
1486		self.nftMetadata ={} 
1487		self.addressMintLimit = nil
1488		self.baseTokenURI = nil
1489		
1490		// Used to calculate maxSupply
1491		let v1Supply: UInt64 = 475
1492		let v2Supply: UInt64 = 275
1493		let v3Supply: UInt64 = 350
1494		let v4Supply: UInt64 = 5025
1495		let v5Supply: UInt64 = 375
1496		let v6Supply: UInt64 = 275
1497		let v7Supply: UInt64 = 275
1498		let v8Supply: UInt64 = 5025
1499		self.maxSupply = v1Supply + v2Supply + v3Supply + v4Supply + v5Supply + v6Supply + v7Supply + v8Supply
1500		self.variants ={ 1: VariantInfo(id: 1, name: "Hardcore Happiness", description: "Where are we headed, can you feel the excitement in the air? The journey is about to begin. Right before you go to the party, the excitement can even make you a little nauseous. Eating the forbidden fruit is also known as breaking free of conventions. Can you shift your paradigm? Are you open to rediscover new parts of yourself you forgot existed, yet were here all along?", paymentAmount: 70.0, supply: v1Supply), 2: VariantInfo(id: 2, name: "Door Bitch", description: "We all judge, all the time. It is our mechanism. Discrimination is the ability to distinguish things. We need it, yet it has gotten such a heavy load in our culture. Can we see beyond the boundaries, beyond the binaries, and discover the true nature is all made of the same anyway? Our souls are all the same and we have all lived multiple lives. Will you get into the club in this lifetime or the next?", paymentAmount: 50.0, supply: v2Supply), 3: VariantInfo(id: 3, name: "Skullfck", description: "Take a good look at yourself in the mirror. Are you accepting all of you? Or does your darkness catch you off guard? Does it scare you, or can you fully accept it? We all have parts of ourselves we hide, but to embrace them is key to becoming whole.", paymentAmount: 30.0, supply: v3Supply), 4: VariantInfo(id: 4, name: "Pump Boots", description: "Dance from dusk till dawn in these platform pumps, emblazoned with the iconic acid house smiley and sad face. Featuring neon detailing across the vamp and heel, lighting the way on even the darkest dance floors.", paymentAmount: 0.0, supply: v4Supply), 5: VariantInfo(id: 5, name: "Curtain Calling", description: "Enter a world of desire, longing and infatuation. Intoxicate yourself with the beauty of these pleasures, but only to widen your perspective. Are you able to admire the beauty without losing yourself in it? Only then you are worthy of entering xthis holy space.. Shaking the bum and hips was used in ancient temples to awaken the pelvic floor and get the energy moving in your body.", paymentAmount: 30.0, supply: v5Supply), 6: VariantInfo(id: 6, name: "Forbidden Fruit", description: "Your core is shaking. Foundations are melting. When you accept your whole self, the ground will melt away under your feet first. If you let yourself melt, accept it fully, only then can you rise from the dark waters.", paymentAmount: 50.0, supply: v6Supply), 7: VariantInfo(id: 7, name: "Ecstasy", description: "If, and only if we can accept ourselves fully, we realize that we are all the parts we played in the game. We shine bright like never before, embracing ourselves in all our fullness. We realize we are everything already anyway, and nothing at the same time. These are just layers of identity, which is not our true self. We cut away anything that is not true and shine our colors in that. We don\u{2019}t need to eat anything to become something, because we are the fruit ourselves.", paymentAmount: 70.0, supply: v7Supply), 8: VariantInfo(id: 8, name: "Lace Boots", description: "Extended version of the pumps boots reaching knee high with fitted fluorescent backs and open front laced up. Neon detailing across the vamp and heel, lighting the way on the darkest dance floors.", paymentAmount: 0.0, supply: v8Supply)}
1501		self.mintableVariants = [1, 2, 3, 4]
1502		self.TheFabricantPrimalRaveCollectionStoragePath = /storage/TheFabricantPrimalRaveCollectionStoragePath
1503		self.TheFabricantPrimalRaveCollectionPublicPath = /public/TheFabricantPrimalRaveCollectionPublicPath
1504		self.TheFabricantPrimalRaveProviderStoragePath = /private/TheFabricantPrimalRaveProviderStoragePath
1505		self.TheFabricantPrimalRaveAdminStoragePath = /storage/TheFabricantPrimalRaveAdminStoragePath
1506		self.TheFabricantPrimalRavePublicMinterStoragePath = /storage/TheFabricantPrimalRavePublicMinterStoragePath
1507		self.TheFabricantPrimalRavePublicMinterPublicPath = /public/TheFabricantPrimalRavePublicMinterPublicPath
1508		self.account.storage.save(<-create Admin(adminAddress: self.account.address), to: self.TheFabricantPrimalRaveAdminStoragePath)
1509		emit ContractInitialized()
1510	}
1511}
1512