Smart Contract

HWGarageCardV2

A.d0bcefdf1e67ea85.HWGarageCardV2

Deployed

2w ago
Feb 11, 2026, 06:36:56 PM UTC

Dependents

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