Smart Contract
HWGaragePack
A.d0bcefdf1e67ea85.HWGaragePack
1/*
2*
3* This is an implemetation of a Flow Non-Fungible Token
4* It is not a part of the official standard but it is assumed to be
5* similar to how NFTs would implement the core functionality
6*
7*
8*/
9
10import NonFungibleToken from 0x1d7e57aa55817448
11import ViewResolver from 0x1d7e57aa55817448
12import MetadataViews from 0x1d7e57aa55817448
13import FungibleToken from 0xf233dcee88fe0abe
14
15access(all) contract HWGaragePack: NonFungibleToken {
16
17 /*
18 * NonFungibleToken Standard Events
19 */
20
21 access(all) event ContractInitialized()
22 access(all) event Withdraw(id: UInt64, from: Address?)
23 access(all) event Deposit(id: UInt64, to: Address?)
24
25 /*
26 * Project Events
27 */
28
29 access(all) event Mint(id: UInt64)
30 access(all) event Burn(id: UInt64)
31 access(all) event DepositEvent(
32 uuid: UInt64,
33 id: UInt64,
34 seriesId: UInt64,
35 editionId: UInt64,
36 to: Address?
37 )
38 access(all) event TransferEvent(
39 uuid: UInt64,
40 id: UInt64,
41 seriesId: UInt64,
42 editionId: UInt64,
43 to: Address?
44 )
45
46 /*
47 * Named Paths
48 */
49
50 access(all) let CollectionStoragePath: StoragePath
51 access(all) let CollectionPublicPath: PublicPath
52
53 /*
54 * NonFungibleToken Standard Fields
55 */
56
57 access(all) var totalSupply: UInt64
58
59 /*
60 * Pack State Variables
61 */
62
63 access(all) var name: String
64
65 access(self) var collectionMetadata: {String: String}
66 access(self) let idToPackMetadata: {UInt64: PackMetadata}
67
68 access(all) struct PackMetadata {
69 access(all) let metadata: {String: String}
70
71 init(metadata: {String: String}) {
72 self.metadata = metadata
73 }
74 }
75
76 access(all) resource NFT: NonFungibleToken.NFT {
77 access(all) let id: UInt64
78 access(all) let packID: UInt64
79 access(all) let packEditionID: UInt64
80 access(all) view fun getMetadata(): {String: String} {
81 if (HWGaragePack.idToPackMetadata[self.id] != nil) {
82 return HWGaragePack.idToPackMetadata[self.id]!.metadata
83 } else {
84 return {}
85 }
86 }
87
88 init(id: UInt64, packID: UInt64, packEditionID: UInt64) {
89 self.id = id
90 self.packID = packID
91 self.packEditionID = packEditionID
92 emit Mint(id: self.id)
93 }
94
95 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
96 return <-HWGaragePack.createEmptyCollection(nftType: Type<@HWGaragePack.NFT>())
97 }
98
99 access(all) view fun getViews(): [Type] {
100 return [
101 Type<MetadataViews.Display>(),
102 Type<MetadataViews.ExternalURL>(),
103 Type<MetadataViews.NFTCollectionData>(),
104 Type<MetadataViews.NFTCollectionDisplay>(),
105 Type<MetadataViews.Royalties>()
106 ]
107 }
108
109 access(all) view fun resolveView(_ view: Type): AnyStruct? {
110 switch view {
111 case Type<MetadataViews.Display>():
112 var ipfsImage: MetadataViews.IPFSFile = MetadataViews.IPFSFile(cid: "No thumbnail cid set", path: "No thumbnail path set")
113 if (self.getMetadata().containsKey("thumbnailCID")) {
114 ipfsImage = MetadataViews.IPFSFile(cid: self.getMetadata()["thumbnailCID"]!, path: self.getMetadata()["thumbnailPath"])
115 }
116 return MetadataViews.Display(
117 name: self.getMetadata()["name"] ?? "Hot Wheels Garage Series 4 Pack #".concat(self.packEditionID.toString()),
118 description: self.getMetadata()["description"] ?? "Digital Pack Collectable from Hot Wheels Garage",
119 thumbnail: ipfsImage
120 )
121
122 case Type<MetadataViews.ExternalURL>():
123 return MetadataViews.ExternalURL("")
124
125 case Type<MetadataViews.NFTCollectionData>():
126 return HWGaragePack.resolveContractView(resourceType: Type<@HWGaragePack.NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
127
128 case Type<MetadataViews.NFTCollectionDisplay>():
129 return HWGaragePack.resolveContractView(resourceType: Type<@HWGaragePack.NFT>(), viewType: Type<MetadataViews.NFTCollectionDisplay>())
130
131 case Type<MetadataViews.Royalties>():
132 return HWGaragePack.resolveContractView(resourceType: Type<@HWGaragePack.NFT>(), viewType: Type<MetadataViews.Royalties>())
133 }
134
135 return nil
136 }
137}
138
139 access(all) resource interface PackCollectionPublic {}
140
141 access(all) resource Collection: PackCollectionPublic, NonFungibleToken.Collection {
142
143 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
144
145 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
146 let HWGaragePack: @HWGaragePack.NFT <- token as! @HWGaragePack.NFT
147 let HWGaragePackUUID: UInt64 = HWGaragePack.uuid
148 let HWGaragePackSeriesID: UInt64 = 4
149 let HWGaragePackID: UInt64 = HWGaragePack.id
150 let HWGaragePackpackEditionID: UInt64 = HWGaragePack.packEditionID
151
152 self.ownedNFTs[HWGaragePackID] <-! HWGaragePack
153 emit Deposit(id: HWGaragePackID, to: self.owner?.address)
154 emit DepositEvent(
155 uuid: HWGaragePackUUID,
156 id: HWGaragePackID,
157 seriesId: HWGaragePackSeriesID,
158 editionId: HWGaragePackpackEditionID,
159 to: self.owner?.address
160 )
161 }
162
163 access(all) view fun getLength(): Int {
164 return self.ownedNFTs.length
165 }
166
167 init() {
168 self.ownedNFTs <- {}
169 }
170
171 /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
172 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
173 let supportedTypes: {Type: Bool} = {}
174 supportedTypes[Type<@HWGaragePack.NFT>()] = true
175 return supportedTypes
176 }
177
178 /// Returns whether or not the given type is accepted by the collection
179 /// A collection that can accept any type should just return true by default
180 access(all) view fun isSupportedNFTType(type: Type): Bool {
181 return type == Type<@HWGaragePack.NFT>()
182 }
183
184 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
185 let token: @{NonFungibleToken.NFT} <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
186 emit Withdraw(id: token.id, from: self.owner?.address)
187 return <- token
188 }
189
190 // access(all) fun destroyNFT(id: UInt64) {
191 // let nft <- self.ownedNFTs.remove(key: id) ?? panic("NFT not found in account")
192 // emit Burn(id: nft.id)
193 // destroy nft
194 // }
195
196 access(all) view fun getIDs(): [UInt64] {
197 return self.ownedNFTs.keys
198 }
199
200 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
201 return (&self.ownedNFTs[id])
202 }
203
204 access(all) view fun borrowPack(id: UInt64): &NFT? {
205 if let pack: &{NonFungibleToken.NFT} = &self.ownedNFTs[id] {
206 return pack as! &NFT
207 }
208 return nil
209 }
210
211 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
212 if let nftRef: &{NonFungibleToken.NFT} = &self.ownedNFTs[id] {
213 return nftRef as &{ViewResolver.Resolver}
214 }
215 return nil
216 }
217
218
219 /// Allows a given function to iterate through the list
220 /// of owned NFT IDs in a collection without first
221 /// having to load the entire list into memory
222 access(all) fun forEachID(_ f: fun(UInt64): Bool) {
223 self.ownedNFTs.forEachKey(f)
224 }
225
226 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
227 return <- HWGaragePack.createEmptyCollection(nftType: Type<@HWGaragePack.NFT>())
228 }
229 }
230
231
232 /*
233 * Public Functions
234 */
235
236 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
237 return <- create Collection()
238 }
239
240 access(all) view fun getTotalSupply(): UInt64 {
241 return self.totalSupply
242 }
243
244 access(all) view fun getName(): String {
245 return self.name
246 }
247
248 access(all) fun transfer(uuid: UInt64, id: UInt64, packSeriesId: UInt64, packEditionId: UInt64, toAddress: Address) {
249
250 let HWGaragePackV2UUID: UInt64 = uuid
251 let HWGaragePackV2SeriesId: UInt64 = packSeriesId
252 let HWGaragePackV2ID: UInt64 = id
253 let HWGaragePackV2packEditionID: UInt64 = packEditionId
254
255 emit TransferEvent(
256 uuid: HWGaragePackV2UUID,
257 id: HWGaragePackV2ID,
258 seriesId: HWGaragePackV2SeriesId,
259 editionId: HWGaragePackV2packEditionID,
260 to: toAddress
261 )
262 }
263
264 access(all) view fun getCollectionMetadata(): {String: String} {
265 return self.collectionMetadata
266 }
267
268 access(all) view fun getEditionMetadata(_ edition: UInt64): {String: String} {
269 if (self.idToPackMetadata[edition] != nil) {
270 return self.idToPackMetadata[edition]!.metadata
271 } else {
272 return {}
273 }
274 }
275
276 access(all) view fun getMetadataLength(): Int {
277 return self.idToPackMetadata.length
278 }
279
280 access(all) view fun getPackMetadata(): AnyStruct {
281 return self.idToPackMetadata
282 }
283
284 access(all) view fun getContractViews(resourceType: Type?): [Type] {
285 return [
286 Type<MetadataViews.NFTCollectionData>(),
287 Type<MetadataViews.NFTCollectionDisplay>(),
288 Type<MetadataViews.Royalties>()
289 ]
290 }
291
292 access(all) view fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
293 switch viewType {
294 case Type<MetadataViews.NFTCollectionData>():
295 return MetadataViews.NFTCollectionData(
296 storagePath: HWGaragePack.CollectionStoragePath,
297 publicPath: HWGaragePack.CollectionPublicPath,
298 publicCollection: Type<&HWGaragePack.Collection>(),
299 publicLinkedType: Type<&HWGaragePack.Collection>(),
300 createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
301 return <-HWGaragePack.createEmptyCollection(nftType: Type<@HWGaragePack.NFT>())
302 })
303 )
304
305 case Type<MetadataViews.NFTCollectionDisplay>():
306 let externalURL = MetadataViews.ExternalURL("")
307 let squareImage = MetadataViews.Media(
308 file: MetadataViews.HTTPFile(url: ""),
309 mediaType: "image/png"
310 )
311 let bannerImage = MetadataViews.Media(
312 file: MetadataViews.HTTPFile(url: ""),
313 mediaType: "image/png"
314 )
315 let socialMap: {String: MetadataViews.ExternalURL} = {
316 "facebook": MetadataViews.ExternalURL("https://www.facebook.com/hotwheels"),
317 "instagram": MetadataViews.ExternalURL("https://www.instagram.com/hotwheelsofficial/"),
318 "twitter": MetadataViews.ExternalURL("https://twitter.com/Hot_Wheels"),
319 "discord": MetadataViews.ExternalURL("https://discord.gg/mattel")
320 }
321 return MetadataViews.NFTCollectionDisplay(
322 name: "Hot Wheels Garage Pack",
323 description: "Digital Collectable from Hot Wheels Garage",
324 externalURL: externalURL,
325 squareImage: squareImage,
326 bannerImage: bannerImage,
327 socials: socialMap
328 )
329
330 case Type<MetadataViews.Royalties>():
331 let flowReceiver = getAccount(0xf86e2f015cd692be).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
332 return MetadataViews.Royalties([
333 MetadataViews.Royalty(
334 receiver: flowReceiver,
335 cut: 0.05,
336 description: "Mattel 5% Royalty"
337 )
338 ])
339 }
340 return nil
341 }
342 /*
343 * Admin Functions
344 */
345 access(account) fun setEditionMetadata(editionNumber: UInt64, metadata: {String: String}) {
346 self.idToPackMetadata[editionNumber] = PackMetadata(metadata: metadata)
347 }
348
349 access(account) fun setCollectionMetadata(metadata: {String: String}) {
350 self.collectionMetadata = metadata
351 }
352
353 access(account) fun mint(nftID: UInt64, packID: UInt64, packEditionID: UInt64): @NFT {
354 self.totalSupply = self.totalSupply + 1
355 return <- create NFT(id: nftID, packID: packID, packEditionID: packEditionID)
356 }
357
358 // initialize contract state variables
359 init() {
360 self.name = "HWGaragePack"
361 self.totalSupply = 0
362
363 self.collectionMetadata = {}
364 self.idToPackMetadata = {}
365
366 // set the named paths
367 self.CollectionStoragePath = /storage/HWGaragePackCollection
368 self.CollectionPublicPath = /public/HWGaragePackCollection
369
370 // Create a collection resource and save it to storage
371 let collection: @HWGaragePack.Collection <- create Collection()
372 self.account.storage.save(<-collection, to: self.CollectionStoragePath)
373
374 let collectionCap = self.account.capabilities.storage.issue<&HWGaragePack.Collection>(self.CollectionStoragePath)
375 self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
376
377 emit ContractInitialized()
378 }
379
380}
381