Smart Contract

HWGaragePack

A.d0bcefdf1e67ea85.HWGaragePack

Deployed

1w ago
Feb 15, 2026, 04:26:20 PM UTC

Dependents

29 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 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