Smart Contract

MotoGPPack

A.a49cc0ee46c54bfb.MotoGPPack

Deployed

1d ago
Feb 26, 2026, 09:43:52 PM UTC

Dependents

0 imports
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3import MotoGPPackMetadata from 0xa49cc0ee46c54bfb 
4
5pub contract MotoGPPack: NonFungibleToken {
6
7    pub fun getVersion(): String {
8        return "1.0.2"
9    }
10
11    // The total number of Packs that have been minted
12    pub var totalSupply: UInt64
13
14    // An dictionary of all the pack types that have been
15    // created using addPackType method defined 
16    // in the MotoGPAdmin contract
17    //
18    // It maps the packType # to the 
19    // information of that pack type
20    access(account) var packTypes: {UInt64: PackType}
21
22    pub event Mint(id: UInt64)
23
24    pub event Burn(id: UInt64)
25
26    // Event that emitted when the MotoGPPack contract is initialized
27    //
28    pub event ContractInitialized()
29
30    // Event that is emitted when a Pack is withdrawn,
31    // indicating the owner of the collection that it was withdrawn from.
32    //
33    // If the collection is not in an account's storage, `from` will be `nil`.
34    //
35    pub event Withdraw(id: UInt64, from: Address?)
36
37    // Event that emitted when a Pack is deposited to a collection.
38    //
39    // It indicates the owner of the collection that it was deposited to.
40    //
41    pub event Deposit(id: UInt64, to: Address?)
42
43    // PackInfo
44    // a struct that represents the info of a Pack.  
45    // It is conveniant to have a struct because we 
46    // can easily read from it without having to move
47    // resources around. Each PackInfo holds a 
48    // packNumber and packType
49    //
50    pub struct PackInfo {
51        // The pack # of this pack type
52        pub var packNumber: UInt64
53
54        // An ID that represents that type of pack this is
55        pub var packType: UInt64
56
57        init(_packNumber: UInt64, _packType: UInt64) {
58            self.packNumber = _packNumber
59            self.packType = _packType
60        }
61    }
62
63    // NFT
64    // This resource defines a Pack with a PackInfo
65    // struct.
66    // After a Pack is opened, the Pack is destroyed and its id
67    // can never be created again. 
68    //
69    // The NFT (Pack) resource is arbitrary in the sense that it doesn't
70    // actually hold Cards inside. However, by looking at a Pack's
71    // packType and mapping that to the # of Cards in a Pack,
72    // we will use that info when opening the Pack.
73    //
74    pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
75        // The Pack's id (completely sequential)
76        pub let id: UInt64
77
78        pub var packInfo: PackInfo
79
80        init(_packNumber: UInt64, _packType: UInt64) {
81            let packTypeStruct: &PackType = (&MotoGPPack.packTypes[_packType] as &PackType?)!
82            // updates the number of packs minted for this packType
83            packTypeStruct.updateNumberOfPacksMinted()
84            
85            // will panic if this packNumber already exists in this packType
86            packTypeStruct.addPackNumber(packNumber: _packNumber)
87
88            self.id = MotoGPPack.totalSupply
89            self.packInfo = PackInfo(_packNumber: _packNumber, _packType: _packType)
90
91            MotoGPPack.totalSupply = MotoGPPack.totalSupply + (1 as UInt64)
92
93            emit Mint(id: self.id)
94        }
95
96        destroy(){
97            emit Burn(id: self.id)
98        }
99
100        ///////////////////////////////
101        // Resolver interface methods
102        /////////////////////////////// 
103
104       pub fun getViews(): [Type] {
105            return [
106                Type<MetadataViews.Display>(),
107                Type<MetadataViews.Royalties>(),
108                Type<MetadataViews.NFTCollectionData>(),
109                Type<MetadataViews.NFTCollectionDisplay>(),
110                Type<MetadataViews.ExternalURL>(),
111                Type<MetadataViews.Medias>(),
112                Type<MetadataViews.Traits>()
113            ]
114        }
115
116         pub fun resolveView(_ view: Type): AnyStruct? {
117             return MotoGPPackMetadata.resolveView(
118                view: view,
119                id: self.id,
120                packID: self.packInfo.packType,
121                serial: self.packInfo.packNumber,
122                // Below four arguments are passed to MotoGPPackMetadata (as opposed being hardcoded there) to avoid cyclic dependencies MotoGPPack <-> MotoGPPackMetadata
123                publicCollectionType: Type<&MotoGPPack.Collection{MotoGPPack.IPackCollectionPublic}>(),
124                publicLinkedType: Type<&MotoGPPack.Collection{MotoGPPack.IPackCollectionPublic, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(),
125                providerLinkedType: Type<&MotoGPPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>(),
126                createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
127                    return <- MotoGPPack.createEmptyCollection()
128                })
129            )
130         }
131    }
132
133    // createPack
134    // allows us to create Packs from another contract
135    // in this account. This is helpful for 
136    // allowing MotoGPAdmin to mint Packs.
137    //
138    access(account) fun createPack(packNumber: UInt64, packType: UInt64): @NFT {
139        return <- create NFT(_packNumber: packNumber, _packType: packType)
140    }
141
142    // PackType
143    // holds all the information for
144    // a specific pack type
145    //
146    pub struct PackType {
147
148        pub let packType: UInt64
149
150        // the number of packs of this pack type
151        // that have been minted
152        pub var numberOfPacksMinted: UInt64
153
154        // the number of cards that will be minted
155        // when a pack of this pack type is opened
156        pub let numberOfCards: UInt64
157
158        // the pack numbers that already exist of this
159        // pack type.
160        // This is primarily used so we don't create duplicate
161        // Packs with the same packNumber and packType
162        pub var assignedPackNumbers: {UInt64: Bool}
163
164        // updateNumberOfPacksMinted
165        // updates the number of Packs that have
166        // been minted for this specific pack type
167        //
168        access(contract) fun updateNumberOfPacksMinted() {
169            self.numberOfPacksMinted = self.numberOfPacksMinted + (1 as UInt64)
170        }
171
172        // addPackNumber
173        // updates the amount of packNumbers that
174        // belong to this PackType so we do not
175        // make duplicates when minting a Pack
176        //
177        access(contract) fun addPackNumber(packNumber: UInt64) {
178            if let assignedPackNumbers = self.assignedPackNumbers[packNumber] {
179                panic("The following pack number already exists: ".concat(packNumber.toString()))
180            } else {
181                self.assignedPackNumbers[packNumber] = true
182            }
183        }
184
185        init(_packType: UInt64, _numberOfCards: UInt64) {
186            self.packType = _packType
187            self.numberOfCards = _numberOfCards
188            self.numberOfPacksMinted = 0
189            self.assignedPackNumbers = {}
190        }
191    }
192
193    // IPackCollectionPublic
194    // This defines an interface to only expose a
195    // Collection of Packs to the public
196    //
197    // Allows users to deposit Packs, read all the Pack IDs,
198    // borrow a NFT reference to access a Pack's ID,
199    // and borrow a Pack reference
200    // to access all of the Pack's fields.
201    //
202    pub resource interface IPackCollectionPublic {
203        pub fun deposit(token: @NonFungibleToken.NFT)
204        pub fun getIDs(): [UInt64]
205        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
206
207        pub fun borrowPack(id: UInt64): &MotoGPPack.NFT? {
208            // If the result isn't nil, the id of the returned reference
209            // should be the same as the argument to the function
210            post {
211                (result == nil) || (result?.id == id): 
212                    "Cannot borrow Pack reference: The ID of the returned reference is incorrect"
213            }
214        }
215    }
216
217    // IPackCollectionAdminAccessible
218    // Exposes the openPack which allows an admin to
219    // open a pack in this collection.
220    //
221    pub resource interface IPackCollectionAdminAccessible {
222        //Keep for now for compatibility purposes.
223    }
224
225    // Collection
226    // a collection of Pack resources so that users can
227    // own Packs in a collection and trade them back and forth.
228    //
229    pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, IPackCollectionPublic, IPackCollectionAdminAccessible, MetadataViews.ResolverCollection  {
230        // A dictionary that maps ids to the pack with that id
231        pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
232
233        // deposit
234        // deposits a Pack into the users Collection
235        //
236        pub fun deposit(token: @NonFungibleToken.NFT) {
237            let token <- token as! @MotoGPPack.NFT
238
239            let id: UInt64 = token.id
240
241            // add the new Pack to the dictionary which removes the old one
242            let oldToken <- self.ownedNFTs[id] <- token
243
244            // Only emit a deposit event if the Collection 
245            // is in an account's storage
246            if self.owner?.address != nil {
247                emit Deposit(id: id, to: self.owner?.address)
248            }
249
250            destroy oldToken
251        }
252
253        // withdraw
254        // withdraws a Pack from the collection
255        //
256        pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
257            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
258
259            emit Withdraw(id: token.id, from: self.owner?.address)
260
261            return <-token
262        }
263
264        // getIDs
265        // returns the ids of all the Packs this
266        // collection has
267        // 
268        pub fun getIDs(): [UInt64] {
269            return self.ownedNFTs.keys
270        }
271
272        // borrowNFT
273        // borrowNFT gets a reference to an NFT in the collection
274        // so that the caller can read its id
275        //
276        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
277            return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
278        }
279
280        // borrowPack
281        // borrowPack returns a borrowed reference to a Pack
282        // so that the caller can read data from it.
283        // They can use this to read its PackInfo and id
284        //
285        pub fun borrowPack(id: UInt64): &MotoGPPack.NFT? {
286            let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
287            return ref as! &MotoGPPack.NFT?
288        }
289
290        // ResolverCollection interface method
291        //
292        pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
293            let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
294            let packNFT = nft as! &MotoGPPack.NFT 
295            return packNFT as &AnyResource{MetadataViews.Resolver}
296        }
297
298        destroy() {
299            destroy self.ownedNFTs
300        }
301
302        init() {   
303            self.ownedNFTs <- {}
304        }
305    }
306
307    // createEmptyCollection
308    // creates an empty Collection so that users
309    // can be able to receive and deal with Pack resources.
310    //
311    pub fun createEmptyCollection(): @Collection {
312        return <- create Collection()
313    }
314
315    // getPackTypeInfo
316    // returns a PackType struct, which represents the info
317    // of a specific PackType that is passed in
318    //
319    pub fun getPackTypeInfo(packType: UInt64): PackType {
320        return self.packTypes[packType] ?? panic("This pack type does not exist")
321    }
322
323    // addPackType
324    // allows us to add new pack types from another contract
325    // in this account. This is helpful for 
326    // allowing MotoGPAdmin to add new pack types.
327    //
328    access(account) fun addPackType(packType: UInt64, numberOfCards: UInt64) {
329        pre {
330            self.packTypes[packType] == nil:
331                "This pack type already exists!"
332        }
333        // Adds this pack type
334        self.packTypes[packType] = self.PackType(_packType: packType, _numberOfCards: numberOfCards)
335    }
336
337    init() {
338        self.totalSupply = 0
339        self.packTypes = {}
340
341        emit ContractInitialized()
342    }
343}