Smart Contract

TouchstoneSnowyGlobez

A.c4b1f4387748f389.TouchstoneSnowyGlobez

Deployed

1d ago
Feb 26, 2026, 11:04:48 PM UTC

Dependents

0 imports
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448 
3import FungibleToken from 0xf233dcee88fe0abe
4import FlowToken from 0x1654653399040a61
5import ViewResolver from 0x1d7e57aa55817448
6
7// CREATED BY: Touchstone (https://touchstone.city/), a platform crafted by your best friends at Emerald City DAO (https://ecdao.org/).
8// STATEMENT: This contract promises to keep the 5% royalty off of primary sales and 2.5% off of secondary sales to Emerald City DAO or risk permanent suspension from participation in the DAO and its tools.
9
10// import "NonFungibleToken"
11// import "MetadataViews"
12// import "FungibleToken"
13// import "FlowToken"
14// import "ViewResolver"
15
16// import "MintVerifiers"  
17// import "FUSD"
18// import "EmeraldPass"
19
20access(all) contract TouchstoneSnowyGlobez: NonFungibleToken {
21
22	// Collection Information
23	access(self) let collectionInfo: {String: AnyStruct}
24
25	// Contract Information
26	access(all) var nextEditionId: UInt64
27	access(all) var nextMetadataId: UInt64
28	access(all) var totalSupply: UInt64
29
30	// Events
31	access(all) event ContractInitialized()
32	access(all) event Withdraw(id: UInt64, from: Address?)
33	access(all) event Deposit(id: UInt64, to: Address?)
34	access(all) event TouchstonePurchase(id: UInt64, recipient: Address, metadataId: UInt64, name: String, description: String, image: MetadataViews.IPFSFile, price: UFix64)
35	access(all) event Minted(id: UInt64, recipient: Address, metadataId: UInt64)
36	access(all) event MintBatch(metadataIds: [UInt64], recipients: [Address])
37
38	// Paths
39	access(all) let CollectionStoragePath: StoragePath
40	access(all) let CollectionPublicPath: PublicPath
41	access(all) let CollectionPrivatePath: PrivatePath
42	access(all) let AdministratorStoragePath: StoragePath
43
44	// Maps metadataId of NFT to NFTMetadata
45	access(account) let metadatas: {UInt64: NFTMetadata}
46
47	// Maps the metadataId of an NFT to the primary buyer
48	access(account) let primaryBuyers: {Address: {UInt64: [UInt64]}}
49
50	access(account) let nftStorage: @{Address: {UInt64: NFT}}
51
52	access(all) struct NFTMetadata {
53		access(all) let metadataId: UInt64
54		access(all) let name: String
55		access(all) let description: String 
56		// The main image of the NFT
57		access(all) let image: MetadataViews.IPFSFile
58		// An optional thumbnail that can go along with it
59		// for easier loading
60		access(all) let thumbnail: MetadataViews.IPFSFile?
61		// If price is nil, defaults to the collection price
62		access(all) let price: UFix64?
63		access(all) var extra: {String: AnyStruct}
64		access(all) let supply: UInt64
65		access(all) let purchasers: {UInt64: Address}
66
67		access(account) fun purchased(serial: UInt64, buyer: Address) {
68			self.purchasers[serial] = buyer
69		}
70
71		init(_name: String, _description: String, _image: MetadataViews.IPFSFile, _thumbnail: MetadataViews.IPFSFile?, _price: UFix64?, _extra: {String: AnyStruct}, _supply: UInt64) {
72			self.metadataId = TouchstoneSnowyGlobez.nextMetadataId
73			self.name = _name
74			self.description = _description
75			self.image = _image
76			self.thumbnail = _thumbnail
77			self.price = _price
78			self.extra = _extra
79			self.supply = _supply
80			self.purchasers = {}
81		}
82	}
83
84	access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver {
85		// The 'id' is the same as the 'uuid'
86		access(all) let id: UInt64
87		// The 'metadataId' is what maps this NFT to its 'NFTMetadata'
88		access(all) let metadataId: UInt64
89		access(all) let serial: UInt64
90
91		access(all) view fun getMetadata(): NFTMetadata {
92			return TouchstoneSnowyGlobez.getNFTMetadata(self.metadataId)!
93		}
94
95		access(all) view fun getViews(): [Type] {
96			return [
97				Type<MetadataViews.Display>(),
98				Type<MetadataViews.ExternalURL>(),
99				Type<MetadataViews.NFTCollectionData>(),
100				Type<MetadataViews.NFTCollectionDisplay>(),
101				Type<MetadataViews.Royalties>(),
102				Type<MetadataViews.Serial>(),
103				Type<MetadataViews.Traits>(),
104				Type<MetadataViews.NFTView>()
105			]
106		}
107
108		access(all) fun resolveView(_ view: Type): AnyStruct? {
109			switch view {
110				case Type<MetadataViews.Display>():
111					let metadata = self.getMetadata()
112					return MetadataViews.Display(
113						name: metadata.name,
114						description: metadata.description,
115						thumbnail: metadata.thumbnail ?? metadata.image
116					)
117				case Type<MetadataViews.NFTCollectionData>():
118					return MetadataViews.NFTCollectionData(
119						storagePath: TouchstoneSnowyGlobez.CollectionStoragePath,
120						publicPath: TouchstoneSnowyGlobez.CollectionPublicPath,
121						publicCollection: Type<&Collection>(),
122						publicLinkedType: Type<&Collection>(),
123						createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
124								return <- TouchstoneSnowyGlobez.createEmptyCollection(nftType: Type<@TouchstoneSnowyGlobez.Collection>())
125						})
126					)
127				case Type<MetadataViews.ExternalURL>():
128          return MetadataViews.ExternalURL("https://touchstone.city/discover/".concat(self.owner!.address.toString()).concat("/TouchstoneSnowyGlobez"))
129				case Type<MetadataViews.NFTCollectionDisplay>():
130					let squareMedia = MetadataViews.Media(
131						file: TouchstoneSnowyGlobez.getCollectionAttribute(key: "image") as! MetadataViews.IPFSFile,
132						mediaType: "image"
133					)
134
135					// If a banner image exists, use it
136					// Otherwise, default to the main square image
137					var bannerMedia: MetadataViews.Media? = nil
138					if let bannerImage = TouchstoneSnowyGlobez.getOptionalCollectionAttribute(key: "bannerImage") as! MetadataViews.IPFSFile? {
139						bannerMedia = MetadataViews.Media(
140							file: bannerImage,
141							mediaType: "image"
142						)
143					}
144					return MetadataViews.NFTCollectionDisplay(
145						name: TouchstoneSnowyGlobez.getCollectionAttribute(key: "name") as! String,
146						description: TouchstoneSnowyGlobez.getCollectionAttribute(key: "description") as! String,
147						externalURL: MetadataViews.ExternalURL("https://touchstone.city/discover/".concat(self.owner!.address.toString()).concat("/TouchstoneSnowyGlobez")),
148						squareImage: squareMedia,
149						bannerImage: bannerMedia ?? squareMedia,
150						socials: TouchstoneSnowyGlobez.getCollectionAttribute(key: "socials") as! {String: MetadataViews.ExternalURL}
151					)
152				case Type<MetadataViews.Royalties>():
153					return MetadataViews.Royalties([
154						// This is for Emerald City in favor of producing Touchstone, a free platform for our users. Failure to keep this in the contract may result in permanent suspension from Emerald City.
155						MetadataViews.Royalty(
156							receiver: getAccount(0x5643fd47a29770e7).capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver),
157							cut: 0.025, // 2.5% royalty on secondary sales
158							description: "Emerald City DAO receives a 2.5% royalty from secondary sales because this collection was created using Touchstone (https://touchstone.city/), a tool for creating your own NFT collections, crafted by Emerald City DAO."
159						)
160					])
161				case Type<MetadataViews.Serial>():
162					return MetadataViews.Serial(
163						self.serial
164					)
165				case Type<MetadataViews.Traits>():
166					return MetadataViews.dictToTraits(dict: self.getMetadata().extra, excludedNames: nil)
167				case Type<MetadataViews.NFTView>():
168					return MetadataViews.NFTView(
169						id: self.id,
170						uuid: self.uuid,
171						display: self.resolveView(Type<MetadataViews.Display>()) as! MetadataViews.Display?,
172						externalURL: self.resolveView(Type<MetadataViews.ExternalURL>()) as! MetadataViews.ExternalURL?,
173						collectionData: self.resolveView(Type<MetadataViews.NFTCollectionData>()) as! MetadataViews.NFTCollectionData?,
174						collectionDisplay: self.resolveView(Type<MetadataViews.NFTCollectionDisplay>()) as! MetadataViews.NFTCollectionDisplay?,
175						royalties: self.resolveView(Type<MetadataViews.Royalties>()) as! MetadataViews.Royalties?,
176						traits: self.resolveView(Type<MetadataViews.Traits>()) as! MetadataViews.Traits?
177					)
178			}
179			return nil
180		}
181
182		access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
183            return <- TouchstoneSnowyGlobez.createEmptyCollection(nftType: Type<@TouchstoneSnowyGlobez.Collection>())
184        }
185
186		init(_metadataId: UInt64, _serial: UInt64, _recipient: Address) {
187			pre {
188				TouchstoneSnowyGlobez.metadatas[_metadataId] != nil:
189					"This NFT does not exist yet."
190				_serial < TouchstoneSnowyGlobez.getNFTMetadata(_metadataId)!.supply:
191					"This serial does not exist for this metadataId."
192				!TouchstoneSnowyGlobez.getNFTMetadata(_metadataId)!.purchasers.containsKey(_serial):
193					"This serial has already been purchased."
194			}
195			self.id = self.uuid
196			self.metadataId = _metadataId
197			self.serial = _serial
198
199			// Update the buyers list so we keep track of who is purchasing
200			// if let buyersRef: auth(Mutate)  &{UInt64: [UInt64]} = &TouchstoneSnowyGlobez.primaryBuyers[_recipient] {
201			// 	if let metadataIdMap: &[UInt64] = buyersRef[_metadataId]  {
202			// 		metadataIdMap.append(_serial)
203			// 	} else {
204			// 		buyersRef[_metadataId] = [_serial]
205			// 	}
206			// } else {
207			// 	TouchstoneSnowyGlobez.primaryBuyers[_recipient] = {_metadataId: [_serial]}
208			// }
209
210			// Update who bought this serial inside NFTMetadata so it cannot be purchased again.
211			let metadataRef = (&TouchstoneSnowyGlobez.metadatas[_metadataId] as &NFTMetadata?)!
212			metadataRef.purchased(serial: _serial, buyer: _recipient)
213
214			TouchstoneSnowyGlobez.totalSupply = TouchstoneSnowyGlobez.totalSupply + 1
215			emit Minted(id: self.id, recipient: _recipient, metadataId: _metadataId)
216		}
217	}
218
219	access(all) resource Collection: NonFungibleToken.Collection, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, ViewResolver.ResolverCollection {
220	// dictionary of NFT conforming tokens
221		// NFT is a resource type with an 'UInt64' ID field
222		access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
223
224		// withdraw removes an NFT from the collection and moves it to the caller
225		access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {        
226			let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
227
228			emit Withdraw(id: token.id, from: self.owner?.address)
229
230			return <-token
231		}
232
233		// deposit takes a NFT and adds it to the collections dictionary
234		// and adds the ID to the id array
235		access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
236            let token: @TouchstoneSnowyGlobez.NFT <- token as! @TouchstoneSnowyGlobez.NFT
237
238            let id: UInt64 = token.id
239
240            // add the new token to the dictionary which removes the old one
241            let oldToken: @{NonFungibleToken.NFT}? <- self.ownedNFTs[id] <- token
242
243            emit Deposit(id: id, to: self.owner?.address)
244
245            destroy oldToken
246        }
247
248		// getIDs returns an array of the IDs that are in the collection
249		access(all) view fun getIDs(): [UInt64] {
250			return self.ownedNFTs.keys
251		}
252
253		access(all) view fun getLength(): Int {
254            return self.ownedNFTs.length
255        }
256
257        access(all) fun forEachID(_ f: fun (UInt64): Bool): Void {}
258
259        /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
260        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
261            let supportedTypes: {Type: Bool} = {}
262            supportedTypes[Type<@TouchstoneSnowyGlobez.NFT>()] = true
263            return supportedTypes
264        }
265
266        /// Returns whether or not the given type is accepted by the collection
267        /// A collection that can accept any type should just return true by default
268        access(all) view fun isSupportedNFTType(type: Type): Bool {
269            return type == Type<@TouchstoneSnowyGlobez.NFT>()
270        }
271
272		// borrowNFT gets a reference to an NFT in the collection
273		// so that the caller can read its metadata and call its methods
274		access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
275            return (&self.ownedNFTs[id])
276        }
277
278		access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
279          pre {
280            self.ownedNFTs[id] != nil : "NFT not in collection"
281          }
282          let nft: &{NonFungibleToken.NFT} = (&self.ownedNFTs[id])!
283          let tokenRef = nft as! &TouchstoneSnowyGlobez.NFT
284          return tokenRef
285        }
286
287		access(all) fun claim() {
288			if let storage: auth(Mutate) &{UInt64: TouchstoneSnowyGlobez.NFT} = &TouchstoneSnowyGlobez.nftStorage[self.owner!.address] {
289				for id in storage.keys {
290					self.deposit(token: <- storage.remove(key: id)!)
291				}
292			}
293		}
294		
295		access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
296            return <- TouchstoneSnowyGlobez.createEmptyCollection(nftType: Type<@TouchstoneSnowyGlobez.NFT>())
297        }
298
299		init () {
300			self.ownedNFTs <- {}
301		}
302	}
303
304	// A function to mint NFTs. 
305	// You can only call this function if minting
306	// is currently active.
307	access(all) fun mintNFT(metadataId: UInt64, recipient: &{NonFungibleToken.Receiver}, payment: @FlowToken.Vault, serial: UInt64): UInt64 {
308		pre {
309			self.canMint(): "Minting is currently closed by the Administrator!"
310			payment.balance == self.getPriceOfNFT(metadataId): 
311				"Payment does not match the price. You passed in ".concat(payment.balance.toString()).concat(" but this NFT costs ").concat(self.getPriceOfNFT(metadataId)!.toString())
312		}
313		let price: UFix64 = self.getPriceOfNFT(metadataId)!
314
315		// Confirm recipient passes all verifiers
316		// for verifier in self.getMintVerifiers() {
317		// 	let params = {"minter": recipient.owner!.address}
318		// 	if let error = verifier.verify(params) {
319		// 		panic(error)
320		// 	}
321		// }
322
323		// Handle Emerald City DAO royalty (5%)
324		let EmeraldCityTreasury = getAccount(0x5643fd47a29770e7).capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)
325								.borrow()!
326		let emeraldCityCut: UFix64 = 0.05 * price
327
328		// Handle royalty to user that was configured upon creation
329		if let royalty = TouchstoneSnowyGlobez.getOptionalCollectionAttribute(key: "royalty") as! MetadataViews.Royalty? {
330			royalty.receiver.borrow()!.deposit(from: <- payment.withdraw(amount: price * royalty.cut))
331		}
332
333		EmeraldCityTreasury.deposit(from: <- payment.withdraw(amount: emeraldCityCut))
334
335		// Give the rest to the collection owner
336		let paymentRecipient = self.account.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)
337								.borrow()!
338		paymentRecipient.deposit(from: <- payment)
339
340		// Mint the nft 
341		let nft <- create NFT(_metadataId: metadataId, _serial: serial, _recipient: recipient.owner!.address)
342		let nftId: UInt64 = nft.id
343		let metadata = self.getNFTMetadata(metadataId)!
344		self.collectionInfo["profit"] = (self.getCollectionAttribute(key: "profit") as! UFix64) + price
345
346		// Emit event
347		emit TouchstonePurchase(id: nftId, recipient: recipient.owner!.address, metadataId: metadataId, name: metadata.name, description: metadata.description, image: metadata.image, price: price)
348		
349		// Deposit nft
350		recipient.deposit(token: <- nft)
351
352		return nftId
353	}
354
355	access(all) resource Administrator {
356		access(all) fun createNFTMetadata(name: String, description: String, imagePath: String, thumbnailPath: String?, ipfsCID: String, price: UFix64?, extra: {String: AnyStruct}, supply: UInt64) {
357			TouchstoneSnowyGlobez.metadatas[TouchstoneSnowyGlobez.nextMetadataId] = NFTMetadata(
358				_name: name,
359				_description: description,
360				_image: MetadataViews.IPFSFile(
361					cid: ipfsCID,
362					path: imagePath
363				),
364				_thumbnail: thumbnailPath == nil ? nil : MetadataViews.IPFSFile(cid: ipfsCID, path: thumbnailPath),
365				_price: price,
366				_extra: extra,
367				_supply: supply
368			)
369			TouchstoneSnowyGlobez.nextMetadataId = TouchstoneSnowyGlobez.nextMetadataId + 1
370		}
371
372		// mintNFT mints a new NFT and deposits 
373		// it in the recipients collection
374		access(all) fun mintNFT(metadataId: UInt64, serial: UInt64, recipient: Address) {
375			pre {
376				// EmeraldPass.isActive(user: TouchstoneSnowyGlobez.account.address): "You must have an active Emerald Pass subscription to airdrop NFTs. You can purchase Emerald Pass at https://pass.ecdao.org/"
377			}
378			let nft <- create NFT(_metadataId: metadataId, _serial: serial, _recipient: recipient)
379			if let recipientCollection = getAccount(recipient).capabilities.get<&TouchstoneSnowyGlobez.Collection>(TouchstoneSnowyGlobez.CollectionPublicPath).borrow() {
380				recipientCollection.deposit(token: <- nft)
381			} else {
382				if let storage: auth(Mutate) &{UInt64: TouchstoneSnowyGlobez.NFT} = &TouchstoneSnowyGlobez.nftStorage[recipient] {
383					storage[nft.id] <-! nft
384				} else {
385					TouchstoneSnowyGlobez.nftStorage[recipient] <-! {nft.id: <- nft}
386				}
387			}
388		}
389
390		access(all) fun mintBatch(metadataIds: [UInt64], serials: [UInt64], recipients: [Address]) {
391			pre {
392				metadataIds.length == recipients.length: "You need to pass in an equal number of metadataIds and recipients."
393			}
394			var i = 0
395			while i < metadataIds.length {
396				self.mintNFT(metadataId: metadataIds[i], serial: serials[i], recipient: recipients[i])
397				i = i + 1
398			}
399
400			emit MintBatch(metadataIds: metadataIds, recipients: recipients)
401		}
402
403		// create a new Administrator resource
404		access(all) fun createAdmin(): @Administrator {
405			return <- create Administrator()
406		}
407
408		// change piece of collection info
409		access(all) fun changeField(key: String, value: AnyStruct) {
410			TouchstoneSnowyGlobez.collectionInfo[key] = value
411		}
412	}
413
414	// public function that anyone can call to create a new empty collection
415	access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
416		return <- create Collection()
417	}
418
419	// Get information about a NFTMetadata
420	access(all) view fun getNFTMetadata(_ metadataId: UInt64): NFTMetadata? {
421		return self.metadatas[metadataId]
422	}
423
424	access(all) view fun getNFTMetadatas(): {UInt64: NFTMetadata} {
425		return self.metadatas
426	}
427
428	access(all) view fun getPrimaryBuyers(): {Address: {UInt64: [UInt64]}} {
429		return self.primaryBuyers
430	}
431
432	access(all) view fun getCollectionInfo(): {String: AnyStruct} {
433		let collectionInfo = self.collectionInfo
434		collectionInfo["metadatas"] = self.metadatas
435		collectionInfo["primaryBuyers"] = self.primaryBuyers
436		collectionInfo["totalSupply"] = self.totalSupply
437		collectionInfo["nextMetadataId"] = self.nextMetadataId
438		collectionInfo["version"] = 1
439		return collectionInfo
440	}
441
442	access(all) view fun getCollectionAttribute(key: String): AnyStruct {
443		return self.collectionInfo[key] ?? panic(key.concat(" is not an attribute in this collection."))
444	}
445
446	access(all) view fun getOptionalCollectionAttribute(key: String): AnyStruct? {
447		return self.collectionInfo[key]
448	}
449
450	// access(all) view fun getMintVerifiers(): [{MintVerifiers.IVerifier}] {
451	// 	return self.getCollectionAttribute(key: "mintVerifiers") as! [{MintVerifiers.IVerifier}]
452	// }
453
454	access(all) view fun canMint(): Bool {
455		return self.getCollectionAttribute(key: "minting") as! Bool
456	}
457
458	// Returns nil if an NFT with this metadataId doesn't exist
459	access(all) view fun getPriceOfNFT(_ metadataId: UInt64): UFix64? {
460		if let metadata: TouchstoneSnowyGlobez.NFTMetadata = self.getNFTMetadata(metadataId) {
461			let defaultPrice: UFix64 = self.getCollectionAttribute(key: "price") as! UFix64
462			if self.getCollectionAttribute(key: "lotteryBuying") as! Bool {
463				return defaultPrice
464			}
465			return metadata.price ?? defaultPrice
466		}
467		// If the metadataId doesn't exist
468		return nil
469	}
470
471	// Returns an mapping of id to NFTMetadata
472	// for the NFTs a user can claim
473	access(all) view fun getClaimableNFTs(user: Address): {UInt64: NFTMetadata} {
474		let answer: {UInt64: NFTMetadata} = {}
475		if let storage: auth(Mutate) &{UInt64: TouchstoneSnowyGlobez.NFT} = &TouchstoneSnowyGlobez.nftStorage[user] {
476			for id in storage.keys {
477				let nftRef = (storage[id])!
478				answer[id] = self.getNFTMetadata(nftRef.metadataId)
479			}
480		}
481		return answer
482	}
483
484	access(all) view fun getContractViews(resourceType: Type?): [Type] {
485		return [
486			Type<MetadataViews.NFTCollectionData>()
487		]
488	}
489
490	access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
491		return nil
492	}
493
494	init(
495		_name: String, 
496		_description: String, 
497		_imagePath: String, 
498		_bannerImagePath: String?,
499		_minting: Bool, 
500		_royalty: MetadataViews.Royalty?,
501		_defaultPrice: UFix64,
502		_paymentType: String,
503		_ipfsCID: String,
504		_lotteryBuying: Bool,
505		_socials: {String: MetadataViews.ExternalURL}
506		// _mintVerifiers: [{MintVerifiers.IVerifier}]
507	) {
508		// Collection Info
509		self.collectionInfo = {}
510		self.collectionInfo["name"] = _name
511		self.collectionInfo["description"] = _description
512		self.collectionInfo["image"] = MetadataViews.IPFSFile(
513			cid: _ipfsCID,
514			path: _imagePath
515		)
516		if let bannerImagePath = _bannerImagePath {
517			self.collectionInfo["bannerImage"] = MetadataViews.IPFSFile(
518				cid: _ipfsCID,
519				path: _bannerImagePath
520			)
521		}
522		self.collectionInfo["ipfsCID"] = _ipfsCID
523		self.collectionInfo["socials"] = _socials
524		self.collectionInfo["minting"] = _minting
525		self.collectionInfo["lotteryBuying"] = _lotteryBuying
526		if let royalty = _royalty {
527			assert(royalty.receiver.check(), message: "The passed in royalty receiver is not valid. The royalty account must set up the intended payment token.")
528			assert(royalty.cut <= 0.95, message: "The royalty cut cannot be bigger than 95% because 5% goes to Emerald City treasury for primary sales.")
529			self.collectionInfo["royalty"] = royalty
530		}
531		self.collectionInfo["price"] = _defaultPrice
532		self.collectionInfo["paymentType"] = _paymentType
533		self.collectionInfo["dateCreated"] = getCurrentBlock().timestamp
534		// self.collectionInfo["mintVerifiers"] = _mintVerifiers
535		self.collectionInfo["profit"] = 0.0
536
537		self.nextEditionId = 0
538		self.nextMetadataId = 0
539		self.totalSupply = 0
540		self.metadatas = {}
541		self.primaryBuyers = {}
542		self.nftStorage <- {}
543
544		// Set the named paths
545		// We include the user's address in the paths.
546		// This is to prevent clashing with existing 
547		// Collection paths in the ecosystem.
548		self.CollectionStoragePath = /storage/TouchstoneSnowyGlobezCollection_0xc4b1f4387748f389
549		self.CollectionPublicPath = /public/TouchstoneSnowyGlobezCollection_0xc4b1f4387748f389
550		self.CollectionPrivatePath = /private/TouchstoneSnowyGlobezCollection_0xc4b1f4387748f389
551		self.AdministratorStoragePath = /storage/TouchstoneSnowyGlobezAdministrator_0xc4b1f4387748f389
552
553		// Create a Collection resource and save it to storage
554		let collection <- create Collection()
555		self.account.storage.save(<- collection, to: self.CollectionStoragePath)
556
557		// create a public capability for the collection
558		let pubCap = self.account.capabilities.storage.issue<&Collection>(self.CollectionStoragePath)
559		self.account.capabilities.publish(pubCap, at: self.CollectionPublicPath)
560
561		// Create a Administrator resource and save it to storage
562		let administrator <- create Administrator()
563		self.account.storage.save(<- administrator, to: self.AdministratorStoragePath)
564
565		emit ContractInitialized()
566	}
567}
568