Smart Contract

HWGarageTokenV2

A.d0bcefdf1e67ea85.HWGarageTokenV2

Deployed

1w ago
Feb 15, 2026, 03:29:16 PM UTC

Dependents

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