Smart Contract

MotoGPCard

A.a49cc0ee46c54bfb.MotoGPCard

Deployed

2d ago
Feb 26, 2026, 03:02:33 PM UTC

Dependents

0 imports
1import NonFungibleToken from 0x1d7e57aa55817448
2import MotoGPAdmin from 0xa49cc0ee46c54bfb
3import MotoGPCounter from 0xa49cc0ee46c54bfb
4import MetadataViews from 0x1d7e57aa55817448
5import MotoGPCardMetadata from 0xa49cc0ee46c54bfb 
6
7pub contract MotoGPCard: NonFungibleToken {
8
9    pub fun getVersion(): String {
10        return "1.0.3"
11    }
12
13    // The total number of Cards in existence
14    pub var totalSupply: UInt64
15
16    // Event that emitted when the MotoGPCard contract is initialized
17    //
18    pub event ContractInitialized()
19
20    // Event that is emitted when a Card is withdrawn,
21    // indicating the owner of the collection that it was withdrawn from.
22    //
23    // If the collection is not in an account's storage, `from` will be `nil`.
24    //
25    pub event Withdraw(id: UInt64, from: Address?)
26
27    // Event that emitted when a Card is deposited to a collection.
28    //
29    // It indicates the owner of the collection that it was deposited to.
30    //
31    pub event Deposit(id: UInt64, to: Address?)
32
33
34    pub event Mint(id: UInt64)
35
36    pub event Burn(id: UInt64)
37
38    // An array UInt128s that represents cardID + serial keys
39    // This is primarily used to ensure there
40    // are no duplicates when we mint a new Card (NFT)
41   access(account) var allCards: [UInt128]
42
43    // NFT
44    // The NFT resource defines a specific Card
45    // that has an id, cardID, and serial.
46    // This resource will be created every time
47    // a pack opens and when we need to mint Cards.
48    //
49    // This NFT represents a Card. These names
50    // will be used interchangeably.
51    //
52    pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
53        // The card's Issue ID (completely sequential)
54        pub let id: UInt64
55
56        // The card's cardID, which will be determined
57        // once the pack is opened
58        pub let cardID: UInt64
59
60        // The card's Serial, which will also be determined
61        // once the pack is opened
62        pub let serial: UInt64
63
64        // initializer
65        //
66        init(_cardID: UInt64, _serial: UInt64) {
67            let keyValue = UInt128(_cardID) + (UInt128(_serial) * (0x4000000000000000 as UInt128))
68            if (MotoGPCard.allCards.contains(keyValue)) {
69                panic("This cardID and serial combination already exists")
70            }
71            MotoGPCard.allCards.append(keyValue)
72
73            self.cardID = _cardID
74            self.serial = _serial
75
76            self.id = MotoGPCounter.increment("MotoGPCard")
77
78            MotoGPCard.totalSupply = MotoGPCard.totalSupply + (1 as UInt64)
79
80            emit Mint(id: self.id)
81        }
82
83        // NOTE: The method getCardMetadata(): MotoGPCardMetadata.Metadata? has been removed. 
84        // Use methods getViews and resolveView instead to fetch metadata
85
86        destroy(){
87            MotoGPCard.totalSupply = MotoGPCard.totalSupply - (1 as UInt64)
88            emit Burn(id: self.id)
89        }
90
91        ///////////////////////////////
92        // Resolver interface methods
93        /////////////////////////////// 
94
95        pub fun getViews(): [Type] {
96            return [
97                Type<MetadataViews.Display>(),
98                Type<MetadataViews.Royalties>(),
99                Type<MetadataViews.NFTCollectionData>(),
100                Type<MetadataViews.NFTCollectionDisplay>(),
101                Type<MetadataViews.ExternalURL>(),
102                Type<MetadataViews.Medias>(),
103                Type<MetadataViews.Traits>(),
104                Type<MotoGPCardMetadata.Riders>() // custom type
105            ]
106        }
107
108        pub fun resolveView(_ view: Type): AnyStruct? {
109            return MotoGPCardMetadata.resolveView(
110                view: view,
111                id: self.id,
112                cardID: self.cardID,
113                serial: self.serial,
114                // Below four arguments are passed to MotoGPCardMetadata (as opposed being hardcoded there) to avoid cyclic dependencies MotoGPCard <-> MotoGPCardMetadata
115                publicCollectionType: Type<&MotoGPCard.Collection{MotoGPCard.ICardCollectionPublic}>(),
116                publicLinkedType: Type<&MotoGPCard.Collection{MotoGPCard.ICardCollectionPublic, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(),
117                providerLinkedType: Type<&MotoGPCard.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>(),
118                createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
119                    return <- MotoGPCard.createEmptyCollection()
120                })
121            )
122        }
123    }
124
125    // createNFT
126    // allows us to create an NFT from another contract in this
127    // account because we want to be able to mint NFTs
128    // in MotoGPPack
129    //
130    access(account) fun createNFT(cardID: UInt64, serial: UInt64): @NFT {
131        return <- create NFT(_cardID: cardID, _serial: serial)
132    }
133
134    // ICardCollectionPublic
135    // Defines an interface that specifies
136    // what fields and functions 
137    // we want to expose to the public.
138    //
139    // Allows users to deposit Cards, read all the Card IDs,
140    // borrow a NFT reference to access a Card's ID,
141    // deposit a batch of Cards, and borrow a Card reference
142    // to access all of the Card's fields.
143    //
144    pub resource interface ICardCollectionPublic {
145        pub fun deposit(token: @NonFungibleToken.NFT)
146        pub fun getIDs(): [UInt64]
147        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
148
149        pub fun depositBatch(cardCollection: @NonFungibleToken.Collection)
150        pub fun borrowCard(id: UInt64): &MotoGPCard.NFT? {
151            // If the result isn't nil, the id of the returned reference
152            // should be the same as the argument to the function
153            post {
154                (result == nil) || (result?.id == id): 
155                    "Cannot borrow Card reference: The ID of the returned reference is incorrect"
156            }
157        }
158    }
159
160    // Collection
161    // This resource defines a collection of Cards
162    // that a user will have. We must give each user
163    // this collection so they can
164    // interact with Cards.
165    //
166    pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, ICardCollectionPublic, MetadataViews.ResolverCollection {
167        // A dictionary that maps a Card's id to a 
168        // Card in the collection. It holds all the 
169        // Cards in a collection.
170        pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
171
172        // deposit
173        // deposits a Card into the Collection
174        //
175        pub fun deposit(token: @NonFungibleToken.NFT) {
176            let token <- token as! @MotoGPCard.NFT
177
178            let id: UInt64 = token.id
179
180            // add the new Card to the dictionary which removes the old one
181            let oldToken <- self.ownedNFTs[id] <- token
182
183            // Only emit a deposit event if the Collection 
184            // is in an account's storage
185            if self.owner?.address != nil {
186                emit Deposit(id: id, to: self.owner?.address)
187            }
188
189            destroy oldToken
190        }
191
192        // depositBatch
193        // This method deposits a collection of Cards into the
194        // user's Collection.
195        //
196        // This is primarily called by an Admin to
197        // deposit newly minted Cards into this Collection.
198        //
199        pub fun depositBatch(cardCollection: @NonFungibleToken.Collection) {
200            pre {
201                cardCollection.getIDs().length <= 100:
202                    "Too many cards being deposited. Must be less than or equal to 100"
203            }
204
205            // Get an array of the IDs to be deposited
206            let keys = cardCollection.getIDs()
207
208            // Iterate through the keys in the collection and deposit each one
209            for key in keys {
210                self.deposit(token: <-cardCollection.withdraw(withdrawID: key))
211            }
212
213            // Destroy the empty Collection
214            destroy cardCollection
215        }
216
217        // withdraw
218        // withdraw removes a Card from the collection and moves it to the caller
219        //
220        pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
221            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
222
223            emit Withdraw(id: token.id, from: self.owner?.address)
224
225            return <-token
226        }
227
228        // getIDs
229        // returns the ids of all the Card this
230        // collection has
231        // 
232        pub fun getIDs(): [UInt64] {
233            return self.ownedNFTs.keys
234        }
235
236        // borrowNFT
237        // borrowNFT gets a reference to an NFT in the collection
238        // so that the caller can read its id field
239        //
240        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
241            return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
242        }
243
244        // borrowCard
245        // borrowCard returns a borrowed reference to a Card
246        // so that the caller can read data from it.
247        // They can use this to read its id, cardID, and serial
248        //
249        pub fun borrowCard(id: UInt64): &MotoGPCard.NFT? {
250            let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
251            return ref as! &MotoGPCard.NFT?
252        }
253
254        // ResolverCollection interface method
255        //
256        pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
257            let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
258            let cardNFT = nft as! &MotoGPCard.NFT
259            return cardNFT as &AnyResource{MetadataViews.Resolver}
260        }
261
262        destroy() {
263            destroy self.ownedNFTs
264        }
265
266        init () {
267            self.ownedNFTs <- {}
268        }
269    }
270
271    // createEmptyCollection
272    // creates a new Collection resource and returns it.
273    // This will primarily be used to give a user a new Collection
274    // so they can store Cards
275    //
276    pub fun createEmptyCollection(): @Collection {
277        return <- create Collection()
278    }
279
280    init() {
281        self.totalSupply = 0
282        self.allCards = []
283
284        emit ContractInitialized()
285    }
286
287}