Smart Contract
TMNFT
A.a8d1a60acba12a20.TMNFT
1// Description: Smart Contract for Ticketmaster Digital Collectibles
2// SPDX-License-Identifier: UNLICENSED
3
4import NonFungibleToken from 0x1d7e57aa55817448
5import MetadataViews from 0x1d7e57aa55817448
6import ViewResolver from 0x1d7e57aa55817448
7
8access(all) contract TMNFT : NonFungibleToken {
9
10 access(all) var totalSupply: UInt64
11
12 access(all) event ContractInitialized()
13 access(all) event Withdraw(id: UInt64, from: Address?)
14 access(all) event Deposit(id: UInt64, to: Address?)
15
16 access(all) let CollectionStoragePath: StoragePath
17 access(all) let CollectionPublicPath: PublicPath
18 access(all) let MinterStoragePath: StoragePath
19
20 // Correct type from NonFungibleToken.INFT to NonFungibleToken.NFT
21 access(all) resource NFT : NonFungibleToken.NFT {
22 access(all) let id: UInt64
23 access(all) var link: String
24 access(all) var batch: UInt32
25 access(all) var sequence: UInt16
26 access(all) var limit: UInt16
27
28 init(
29 initID: UInt64,
30 initlink: String,
31 initbatch: UInt32,
32 initsequence: UInt16,
33 initlimit: UInt16
34 ) {
35 self.id = initID
36 self.link = initlink
37 self.batch = initbatch
38 self.sequence = initsequence
39 self.limit = initlimit
40 }
41
42 /// createEmptyCollection creates an empty Collection
43 /// and returns it to the caller so that they can own NFTs
44 /// @{NonFungibleToken.Collection}
45 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
46 return <-TMNFT.createEmptyCollection(nftType: Type<@TMNFT.NFT>())
47 }
48
49 access(all) view fun getViews(): [Type] {
50 return [
51 Type<MetadataViews.NFTCollectionData>()
52 ]
53 }
54
55 access(all) fun resolveView(_ view: Type): AnyStruct? {
56 switch view {
57 case Type<MetadataViews.NFTCollectionData>():
58 return TMNFT.resolveContractView(resourceType: Type<@TMNFT.NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
59 }
60 return nil
61 }
62 }
63
64 // Ensure all type specifications conform to interface requirements
65 access(all) resource interface TMNFTCollectionPublic {
66 // Deprecated, only here for backwards compatibility
67 }
68
69 access(all) resource Collection : NonFungibleToken.Collection, TMNFTCollectionPublic {
70 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
71
72 init() {
73 self.ownedNFTs <- {}
74 }
75
76 /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
77 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
78 let supportedTypes: {Type: Bool} = {}
79 supportedTypes[Type<@TMNFT.NFT>()] = true
80 return supportedTypes
81 }
82
83 /// Returns whether or not the given type is accepted by the collection
84 /// A collection that can accept any type should just return true by default
85 access(all) view fun isSupportedNFTType(type: Type): Bool {
86 return type == Type<@TMNFT.NFT>()
87 }
88
89 /// withdraw removes an NFT from the collection and moves it to the caller
90 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
91 let token <- self.ownedNFTs.remove(key: withdrawID)
92 ?? panic("Could not withdraw an NFT with the provided ID from the collection")
93
94 return <-token
95 }
96
97 /// deposit takes a NFT and adds it to the collections dictionary
98 /// and adds the ID to the id array
99 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
100 let token <- token as! @TMNFT.NFT
101 let id = token.id
102
103 // add the new token to the dictionary which removes the old one
104 let oldToken <- self.ownedNFTs[token.id] <- token
105
106 destroy oldToken
107
108 // This code is for testing purposes only
109 // Do not add to your contract unless you have a specific
110 // reason to want to emit the NFTUpdated event somewhere
111 // in your contract
112 }
113
114 /// getIDs returns an array of the IDs that are in the collection
115 access(all) view fun getIDs(): [UInt64] {
116 return self.ownedNFTs.keys
117 }
118
119 /// Gets the amount of NFTs stored in the collection
120 access(all) view fun getLength(): Int {
121 return self.ownedNFTs.length
122 }
123
124 /// Borrow the view resolver for the specified NFT ID
125 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
126 if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
127 return nft as &{ViewResolver.Resolver}
128 }
129 return nil
130 }
131
132 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
133 return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
134 }
135
136 /// createEmptyCollection creates an empty Collection of the same type
137 /// and returns it to the caller
138 /// @return A an empty collection of the same type
139 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
140 return <- TMNFT.createEmptyCollection(nftType: Type<@TMNFT.NFT>())
141 }
142
143 }
144
145 /// createEmptyCollection creates an empty Collection for the specified NFT type
146 /// and returns it to the caller so that they can own NFTs
147 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
148 return <- create Collection()
149 }
150
151 /// Function that returns all the Metadata Views implemented by a Non Fungible Token
152 ///
153 /// @return An array of Types defining the implemented views. This value will be used by
154 /// developers to know which parameter to pass to the resolveView() method.
155 ///
156 access(all) view fun getContractViews(resourceType: Type?): [Type] {
157 return [
158 Type<MetadataViews.NFTCollectionData>(),
159 Type<MetadataViews.NFTCollectionDisplay>(),
160 Type<MetadataViews.EVMBridgedMetadata>()
161 ]
162 }
163
164 /// Function that resolves a metadata view for this contract.
165 ///
166 /// @param view: The Type of the desired view.
167 /// @return A structure representing the requested view.
168 ///
169 access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
170 switch viewType {
171 case Type<MetadataViews.NFTCollectionData>():
172 let collectionData = MetadataViews.NFTCollectionData(
173 storagePath: self.CollectionStoragePath,
174 publicPath: self.CollectionPublicPath,
175 publicCollection: Type<&TMNFT.Collection>(),
176 publicLinkedType: Type<&TMNFT.Collection>(),
177 createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
178 return <-TMNFT.createEmptyCollection(nftType: Type<@TMNFT.NFT>())
179 })
180 )
181 return collectionData
182 case Type<MetadataViews.NFTCollectionDisplay>():
183 let media = MetadataViews.Media(
184 file: MetadataViews.HTTPFile(
185 url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg"
186 ),
187 mediaType: "image/svg+xml"
188 )
189 return MetadataViews.NFTCollectionDisplay(
190 name: "Ticketmaster Collection",
191 description: "This collection represents Ticketmaster Digital Collectibles.",
192 externalURL: MetadataViews.ExternalURL("https://ticketmaster-nft.onflow.org"),
193 squareImage: media,
194 bannerImage: media,
195 socials: {
196 "twitter": MetadataViews.ExternalURL("https://twitter.com/ticketmaster")
197 }
198 )
199 case Type<MetadataViews.EVMBridgedMetadata>():
200 // Implementing this view gives the project control over how the bridged NFT is represented as an ERC721
201 // when bridged to EVM on Flow via the public infrastructure bridge.
202
203 // Compose the contract-level URI. In this case, the contract metadata is located on some HTTP host,
204 // but it could be IPFS, S3, a data URL containing the JSON directly, etc.
205 return MetadataViews.EVMBridgedMetadata(
206 name: "TMNFT",
207 symbol: "TMNFT",
208 uri: MetadataViews.URI(
209 baseURI: nil, // setting baseURI as nil sets the given value as the uri field value
210 value: "https://ticketmaster-nft.onflow.org/contract-metadata.json"
211 )
212 )
213 }
214 return nil
215
216
217 }
218
219 /// Resource that an admin or something similar would own to be
220 /// able to mint new NFTs
221 ///
222 access(all) resource NFTMinter {
223
224 /// mintNFT mints a new NFT with a new ID
225 /// and returns it to the calling context
226 access(all) fun mintNFT(
227 glink: String,
228 gbatch: UInt32,
229 glimit: UInt16,
230 gsequence: UInt16
231 ): @TMNFT.NFT {
232
233 let tokenID = (UInt64(gbatch) << 32) | (UInt64(glimit) << 16) | UInt64(gsequence)
234
235 let metadata: {String: AnyStruct} = {}
236 let currentBlock = getCurrentBlock()
237 metadata["mintedBlock"] = currentBlock.height
238 metadata["mintedTime"] = currentBlock.timestamp
239
240 // this piece of metadata will be used to show embedding rarity into a trait
241 metadata["foo"] = "bar"
242
243 // create a new NFT
244 var newNFT <- create NFT(
245 initID: tokenID,
246 initlink: glink,
247 initbatch: gbatch,
248 initsequence: gsequence,
249 initlimit: glimit
250 )
251 TMNFT.totalSupply = TMNFT.totalSupply + 1
252 return <-newNFT
253 }
254 }
255
256 init() {
257 self.CollectionStoragePath = /storage/TMNFTCollection
258 self.CollectionPublicPath = /public/TMNFTCollection
259 self.MinterStoragePath = /storage/TMNFTMinter
260 self.totalSupply = 0
261
262 let collection <- create Collection()
263 self.account.storage.save(<-collection, to: self.CollectionStoragePath)
264
265 let collectionCap = self.account.capabilities.storage.issue<&TMNFT.Collection>(self.CollectionStoragePath)
266 self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
267
268 let minter <- create NFTMinter()
269 self.account.storage.save(<-minter, to: self.MinterStoragePath)
270 }
271}