Smart Contract

HWGaragePackV2

A.d0bcefdf1e67ea85.HWGaragePackV2

Deployed

2w ago
Feb 11, 2026, 06:46:53 PM UTC

Dependents

36 imports
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