Smart Contract

Weekday

A.7752ea736384322f.Weekday

Deployed

3h ago
Feb 28, 2026, 08:14:46 PM UTC

Dependents

0 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
19access(all)
20contract Weekday: NonFungibleToken, TheFabricantNFTStandardV2, RevealableV2{ 
21	
22	// -----------------------------------------------------------------------
23	// Paths
24	// -----------------------------------------------------------------------
25	access(all)
26	let WeekdayCollectionStoragePath: StoragePath
27	
28	access(all)
29	let WeekdayCollectionPublicPath: PublicPath
30	
31	access(all)
32	let WeekdayProviderStoragePath: PrivatePath
33	
34	access(all)
35	let WeekdayPublicMinterStoragePath: StoragePath
36	
37	access(all)
38	let WeekdayAdminStoragePath: StoragePath
39	
40	access(all)
41	let WeekdayPublicMinterPublicPath: PublicPath
42	
43	// -----------------------------------------------------------------------
44	// Contract Events
45	// -----------------------------------------------------------------------
46	// Event that emitted when the NFT contract is initialized
47	//
48	access(all)
49	event ContractInitialized()
50	
51	access(all)
52	event ItemMintedAndTransferred(uuid: UInt64, id: UInt64, name: String, description: String, collection: String, editionNumber: UInt64, originalRecipient: Address, license: MetadataViews.License?, nftMetadataId: UInt64)
53	
54	access(all)
55	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)
56	
57	access(all)
58	event TraitRevealed(nftUuid: UInt64, id: UInt64, trait: String)
59	
60	access(all)
61	event IsTraitRevealableV2Updated(nftUuid: UInt64, id: UInt64, trait: String, isRevealableV2: Bool)
62	
63	access(all)
64	event MintPaymentSplitDeposited(address: Address, price: UFix64, amount: UFix64, nftUuid: UInt64)
65	
66	access(all)
67	event ItemDestroyed(uuid: UInt64, id: UInt64, name: String, description: String, collection: String)
68	
69	access(all)
70	event PublicMinterCreated(uuid: UInt64, name: String, description: String, collection: String, path: String)
71	
72	access(all)
73	event PublicMinterIsOpenAccessChanged(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool)
74	
75	access(all)
76	event PublicMinterIsAccessListOnly(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool)
77	
78	access(all)
79	event PublicMinterMintingIsOpen(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool)
80	
81	access(all)
82	event PublicMinterSetAccessListId(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool, accessListId: UInt64)
83	
84	access(all)
85	event PublicMinterSetPaymentAmount(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool, paymentAmount: UFix64)
86	
87	access(all)
88	event PublicMinterSetMinterMintLimit(uuid: UInt64, name: String, description: String, collection: String, path: String, isOpenAccess: Bool, isAccessListOnly: Bool, isOpen: Bool, minterMintLimit: UInt64?)
89	
90	access(all)
91	event AdminResourceCreated(uuid: UInt64, adminAddress: Address)
92	
93	access(all)
94	event AdminPaymentReceiverCapabilityChanged(address: Address, paymentType: Type)
95	
96	access(all)
97	event AdminSetMaxSupply(maxSupply: UInt64)
98	
99	access(all)
100	event AdminSetAddressMintLimit(addressMintLimit: UInt64)
101	
102	access(all)
103	event AdminSetCollectionId(collectionId: String)
104	
105	access(all)
106	event AdminSetBaseURI(baseURI: String)
107	
108	// Event that is emitted when a token is withdrawn,
109	// indicating the owner of the collection that it was withdrawn from.
110	//
111	// If the collection is not in an account's storage, `from` will be `nil`.
112	//
113	access(all)
114	event Withdraw(id: UInt64, from: Address?)
115	
116	// Event that emitted when a token is deposited to a collection.
117	//
118	// It indicates the owner of the collection that it was deposited to.
119	//
120	access(all)
121	event Deposit(id: UInt64, to: Address?)
122	
123	// -----------------------------------------------------------------------
124	// Contract State
125	// -----------------------------------------------------------------------
126	// NOTE: This is updated anywhere ownership of the nft is changed - on minting and therefore on deposit
127	access(contract)
128	var nftIdsToOwner:{ UInt64: Address}
129	
130	access(contract)
131	var publicMinterPaths:{ UInt64: String}
132	
133	// NOTE: this is contract-level so all minters can access it.
134	// Keeps track of the number of times an address has minted
135	access(contract)
136	var addressMintCount:{ Address: UInt64}
137	
138	// Receives payment for minting
139	access(contract)
140	var paymentReceiverCap: Capability<&{FungibleToken.Receiver}>?
141	
142	access(contract)
143	var nftMetadata:{ UInt64:{ RevealableV2.RevealableMetadata}}
144	
145	// The total number of tokens of this type in existence
146	// NOTE: All public minters use totalSupply to assign the next
147	// id and edition number. Each public minter has a minterMintLimit property
148	// that defines the max no. of mints a pM can do. 
149	access(all)
150	var totalSupply: UInt64
151	
152	// NOTE: The max number of NFTs in this collection that will ever be minted
153	// Init as nil if there is no max. 
154	access(all)
155	var maxSupply: UInt64?
156	
157	// NOTE: Max mints per address
158	access(all)
159	var addressMintLimit: UInt64?
160	
161	//NOTE: uuid of collection added to NFT and used by BE
162	access(all)
163	var collectionId: String?
164	
165	access(contract)
166	var baseTokenURI: String?
167	
168	// -----------------------------------------------------------------------
169	// RevealableV2 Metadata Struct
170	// -----------------------------------------------------------------------
171	access(all)
172	struct RevealableMetadata: RevealableV2.RevealableMetadata{ 
173		
174		//NOTE: totalSupply value of attached NFT, therefore edition number. 
175		access(all)
176		let id: UInt64
177		
178		// NOTE: !IMPORTANT! nftUuid is the uuid of the associated nft.
179		// This RevealableMetadata struct should be stored in the nftMetadata dict under this
180		// value. This is because the uuid is used across contracts for identification purposes
181		access(all)
182		let nftUuid: UInt64 // uuid of NFT
183		
184		
185		// NOTE: Name of NFT. 
186		// Will be combined with the edition number on the application
187		// Doesn't include the edition number.
188		access(all)
189		var name: String
190		
191		access(all)
192		var description: String //Display
193		
194		
195		// NOTE: Thumbnail, which is needed for the Display view, should be set using one of the
196		// media properties
197		//access(all) let thumbnail: String //Display
198		access(all)
199		let collection: String // Name of collection eg The Fabricant > Season 3 > Wholeland > XXories Originals
200		
201		
202		// Stores the metadata that describes this particular creation,
203		// but is not part of a characteristic eg mainImage, video etc
204		access(all)
205		var metadata:{ String: AnyStruct}
206		
207		// This is where the user-chosed characteristics live. This represents
208		// the data that in older contracts, would've been separate NFTs.		
209		access(all)
210		var characteristics:{ String:{ CoCreatableV2.Characteristic}}
211		
212		access(all)
213		var rarity: UFix64?
214		
215		access(all)
216		var rarityDescription: String?
217		
218		// NOTE: Media is not implemented in the struct because MetadataViews.Medias
219		// is not mutable, so can't be updated. In addition, each 
220		// NFT collection might have a different number of image/video properties.
221		// Instead, the NFT should implement a function that rolls up the props
222		// into a MetadataViews.Medias struct
223		//access(all) let media: MetadataViews.Medias //Media
224		access(all)
225		let license: MetadataViews.License? //License
226		
227		
228		access(all)
229		let externalURL: MetadataViews.ExternalURL //ExternalURL
230		
231		
232		access(all)
233		let coCreatable: Bool
234		
235		access(all)
236		let coCreator: Address
237		
238		access(all)
239		var isRevealed: Bool?
240		
241		// id and editionNumber might not be the same in the nft...
242		access(all)
243		let editionNumber: UInt64 //Edition
244		
245		
246		access(all)
247		let maxEditionNumber: UInt64?
248		
249		access(all)
250		let royalties: MetadataViews.Royalties //Royalty
251		
252		
253		access(all)
254		let royaltiesTFMarketplace: TheFabricantMetadataViewsV2.Royalties
255		
256		access(contract)
257		var revealableTraits:{ String: Bool}
258		
259		access(all)
260		fun getRevealableTraits():{ String: Bool}{ 
261			return self.revealableTraits
262		}
263		
264		//NOTE: Customise
265		//NOTE: This should be updated for each campaign contract!
266		// Called by the Admin to reveal the traits for this NFT.
267		// Should contain a switch function that knows how to modify
268		// the properties of this struct. Should check that the trait
269		// being revealed is allowed to be modified.
270		access(contract)
271		fun revealTraits(traits: [{RevealableV2.RevealableTrait}]){ 
272			//TODO: This is dependent upon what will be saved in this specific campaign
273			// nft.
274			var i = 0
275			while i < traits.length{ 
276				let RevealableTrait = traits[i]
277				let traitName = RevealableTrait.name
278				let traitValue = RevealableTrait.value
279				switch traitName{ 
280					case "mainImage":
281						assert(self.checkRevealableTrait(traitName: traitName)!, message: "UnRevealableV2 trait passed in - please ensure trait can be revealed: ".concat(traitName))
282						self.updateMetadata(key: traitName, value: traitValue)
283					case "video":
284						assert(self.checkRevealableTrait(traitName: traitName)!, message: "UnRevealableV2 trait passed in - please ensure trait can be revealed: ".concat(traitName))
285						self.updateMetadata(key: traitName, value: traitValue)
286					default:
287						panic("UnRevealableV2 trait passed in - please ensure trait can be revealed: ".concat(traitName))
288				}
289				i = i + 1
290			}
291			self.isRevealed = true
292		}
293		
294		access(contract)
295		fun updateMetadata(key: String, value: AnyStruct){ 
296			self.metadata[key] = value
297		}
298		
299		// Called by the nft owner to modify if a trait can be 
300		// revealed or not - used to revoke admin access
301		access(all)
302		fun updateIsTraitRevealable(key: String, value: Bool){ 
303			self.revealableTraits[key] = value
304		}
305		
306		access(all)
307		fun checkRevealableTrait(traitName: String): Bool?{ 
308			if let RevealableV2 = self.revealableTraits[traitName]{ 
309				return RevealableV2
310			}
311			return nil
312		}
313		
314		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){ 
315			self.id = id
316			self.nftUuid = nftUuid
317			self.name = name
318			self.description = description
319			self.collection = collection
320			self.metadata = metadata
321			self.characteristics = characteristics
322			self.rarity = nil
323			self.rarityDescription = nil
324			self.license = license
325			self.externalURL = externalURL
326			self.coCreatable = coCreatable
327			self.coCreator = coCreator
328			//NOTE: Customise
329			// This should be nil if the nft can't be revealed!
330			self.isRevealed = true
331			self.editionNumber = editionNumber
332			self.maxEditionNumber = maxEditionNumber
333			self.revealableTraits = revealableTraits
334			self.royalties = royalties
335			self.royaltiesTFMarketplace = royaltiesTFMarketplace
336		}
337	}
338	
339	// -----------------------------------------------------------------------
340	// Trait Struct
341	// -----------------------------------------------------------------------
342	// Used by txs to target traits/characteristics to be revealed
343	access(all)
344	struct Trait: RevealableV2.RevealableTrait{ 
345		access(all)
346		let name: String
347		
348		access(all)
349		let value: AnyStruct
350		
351		init(name: String, value: AnyStruct){ 
352			self.name = name
353			self.value = value
354		}
355	}
356	
357	// -----------------------------------------------------------------------
358	// NFT Resource
359	// -----------------------------------------------------------------------
360	// Restricted scope for borrowWeekday() in Collection.
361	// Ensures that the returned NFT ref is read only.
362	access(all)
363	resource interface PublicNFT{ 
364		access(all)
365		fun getFullName(): String
366		
367		access(all)
368		fun getEditions(): MetadataViews.Editions
369		
370		access(all)
371		fun getMedias(): MetadataViews.Medias
372		
373		access(all)
374		fun getTraits(): MetadataViews.Traits?
375		
376		access(all)
377		view fun getRarity(): MetadataViews.Rarity?
378		
379		access(all)
380		fun getExternalRoyalties(): MetadataViews.Royalties
381		
382		access(all)
383		fun getTFRoyalties(): TheFabricantMetadataViewsV2.Royalties
384		
385		access(all)
386		fun getMetadata():{ String: AnyStruct}
387		
388		access(all)
389		fun getCharacteristics():{ String:{ CoCreatableV2.Characteristic}}?
390		
391		access(all)
392		fun getDisplay(): MetadataViews.Display
393		
394		access(all)
395		fun getCollectionData(): MetadataViews.NFTCollectionData
396		
397		access(all)
398		fun getCollectionDisplay(): MetadataViews.NFTCollectionDisplay
399		
400		access(all)
401		fun getNFTView(): MetadataViews.NFTView
402		
403		access(all)
404		fun getViews(): [Type]
405		
406		access(all)
407		fun resolveView(_ view: Type): AnyStruct?
408	}
409	
410	access(all)
411	resource NFT: TheFabricantNFTStandardV2.TFNFT, NonFungibleToken.NFT, ViewResolver.Resolver, PublicNFT{ 
412		access(all)
413		let id: UInt64
414		
415		// NOTE: Ensure that the name for the nft is correct. This 
416		// will be shown to users. It should not include the edition number.
417		access(contract)
418		let collectionId: String
419		
420		access(contract)
421		let editionNumber: UInt64 //Edition
422		
423		
424		access(contract)
425		let maxEditionNumber: UInt64?
426		
427		access(contract)
428		let originalRecipient: Address
429		
430		access(contract)
431		let license: MetadataViews.License?
432		
433		access(contract)
434		let nftMetadataId: UInt64
435		
436		access(all)
437		fun getFullName(): String{ 
438			return ((Weekday.nftMetadata[self.nftMetadataId]!).name!).concat(" #".concat(self.editionNumber.toString()))
439		}
440		
441		// NOTE: This is important for Edition view
442		access(all)
443		fun getEditionName(): String{ 
444			return (Weekday.nftMetadata[self.nftMetadataId]!).collection
445		}
446		
447		access(all)
448		fun getEditions(): MetadataViews.Editions{ 
449			// NOTE: In this case, id == edition number
450			let edition = MetadataViews.Edition(name: (Weekday.nftMetadata[self.nftMetadataId]!).collection, number: self.editionNumber, max: Weekday.maxSupply)
451			return MetadataViews.Editions([edition])
452		}
453		
454		//NOTE: Customise
455		//NOTE: This will be different for each campaign, determined by how
456		// many media files there are and their keys in metadata! Pay attention
457		// to where the media files are stored and therefore accessed
458		access(all)
459		fun getMedias(): MetadataViews.Medias{ 
460			let nftMetadata = Weekday.nftMetadata[self.id]!
461			let mainImage = nftMetadata.metadata["mainImage"]! as! String
462			// NOTE: This assumes that when the shoeShape characteristic is created
463			// in the update_shoe_shapes_char tx, the value property is created as a dictionary
464			let video = nftMetadata.metadata["video"]! as! String
465			let mainImageMedia = MetadataViews.Media(file: MetadataViews.HTTPFile(url: mainImage), mediaType: "image/png")
466			let videoMedia = MetadataViews.Media(file: MetadataViews.HTTPFile(url: video), mediaType: "video/mp4")
467			return MetadataViews.Medias([mainImageMedia, videoMedia])
468		}
469		
470		// NOTE: Customise
471		access(all)
472		fun getImages():{ String: String}{ 
473			let nftMetadata = Weekday.nftMetadata[self.id]!
474			let mainImage = nftMetadata.metadata["mainImage"]! as! String
475			return{ "mainImage": mainImage}
476		}
477		
478		// NOTE: Customise
479		access(all)
480		fun getVideos():{ String: String}{ 
481			let nftMetadata = Weekday.nftMetadata[self.id]!
482			let mainVideo = nftMetadata.metadata["video"]! as! String
483			return{ "mainVideo": mainVideo}
484		}
485		
486		// NOTE: Customise
487		// What are the traits that you want external marketplaces
488		// to display?
489		access(all)
490		fun getTraits(): MetadataViews.Traits?{ 
491			return nil
492		}
493		
494		access(all)
495		view fun getRarity(): MetadataViews.Rarity?{ 
496			return nil
497		}
498		
499		access(all)
500		fun getExternalRoyalties(): MetadataViews.Royalties{ 
501			let nftMetadata = Weekday.nftMetadata[self.id]!
502			return nftMetadata.royalties
503		}
504		
505		access(all)
506		fun getTFRoyalties(): TheFabricantMetadataViewsV2.Royalties{ 
507			let nftMetadata = Weekday.nftMetadata[self.id]!
508			return nftMetadata.royaltiesTFMarketplace
509		}
510		
511		access(all)
512		fun getMetadata():{ String: AnyStruct}{ 
513			return (Weekday.nftMetadata[self.id]!).metadata
514		}
515		
516		//NOTE: This is not a CoCreatableV2 NFT, so no characteristics are present
517		access(all)
518		fun getCharacteristics():{ String:{ CoCreatableV2.Characteristic}}?{ 
519			return nil
520		}
521		
522		access(all)
523		fun getRevealableTraits():{ String: Bool}?{ 
524			return (Weekday.nftMetadata[self.id]!).getRevealableTraits()
525		}
526		
527		//NOTE: The first file in medias will be the thumbnail.
528		// Maybe put a file type check in here to ensure it is 
529		// an image?
530		access(all)
531		fun getDisplay(): MetadataViews.Display{ 
532			return MetadataViews.Display(name: self.getFullName(), description: (Weekday.nftMetadata[self.nftMetadataId]!).description, thumbnail: self.getMedias().items[0].file)
533		}
534		
535		access(all)
536		fun getCollectionData(): MetadataViews.NFTCollectionData{ 
537			return MetadataViews.NFTCollectionData(storagePath: Weekday.WeekdayCollectionStoragePath, publicPath: Weekday.WeekdayCollectionPublicPath, publicCollection: Type<&Weekday.Collection>(), publicLinkedType: Type<&Weekday.Collection>(), createEmptyCollectionFunction: fun (): @{NonFungibleToken.Collection}{ 
538					return <-Weekday.createEmptyCollection(nftType: Type<@Weekday.Collection>())
539				})
540		}
541		
542		//NOTE: Customise
543		// NOTE: Update this function with the collection display image
544		// and TF socials
545		access(all)
546		fun getCollectionDisplay(): MetadataViews.NFTCollectionDisplay{ 
547			let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://weekday-collection-display.s3.eu-central-1.amazonaws.com/images/WD_squareImage.png"), mediaType: "image/png")
548			let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://weekday-collection-display.s3.eu-central-1.amazonaws.com/images/WD_bannerImage.jpeg"), mediaType: "image/png")
549			return MetadataViews.NFTCollectionDisplay(name: self.getEditionName(), description: "Enter Artifact 001, a limited-edition collection of digital collectibles complete with AR filters, and physical accessories for the citizens of tomorrow. The items, inspired by mineral formations, are part of a collab between Weekday and digital fashion house The Fabricant. Consider them locked in time, always remaining as they find their way to new owners. Make your move now, history doesn\u{2019}t wait.", externalURL: (Weekday.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")})
550		}
551		
552		access(all)
553		fun getNFTView(): MetadataViews.NFTView{ 
554			return MetadataViews.NFTView(id: self.id, uuid: self.uuid, display: self.getDisplay(), externalURL: (Weekday.nftMetadata[self.id]!).externalURL, collectionData: self.getCollectionData(), collectionDisplay: self.getCollectionDisplay(), royalties: (Weekday.nftMetadata[self.id]!).royalties, traits: self.getTraits())
555		}
556		
557		access(all)
558		view fun getViews(): [Type]{ 
559			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>()]
560			return viewArray
561		}
562		
563		access(all)
564		fun resolveView(_ view: Type): AnyStruct?{ 
565			switch view{ 
566				case Type<TheFabricantMetadataViewsV2.TFNFTIdentifierV1>():
567					return TheFabricantMetadataViewsV2.TFNFTIdentifierV1(uuid: self.uuid, id: self.id, name: self.getFullName(), collection: (Weekday.nftMetadata[self.nftMetadataId]!).collection, editions: self.getEditions(), address: (self.owner!).address, originalRecipient: self.originalRecipient)
568				case Type<TheFabricantMetadataViewsV2.TFNFTSimpleView>():
569					return TheFabricantMetadataViewsV2.TFNFTSimpleView(uuid: self.uuid, id: self.id, name: self.getFullName(), description: (Weekday.nftMetadata[self.nftMetadataId]!).description, collection: (Weekday.nftMetadata[self.nftMetadataId]!).collection, collectionId: Weekday.collectionId!, metadata: self.getMetadata(), media: self.getMedias(), images: self.getImages(), videos: self.getVideos(), externalURL: (Weekday.nftMetadata[self.id]!).externalURL, rarity: self.getRarity(), traits: self.getTraits(), characteristics: self.getCharacteristics(), coCreatable: (Weekday.nftMetadata[self.id]!).coCreatable, coCreator: (Weekday.nftMetadata[self.id]!).coCreator, isRevealed: (Weekday.nftMetadata[self.id]!).isRevealed, editions: self.getEditions(), originalRecipient: self.originalRecipient, royalties: (Weekday.nftMetadata[self.id]!).royalties, royaltiesTFMarketplace: (Weekday.nftMetadata[self.id]!).royaltiesTFMarketplace, revealableTraits: self.getRevealableTraits(), address: (self.owner!).address)
570				case Type<MetadataViews.NFTView>():
571					return self.getNFTView()
572				case Type<MetadataViews.Display>():
573					return self.getDisplay()
574				case Type<MetadataViews.Editions>():
575					return self.getEditions()
576				case Type<MetadataViews.Serial>():
577					return self.id
578				case Type<MetadataViews.Royalties>():
579					return Weekday.nftMetadata[self.id]?.royalties
580				case Type<MetadataViews.Medias>():
581					return self.getMedias()
582				case Type<MetadataViews.License>():
583					return self.license
584				case Type<MetadataViews.ExternalURL>():
585					return Weekday.nftMetadata[self.id]?.externalURL
586				case Type<MetadataViews.NFTCollectionData>():
587					return self.getCollectionData()
588				case Type<MetadataViews.NFTCollectionDisplay>():
589					return self.getCollectionDisplay()
590				case Type<MetadataViews.Rarity>():
591					return self.getRarity()
592				case Type<MetadataViews.Traits>():
593					return self.getTraits()
594			}
595			return nil
596		}
597		
598		access(all)
599		fun updateIsTraitRevealable(key: String, value: Bool){ 
600			let nftMetadata = Weekday.nftMetadata[self.id]!
601			nftMetadata.updateIsTraitRevealable(key: key, value: value)
602			Weekday.nftMetadata[self.id] = nftMetadata
603			emit IsTraitRevealableV2Updated(nftUuid: nftMetadata.nftUuid, id: nftMetadata.id, trait: key, isRevealableV2: value)
604		}
605		
606		access(all)
607		fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
608			return <-create Collection()
609		}
610		
611		init(originalRecipient: Address, license: MetadataViews.License?){ 
612			assert(Weekday.collectionId != nil, message: "Ensure that Admin has set collectionId in the contract")
613			Weekday.totalSupply = Weekday.totalSupply + 1
614			self.id = Weekday.totalSupply
615			self.collectionId = Weekday.collectionId!
616			
617			// NOTE: Customise
618			// The edition number may need to be different to id
619			// for some campaigns
620			self.editionNumber = self.id
621			self.maxEditionNumber = Weekday.maxSupply
622			self.originalRecipient = originalRecipient
623			self.license = license
624			self.nftMetadataId = self.id
625		}
626	}
627	
628	// -----------------------------------------------------------------------
629	// Collection Resource
630	// -----------------------------------------------------------------------
631	access(all)
632	resource interface WeekdayCollectionPublic{ 
633		access(all)
634		fun borrowWeekday(id: UInt64): &Weekday.NFT?
635		
636		access(all)
637		fun deposit(token: @{NonFungibleToken.NFT})
638		
639		access(all)
640		fun getIDs(): [UInt64]
641		
642		access(all)
643		view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
644
645		access(all)
646		view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}?
647	}
648	
649	access(all)
650	resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, NonFungibleToken.CollectionPublic, WeekdayCollectionPublic, ViewResolver.ResolverCollection{ 
651		
652		// Dictionary to hold the NFTs in the Collection
653		access(all)
654		var ownedNFTs: @{UInt64:{ NonFungibleToken.NFT}}
655		
656		access(all)
657		view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}?{ 
658			let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
659			let Weekday = nft as! &Weekday.NFT
660			return Weekday as &{ViewResolver.Resolver}
661		}
662		
663		// withdraw removes an NFT from the collection and moves it to the caller
664		access(NonFungibleToken.Withdraw)
665		fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT}{ 
666			// Remove the nft from the Collection
667			let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Cannot withdraw: NFT does not exist in the collection")
668			emit Withdraw(id: token.id, from: self.owner?.address)
669			
670			// Return the withdrawn token
671			return <-token
672		}
673		
674		// deposit takes an NFT and adds it to the collections dictionary
675		// and adds the ID to the id array
676		access(all)
677		fun deposit(token: @{NonFungibleToken.NFT}){ 
678			// By ensuring self.owner.address is not nil we keep the nftIdsToOwner dict 
679			// up to date.
680			pre{ 
681				self.owner?.address != nil:
682					"The Collection resource must be stored in a users account"
683			}
684			
685			// Cast the deposited token as  NFT to make sure
686			// it is the correct type
687			let token <- token as! @NFT
688			
689			// Get the token's ID
690			let id = token.id
691			
692			// Add the new token to the dictionary
693			let oldToken <- self.ownedNFTs[id] <- token
694			Weekday.nftIdsToOwner[id] = (self.owner!).address
695			emit Deposit(id: id, to: self.owner?.address)
696			
697			// Destroy the empty old token that was "removed"
698			destroy oldToken
699		}
700		
701		// getIDs returns an array of the IDs that are in the collection
702		access(all)
703		view fun getIDs(): [UInt64]{ 
704			return self.ownedNFTs.keys
705		}
706		
707		// Returns a borrowed reference to an NFT in the collection
708		// so that the caller can read data and call methods from it
709		access(all)
710		view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?{ 
711			return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
712		}
713		
714		access(all)
715		fun borrowWeekday(id: UInt64): &Weekday.NFT?{ 
716			if self.ownedNFTs[id] != nil{ 
717				// Create an authorized reference to allow downcasting
718				let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
719				return ref as! &Weekday.NFT
720			}
721			return nil
722		}
723		
724		access(all)
725		view fun getSupportedNFTTypes():{ Type: Bool}{ 
726			panic("implement me")
727		}
728		
729		access(all)
730		view fun isSupportedNFTType(type: Type): Bool{ 
731			panic("implement me")
732		}
733		
734		access(all)
735		fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
736			return <-create Collection()
737		}
738		
739		// If a transaction destroys the Collection object,
740		// All the NFTs contained within are also destroyed!
741		//
742		init(){ 
743			self.ownedNFTs <-{} 
744		}
745	}
746	
747	// -----------------------------------------------------------------------
748	// Admin Resource
749	// -----------------------------------------------------------------------
750	access(all)
751	resource Admin{ 
752		access(all)
753		fun setPublicReceiverCap(paymentReceiverCap: Capability<&{FungibleToken.Receiver}>){ 
754			Weekday.paymentReceiverCap = paymentReceiverCap
755			emit AdminPaymentReceiverCapabilityChanged(address: paymentReceiverCap.address, paymentType: paymentReceiverCap.getType())
756		}
757		
758		access(all)
759		fun setBaseURI(baseURI: String){ 
760			Weekday.baseTokenURI = baseURI
761			emit AdminSetBaseURI(baseURI: baseURI)
762		}
763		
764		// The max supply determines the maximum number of NFTs that can be minted from this contract
765		access(all)
766		fun setMaxSupply(maxSupply: UInt64){ 
767			Weekday.maxSupply = maxSupply
768			emit AdminSetMaxSupply(maxSupply: maxSupply)
769		}
770		
771		access(all)
772		fun setAddressMintLimit(addressMintLimit: UInt64){ 
773			Weekday.addressMintLimit = addressMintLimit
774			emit AdminSetAddressMintLimit(addressMintLimit: addressMintLimit)
775		}
776		
777		access(all)
778		fun setCollectionId(collectionId: String){ 
779			Weekday.collectionId = collectionId
780			emit AdminSetCollectionId(collectionId: collectionId)
781		}
782		
783		//NOTE: Customise
784		// mint not:
785		// maxSupply has been hit √
786		// minting isn't open (!isOpen) √
787		// mint if:
788		// openAccess √
789		// OR address on access list √
790		// Output:
791		// NFT √
792		// nftMetadata √
793		// update mints per address √
794		//NOTE: !Used for CC payments via MoonPay!
795		access(all)
796		fun distributeDirectlyViaAccessList(receiver: &{NonFungibleToken.CollectionPublic}, publicMinterPathString: String, variantId: UInt64){ 
797			
798			// Ensure that the maximum supply of nfts for this contract has not been hit
799			if Weekday.maxSupply != nil{ 
800				assert(Weekday.totalSupply + 1 <= Weekday.maxSupply!, message: "Max supply for NFTs has been hit")
801			}
802			
803			// Get the publicMinter details so we can apply all the correct props to the NFT
804			//NOTE: Therefore relies on a pM having been created
805			let publicPath = PublicPath(identifier: publicMinterPathString) ?? panic("Failed to construct public path from path string: ".concat(publicMinterPathString))
806			let publicMinterCap = getAccount((self.owner!).address).capabilities.get<&Weekday.PublicMinter>(publicPath).borrow() ?? panic("Couldn't get publicMinter ref or pathString is wrong: ".concat(publicMinterPathString))
807			let publicMinterDetails = publicMinterCap.getPublicMinterDetails()
808			
809			//Confirm that minting is open on the publicMinter
810			let isOpen = publicMinterDetails["isOpen"] as! Bool?
811			assert(isOpen!, message: "Minting is not open!")
812			
813			//Check that the address has access via the access list. If isOpenAccess, then anyone can mint.
814			let isOpenAccess = publicMinterDetails["isOpenAccess"] as! Bool?
815			let accessListId = publicMinterDetails["accessListId"] as! UInt64?
816			if !isOpenAccess!{ 
817				assert(TheFabricantAccessList.checkAccessForAddress(accessListDetailsId: accessListId!, address: (receiver.owner!).address), message: "User address is not on the access list and so cannot mint.")
818			}
819			
820			// Create the NFT
821			let license = publicMinterDetails["license"] as! MetadataViews.License?
822			let nft <- create NFT(originalRecipient: (receiver.owner!).address, license: license)
823			let name = publicMinterDetails["name"] as! String?
824			let description = publicMinterDetails["description"] as! String?
825			let collection = publicMinterDetails["collection"] as! String?
826			let externalURL = publicMinterDetails["externalURL"] as! MetadataViews.ExternalURL?
827			let coCreatable = publicMinterDetails["coCreatable"] as! Bool?
828			let revealableTraits = publicMinterDetails["revealableTraits"] as!{ String: Bool}?
829			let royalties = publicMinterDetails["royalties"] as! MetadataViews.Royalties?
830			let royaltiesTFMarketplace = publicMinterDetails["royaltiesTFMarketplace"] as! TheFabricantMetadataViewsV2.Royalties?
831			
832			//Create the nftMetadata
833			Weekday.createNftMetadata(id: nft.id, nftUuid: nft.uuid, variantId: variantId, name: name!, description: description!, 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!)
834			
835			//NOTE: Event is emitted here and not in nft init because
836			// data is split between RevealableMetadata and nft,
837			// so not all event data is accessible during nft init
838			emit ItemMintedAndTransferred(uuid: nft.uuid, id: nft.id, name: (Weekday.nftMetadata[nft.nftMetadataId]!).name, description: (Weekday.nftMetadata[nft.nftMetadataId]!).description, collection: (Weekday.nftMetadata[nft.nftMetadataId]!).collection, editionNumber: nft.editionNumber, originalRecipient: nft.originalRecipient, license: nft.license, nftMetadataId: nft.nftMetadataId)
839			receiver.deposit(token: <-nft)
840			
841			// Increment the number of mints that an address has
842			if Weekday.addressMintCount[(receiver.owner!).address] != nil{ 
843				Weekday.addressMintCount[(receiver.owner!).address] = Weekday.addressMintCount[(receiver.owner!).address]! + 1
844			} else{ 
845				Weekday.addressMintCount[(receiver.owner!).address] = 1
846			}
847		}
848		
849		// NOTE: It is in the public minter that you would create the restrictions
850		// for minting. 
851		access(all)
852		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){ 
853			pre{ 
854				Weekday.paymentReceiverCap != nil:
855					"Please set the paymentReceiverCap before creating a minter"
856			}
857			let publicMinter: @Weekday.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)
858			
859			// Save path: name_collection_uuid
860			// Link the Public Minter to a Public Path of the admin account
861			let publicMinterStoragePath = StoragePath(identifier: publicMinter.path)
862			let publicMinterPublicPath = PublicPath(identifier: publicMinter.path)
863			Weekday.account.storage.save(<-publicMinter, to: publicMinterStoragePath!)
864		}
865		
866		access(all)
867		fun revealTraits(nftMetadataId: UInt64, traits: [{RevealableV2.RevealableTrait}]){ 
868			let nftMetadata = Weekday.nftMetadata[nftMetadataId]! as! Weekday.RevealableMetadata
869			nftMetadata.revealTraits(traits: traits)
870			Weekday.nftMetadata[nftMetadataId] = nftMetadata
871			
872			// Event should be emitted in resource, not struct
873			var i = 1
874			while i < traits.length{ 
875				let traitName = traits[i].name
876				let traitValue = traits[i].value
877				emit TraitRevealed(nftUuid: nftMetadata.nftUuid, id: nftMetadata.id, trait: traitName)
878				i = i + 1
879			}
880			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)
881		}
882		
883		init(adminAddress: Address){ 
884			emit AdminResourceCreated(uuid: self.uuid, adminAddress: adminAddress)
885		}
886	}
887	
888	// -----------------------------------------------------------------------
889	// PublicMinter Resource
890	// -----------------------------------------------------------------------
891	// NOTE: The public minter is exposed via a capability to allow the public
892	// to mint the NFT so long as they meet the criteria.
893	// It is in the public minter that the various mint functions would be exposed
894	// such as paid mint etc.
895	// Every contract has to manage its own minting via the PublicMinter.
896	//NOTE: Customise
897	// Update the mint functions
898	access(all)
899	resource interface Minter{ 
900		access(all)
901		fun mintUsingAccessList(receiver: &{NonFungibleToken.CollectionPublic}, payment: @{FungibleToken.Vault}, variantId: UInt64)
902		
903		access(all)
904		fun getPublicMinterDetails():{ String: AnyStruct}
905	}
906	
907	access(all)
908	resource PublicMinter: TheFabricantNFTStandardV2.TFNFTPublicMinter, Minter{ 
909		access(all)
910		var path: String
911		
912		access(all)
913		var isOpen: Bool
914		
915		access(all)
916		var isAccessListOnly: Bool
917		
918		access(all)
919		var isOpenAccess: Bool
920		
921		// NOTE: Remove these as required and update the NFT props and 
922		// resolveView to reflect this, so that views that this nft
923		// does not display are not provided
924		// Name of nft, not campaign. This will be combined with the edition number
925		access(all)
926		let name: String
927		
928		access(all)
929		let description: String
930		
931		access(all)
932		let collection: String
933		
934		access(all)
935		let license: MetadataViews.License?
936		
937		access(all)
938		let externalURL: MetadataViews.ExternalURL
939		
940		access(all)
941		let coCreatable: Bool
942		
943		access(all)
944		let revealableTraits:{ String: Bool}
945		
946		// 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).
947		access(all)
948		var minterMintLimit: UInt64?
949		
950		access(all)
951		var numberOfMints: UInt64
952		
953		access(all)
954		let royalties: MetadataViews.Royalties
955		
956		access(all)
957		let royaltiesTFMarketplace: TheFabricantMetadataViewsV2.Royalties
958		
959		access(all)
960		var paymentAmount: UFix64
961		
962		access(all)
963		let paymentType: Type
964		
965		// paymentSplit: How much each address gets paid on minting of NFT
966		access(all)
967		let paymentSplit: MetadataViews.Royalties?
968		
969		access(all)
970		var typeRestrictions: [Type]?
971		
972		access(all)
973		var accessListId: UInt64
974		
975		access(all)
976		fun changeIsOpenAccess(isOpenAccess: Bool){ 
977			self.isOpenAccess = isOpenAccess
978			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)
979		}
980		
981		access(all)
982		fun changeIsAccessListOnly(isAccessListOnly: Bool){ 
983			self.isAccessListOnly = isAccessListOnly
984			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)
985		}
986		
987		access(all)
988		fun changeMintingIsOpen(isOpen: Bool){ 
989			self.isOpen = isOpen
990			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)
991		}
992		
993		access(all)
994		fun setAccessListId(accessListId: UInt64){ 
995			self.accessListId = accessListId
996			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)
997		}
998		
999		access(all)
1000		fun setPaymentAmount(amount: UFix64){ 
1001			self.paymentAmount = amount
1002			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)
1003		}
1004		
1005		access(all)
1006		fun setMinterMintLimit(minterMintLimit: UInt64){ 
1007			self.minterMintLimit = minterMintLimit
1008			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)
1009		}
1010		
1011		// The owner of the pM can access this via borrow in tx.
1012		access(all)
1013		fun updateTypeRestrictions(types: [Type]){ 
1014			self.typeRestrictions = types
1015		}
1016		
1017		//NOTE: Customise
1018		// mint not:
1019		// maxMint for this address has been hit √
1020		// maxSupply has been hit √
1021		// minting isn't open (!isOpen) √
1022		// payment is insufficient √
1023		// minterMintLimit is hit √
1024		// mint if:
1025		// openAccess √
1026		// OR address on access list √
1027		// Output:
1028		// NFT √
1029		// nftMetadata √
1030		// update mints per address √
1031		access(all)
1032		fun mintUsingAccessList(receiver: &{NonFungibleToken.CollectionPublic}, payment: @{FungibleToken.Vault}, variantId: UInt64){ 
1033			pre{ 
1034				self.isOpen:
1035					"Minting is not currently open!"
1036				payment.isInstance(self.paymentType):
1037					"payment vault is not requested fungible token"
1038				payment.balance == self.paymentAmount:
1039					"Incorrect payment amount provided for minting"
1040				Weekday.paymentReceiverCap != nil:
1041					"Payment Receiver Cap must be set for minting!"
1042			}
1043			post{ 
1044				receiver.getIDs().length == before(receiver.getIDs().length) + 1:
1045					"Minted NFT must be deposited into Collection"
1046			}
1047			
1048			// Total number of mints by this pM
1049			self.numberOfMints = self.numberOfMints + 1
1050			
1051			// Ensure that minterMintLimit for this pM has not been hit
1052			if self.minterMintLimit != nil{ 
1053				assert(self.numberOfMints <= self.minterMintLimit!, message: "Maximum number of mints for this public minter has been hit")
1054			}
1055			
1056			// Ensure that the maximum supply of nfts for this contract has not been hit
1057			if Weekday.maxSupply != nil{ 
1058				assert(Weekday.totalSupply + 1 <= Weekday.maxSupply!, message: "Max supply for NFTs has been hit")
1059			}
1060			
1061			// Ensure user hasn't minted more NFTs from this contract than allowed
1062			if Weekday.addressMintLimit != nil{ 
1063				if Weekday.addressMintCount[(receiver.owner!).address] != nil{ 
1064					assert(Weekday.addressMintCount[(receiver.owner!).address]! < Weekday.addressMintLimit!, message: "User has already minted the maximum allowance per address!")
1065				}
1066			}
1067			
1068			// Check that the address has access via the access list. If isOpenAccess, then anyone can mint.
1069			if !self.isOpenAccess{ 
1070				assert(TheFabricantAccessList.checkAccessForAddress(accessListDetailsId: self.accessListId, address: (receiver.owner!).address), message: "User address is not on the access list and so cannot mint.")
1071			}
1072			
1073			// Settle Payment
1074			if let _paymentSplit = self.paymentSplit{ 
1075				var i = 0
1076				let splits = _paymentSplit.getRoyalties()
1077				while i < splits.length{ 
1078					let split = splits[i]
1079					let receiver = split.receiver
1080					let cut = split.cut
1081					let paymentAmount = self.paymentAmount * cut
1082					if let wallet = receiver.borrow(){ 
1083						let pay <- payment.withdraw(amount: paymentAmount)
1084						emit MintPaymentSplitDeposited(address: (wallet.owner!).address, price: self.paymentAmount, amount: pay.balance, nftUuid: self.uuid)
1085						wallet.deposit(from: <-pay)
1086					}
1087					i = i + 1
1088				}
1089			}
1090			if payment.balance != 0.0 || payment.balance == 0.0{ 
1091				// pay rest to TF
1092				emit MintPaymentSplitDeposited(address: (Weekday.paymentReceiverCap!).address, price: self.paymentAmount, amount: payment.balance, nftUuid: self.uuid)
1093			}
1094			((			  // Deposit has to occur outside of above if statement as resource must be moved or destroyed
1095			  Weekday.paymentReceiverCap!).borrow()!).deposit(from: <-payment)
1096			let nft <- create NFT(originalRecipient: (receiver.owner!).address, license: self.license)
1097			Weekday.createNftMetadata(id: nft.id, nftUuid: nft.uuid, variantId: variantId, name: self.name, description: self.description, 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)
1098			
1099			//NOTE: Event is emitted here and not in nft init because
1100			// data is split between RevealableMetadata and nft,
1101			// so not all event data is accessible during nft init
1102			emit ItemMintedAndTransferred(uuid: nft.uuid, id: nft.id, name: (Weekday.nftMetadata[nft.nftMetadataId]!).name, description: (Weekday.nftMetadata[nft.nftMetadataId]!).description, collection: (Weekday.nftMetadata[nft.nftMetadataId]!).collection, editionNumber: nft.editionNumber, originalRecipient: nft.originalRecipient, license: self.license, nftMetadataId: nft.nftMetadataId)
1103			receiver.deposit(token: <-nft)
1104			
1105			// Increment the number of mints that an address has
1106			if Weekday.addressMintCount[(receiver.owner!).address] != nil{ 
1107				Weekday.addressMintCount[(receiver.owner!).address] = Weekday.addressMintCount[(receiver.owner!).address]! + 1
1108			} else{ 
1109				Weekday.addressMintCount[(receiver.owner!).address] = 1
1110			}
1111		}
1112		
1113		access(all)
1114		fun getPublicMinterDetails():{ String: AnyStruct}{ 
1115			let ret:{ String: AnyStruct} ={} 
1116			ret["name"] = self.name
1117			ret["uuid"] = self.uuid
1118			ret["path"] = self.path
1119			ret["isOpen"] = self.isOpen
1120			ret["isAccessListOnly"] = self.isAccessListOnly
1121			ret["isOpenAccess"] = self.isOpenAccess
1122			ret["description"] = self.description
1123			ret["collection"] = self.collection
1124			ret["collectionId"] = Weekday.collectionId
1125			ret["license"] = self.license
1126			ret["externalURL"] = self.externalURL
1127			ret["coCreatable"] = self.coCreatable
1128			ret["revealableTraits"] = self.revealableTraits
1129			ret["minterMintLimit"] = self.minterMintLimit
1130			ret["numberOfMints"] = self.numberOfMints
1131			ret["royalties"] = self.royalties
1132			ret["royaltiesTFMarketplace"] = self.royaltiesTFMarketplace
1133			ret["paymentAmount"] = self.paymentAmount
1134			ret["paymentType"] = self.paymentType
1135			ret["paymentSplit"] = self.paymentSplit
1136			ret["typeRestrictions"] = self.typeRestrictions
1137			ret["accessListId"] = self.accessListId
1138			return ret
1139		}
1140		
1141		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){ 
1142			
1143			// Create and save path: name_collection_uuid
1144			let pathString = "TheFabricantNFTPublicMinter_Weekday_".concat(self.uuid.toString())
1145			Weekday.publicMinterPaths[self.uuid] = pathString
1146			self.path = pathString
1147			self.isOpen = false
1148			self.isAccessListOnly = true
1149			self.isOpenAccess = false
1150			self.name = name
1151			self.description = description
1152			self.collection = collection
1153			self.license = license
1154			self.externalURL = externalURL
1155			self.coCreatable = coCreatable
1156			self.revealableTraits = revealableTraits
1157			self.minterMintLimit = minterMintLimit
1158			self.numberOfMints = 0
1159			self.royalties = royalties
1160			self.royaltiesTFMarketplace = royaltiesTFMarketplace
1161			self.paymentAmount = paymentAmount
1162			self.paymentType = paymentType
1163			self.paymentSplit = paymentSplit
1164			self.typeRestrictions = typeRestrictions
1165			self.accessListId = accessListId
1166			emit PublicMinterCreated(uuid: self.uuid, name: name, description: description, collection: collection, path: self.path)
1167		}
1168	}
1169	
1170	// -----------------------------------------------------------------------
1171	// Private Utility Functions
1172	// -----------------------------------------------------------------------
1173	//NOTE: Customise
1174	// This function generates the metadata for the minted nft.
1175	access(contract)
1176	fun createNftMetadata(id: UInt64, nftUuid: UInt64, variantId: UInt64, name: String, description: String, 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){ 
1177		pre{ 
1178			Weekday.baseTokenURI != nil:
1179				"Base URI must be set to mint an NFT!"
1180			variantId == 1 || variantId == 2:
1181				"Variant ID must be either 1 or 2"
1182		}
1183		var nftName: String = ""
1184		var nftDescription: String = ""
1185		var metadata:{ String: String} ={} 
1186		switch variantId{ 
1187			case 1:
1188				nftName = "Dark Stalactite"
1189				nftDescription = "Molded in the shade, headed into the unknown. Dark stalactite is a powerful collectible eager to unfold its full AR-potential when the owner decides to. Respond to it."
1190				metadata ={ "mainImage": (Weekday.baseTokenURI!).concat("/DarkStalactite.png"), "video": (Weekday.baseTokenURI!).concat("/DarkStalactite.mp4")}
1191			case 2:
1192				nftName = "Light Stalactite"
1193				nftDescription = "Born to deflect harmful rays and betraying looks. Light stalactite will enhance the everyday life of its owner with just the right amount of AR-magic."
1194				metadata ={ "mainImage": (Weekday.baseTokenURI!).concat("/LightStalactite.png"), "video": (Weekday.baseTokenURI!).concat("/LightStalactite.mp4")}
1195		}
1196		let mD = RevealableMetadata(id: id, nftUuid: nftUuid, name: nftName, description: nftDescription, collection: collection, metadata: metadata, characteristics: characteristics, license: license, externalURL: externalURL, coCreatable: coCreatable, coCreator: coCreator, editionNumber: editionNumber, maxEditionNumber: maxEditionNumber, revealableTraits: revealableTraits, royalties: royalties, royaltiesTFMarketplace: royaltiesTFMarketplace)
1197		Weekday.nftMetadata[id] = mD
1198	}
1199	
1200	access(self)
1201	fun nftsCanBeUsedForMint(receiver: &{NonFungibleToken.CollectionPublic}, refs: [&{NonFungibleToken.NFT}], typeRestrictions: [Type]): Bool{ 
1202		assert(typeRestrictions.length != 0, message: "There are no type restrictions for this promotion")
1203		var i = 0
1204		while i < refs.length{ 
1205			if typeRestrictions.contains(refs[i].getType()) && (receiver.owner!).address == (refs[i].owner!).address{ 
1206				return true
1207			}
1208			i = i + 1
1209		}
1210		return false
1211	}
1212	
1213	// -----------------------------------------------------------------------
1214	// Public Utility Functions
1215	// -----------------------------------------------------------------------
1216	// createEmptyCollection creates an empty Collection
1217	// and returns it to the caller so that they can own NFTs
1218	access(all)
1219	fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection}{ 
1220		return <-create Collection()
1221	}
1222	
1223	access(all)
1224	fun getPublicMinterPaths():{ UInt64: String}{ 
1225		return Weekday.publicMinterPaths
1226	}
1227	
1228	access(all)
1229	fun getNftIdsToOwner():{ UInt64: Address}{ 
1230		return Weekday.nftIdsToOwner
1231	}
1232	
1233	access(all)
1234	fun getMaxSupply(): UInt64?{ 
1235		return Weekday.maxSupply
1236	}
1237	
1238	access(all)
1239	fun getTotalSupply(): UInt64{ 
1240		return Weekday.totalSupply
1241	}
1242	
1243	access(all)
1244	fun getCollectionId(): String?{ 
1245		return Weekday.collectionId
1246	}
1247	
1248	access(all)
1249	fun getNftMetadatas():{ UInt64:{ RevealableV2.RevealableMetadata}}{ 
1250		return self.nftMetadata
1251	}
1252	
1253	access(all)
1254	fun getPaymentCap(): Address?{ 
1255		return Weekday.paymentReceiverCap?.address
1256	}
1257	
1258	access(all)
1259	fun getBaseUri(): String?{ 
1260		return Weekday.baseTokenURI
1261	}
1262
1263	access(all)
1264	view fun getContractViews(resourceType: Type?): [Type]{ 
1265		return []
1266	}
1267
1268	access(all)
1269	view fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct?{ 
1270		return nil
1271	}
1272	
1273	// -----------------------------------------------------------------------
1274	// Contract Init
1275	// -----------------------------------------------------------------------
1276	init(){ 
1277		self.totalSupply = 0
1278		self.maxSupply = nil
1279		self.publicMinterPaths ={} 
1280		self.collectionId = nil
1281		self.nftIdsToOwner ={} 
1282		self.addressMintCount ={} 
1283		self.paymentReceiverCap = nil
1284		self.nftMetadata ={} 
1285		self.addressMintLimit = nil
1286		self.baseTokenURI = nil
1287		self.WeekdayCollectionStoragePath = /storage/WeekdayCollectionStoragePath
1288		self.WeekdayCollectionPublicPath = /public/WeekdayCollectionPublicPath
1289		self.WeekdayProviderStoragePath = /private/WeekdayProviderStoragePath
1290		self.WeekdayAdminStoragePath = /storage/WeekdayAdminStoragePath
1291		self.WeekdayPublicMinterStoragePath = /storage/WeekdayPublicMinterStoragePath
1292		self.WeekdayPublicMinterPublicPath = /public/WeekdayPublicMinterPublicPath
1293		self.account.storage.save(<-create Admin(adminAddress: self.account.address), to: self.WeekdayAdminStoragePath)
1294		emit ContractInitialized()
1295	}
1296}
1297