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