Smart Contract

ArenaBoyz

A.3a3a4f7d9eec9073.ArenaBoyz

Deployed

1h ago
Mar 01, 2026, 02:20:33 PM UTC

Dependents

0 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3import MetadataViews from 0x1d7e57aa55817448
4
5pub contract ArenaBoyz: NonFungibleToken {
6
7    pub var totalSupply: UInt64
8    pub var customSupply: UInt64
9    pub var genesisSupply: UInt64
10    pub var commonSupply: UInt64
11
12    pub var totalBurned: UInt64
13    pub var customBurned: UInt64
14    pub var genesisBurned: UInt64
15    pub var commonBurned: UInt64
16
17    pub var metadataUrl: String
18
19    pub event ContractInitialized()
20    pub event Withdraw(id: UInt64, from: Address?)
21    pub event Deposit(id: UInt64, to: Address?)
22    pub event Mint(id: UInt64, type: UInt8)
23    pub event Burn(id: UInt64, type: UInt8)
24    pub event MinterCreated()
25
26    pub let CollectionStoragePath: StoragePath
27    pub let CollectionPublicPath: PublicPath
28    pub let AdminStoragePath: StoragePath
29    pub let MinterStoragePath: StoragePath
30
31    pub enum NFTType: UInt8 {
32        pub case custom
33        pub case genesis
34        pub case common
35    }
36
37    pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
38
39        pub let id: UInt64
40        pub let type: NFTType
41
42        init(
43            id: UInt64,
44            type: NFTType,
45        ) {
46            self.id = id
47            self.type = type
48        }
49
50        destroy () {
51            ArenaBoyz.totalBurned = ArenaBoyz.totalBurned + UInt64(1)
52            switch self.type {
53                case NFTType.custom:
54                    ArenaBoyz.customBurned = ArenaBoyz.customBurned + UInt64(1)
55                    emit Burn(id: self.id, type: UInt8(0))
56                case NFTType.genesis:
57                    ArenaBoyz.genesisBurned = ArenaBoyz.genesisBurned + UInt64(1)
58                    emit Burn(id: self.id, type: UInt8(1))
59                
60                case NFTType.common:
61                    ArenaBoyz.commonBurned = ArenaBoyz.commonBurned + UInt64(1)
62                    emit Burn(id: self.id, type: UInt8(2))
63                
64            }
65            
66        }
67
68        pub fun getViews(): [Type] {
69            return [
70                Type<MetadataViews.ExternalURL>(),
71                Type<MetadataViews.Display>(),
72                Type<MetadataViews.Royalties>(),
73                Type<MetadataViews.NFTCollectionData>(),
74                Type<MetadataViews.NFTCollectionDisplay>()
75            ]
76        }
77
78        pub fun resolveView(_ view: Type): AnyStruct? {
79            switch view {
80                case Type<MetadataViews.ExternalURL>():
81                    return MetadataViews.ExternalURL(
82                        url: ArenaBoyz.metadataUrl.concat("heroes/").concat(self.id.toString())
83                    )
84                case Type<MetadataViews.Display>():
85                    return MetadataViews.Display(
86                        name: ("ArenaBoyz #").concat(self.id.toString()),
87                        description: "A Superhero capable of doing battle in the ArenaBoyz Game!",
88                        thumbnail: MetadataViews.HTTPFile(
89                        url: ArenaBoyz.metadataUrl.concat("heroes/i/").concat(self.id.toString()).concat(".png")
90                        )
91                    )
92                case Type<MetadataViews.Royalties>():
93                    let royalties : [MetadataViews.Royalty] = []
94                    royalties.append(MetadataViews.Royalty(recepient: ArenaBoyz.account.getCapability<&{FungibleToken.Receiver}>(MetadataViews.getRoyaltyReceiverPublicPath()), cut: UFix64(0.10), description: "Crypthulhu royalties"))
95                    return MetadataViews.Royalties(cutInfos: royalties)
96                   
97                case Type<MetadataViews.NFTCollectionData>():
98                    return MetadataViews.NFTCollectionData(
99                        storagePath: ArenaBoyz.CollectionStoragePath,
100                        publicPath: ArenaBoyz.CollectionPublicPath,
101                        providerPath: /private/abCollection,
102                        publicCollection: Type<&ArenaBoyz.Collection{ArenaBoyz.CollectionPublic}>(),
103                        publicLinkedType: Type<&ArenaBoyz.Collection{ArenaBoyz.CollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(),
104                        providerLinkedType: Type<&ArenaBoyz.Collection{ArenaBoyz.CollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(),
105                        createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
106                            return <-ArenaBoyz.createEmptyCollection()
107                        })
108                    )
109                case Type<MetadataViews.NFTCollectionDisplay>():
110                    return MetadataViews.NFTCollectionDisplay(
111                        name: "ArenaBoyz",
112                        description: "ArenaBoyz is a ...",
113                        externalURL: MetadataViews.ExternalURL("https://"),
114                        squareImage: MetadataViews.Media(
115                            file: MetadataViews.HTTPFile(url: ArenaBoyz.metadataUrl.concat("heroes/collection_image.png")),
116                            mediaType: "image/png"
117                        ),
118                        bannerImage: MetadataViews.Media(
119                            file: MetadataViews.HTTPFile(url: ArenaBoyz.metadataUrl.concat("heroes/collection_banner.png")),
120                            mediaType: "image/png"
121                        ),
122                        socials: {
123                            "discord": MetadataViews.ExternalURL("https://"),
124                            "twitter": MetadataViews.ExternalURL("https://")
125                        }
126                    )
127                    
128            }
129
130            return nil
131        }
132    }
133
134    pub resource interface CollectionPublic {
135        pub fun deposit(token: @NonFungibleToken.NFT)
136        pub fun getIDs(): [UInt64]
137        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
138        pub fun borrowArenaBoyz(id: UInt64): &ArenaBoyz.NFT? {
139            post {
140                (result == nil) || (result?.id == id):
141                    "Cannot borrow ArenaBoyz reference: the ID of the returned reference is incorrect"
142            }
143        }
144    }
145
146    pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection {
147        // dictionary of NFT conforming tokens
148        // NFT is a resource type with an `UInt64` ID field
149        pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
150
151        init () {
152            self.ownedNFTs <- {}
153        }
154
155        // withdraw removes an NFT from the collection and moves it to the caller
156        pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
157           
158            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
159
160            emit Withdraw(id: token.id, from: self.owner?.address)
161
162            return <-token
163        }
164
165        // deposit takes a NFT and adds it to the collections dictionary
166        // and adds the ID to the id array
167        pub fun deposit(token: @NonFungibleToken.NFT) {
168            let token <- token as! @ArenaBoyz.NFT
169
170            let id: UInt64 = token.id
171
172            // add the new token to the dictionary which removes the old one
173            let oldToken <- self.ownedNFTs[id] <- token
174
175            emit Deposit(id: id, to: self.owner?.address)
176
177            destroy oldToken
178        }
179
180        // getIDs returns an array of the IDs that are in the collection
181        pub fun getIDs(): [UInt64] {
182            return self.ownedNFTs.keys
183        }
184
185        // borrowNFT gets a reference to an NFT in the collection
186        // so that the caller can read its metadata and call its methods
187        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
188            return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
189        }
190 
191        pub fun borrowArenaBoyz(id: UInt64): &ArenaBoyz.NFT? {
192            if self.ownedNFTs[id] != nil {
193                // Create an authorized reference to allow downcasting
194                let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
195                return ref as! &ArenaBoyz.NFT
196            }
197
198            return nil
199        }
200
201        pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
202            let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
203            let abNft = nft as! &ArenaBoyz.NFT
204            return abNft as &AnyResource{MetadataViews.Resolver}
205        }
206
207        destroy() {
208            destroy self.ownedNFTs
209        }
210    }
211
212    // public function that anyone can call to create a new empty collection
213    pub fun createEmptyCollection(): @NonFungibleToken.Collection {
214        return <- create Collection()
215    }
216
217    // Resource that an admin or something similar would own to be
218    // able to mint new NFTs
219    //
220    pub resource NFTMinter {
221        // range if possible
222        pub fun getNextCustomID(): UInt64 {
223            var nextId = ArenaBoyz.customSupply + UInt64(1)
224            return (nextId <= 1000) ? nextId : self.getNextCommonID()
225        }
226
227        // Determine the next available ID for genesis NFTs and use the reserved
228        // range if possible
229        pub fun getNextGenesisID(): UInt64 {
230            var nextId = UInt64(1000) + ArenaBoyz.genesisSupply + UInt64(1)
231            return (nextId <= 11000) ? nextId : panic("Cannot mint more than 10000 genesis NFTs")
232        }
233
234        // Determine the next available ID for the rest of NFTs and take into
235        // account the custom NFTs that have been minted outside of the reserved
236        // range
237        pub fun getNextCommonID(): UInt64 {
238            var customIdOverflow = Int256(ArenaBoyz.customSupply) - Int256(1000)
239            customIdOverflow = customIdOverflow > 0 ? customIdOverflow : 0
240            return 11000 + ArenaBoyz.commonSupply + UInt64(customIdOverflow) + UInt64(1)
241        }
242
243        pub fun mintCustomNFT(
244            recipient: &Collection{NonFungibleToken.CollectionPublic},
245        ) {
246            var nextId = self.getNextCustomID()
247
248            // Update supply counters
249            ArenaBoyz.customSupply = ArenaBoyz.customSupply + UInt64(1)
250            ArenaBoyz.totalSupply = ArenaBoyz.totalSupply + UInt64(1)
251
252            self.mint(
253                recipient: recipient,
254                id: nextId,
255                type: ArenaBoyz.NFTType.custom
256            )
257        }
258
259        pub fun mintGenesisNFT(
260            recipient: &Collection{NonFungibleToken.CollectionPublic},
261        ) {
262            // Determine the next available ID
263            var nextId = self.getNextGenesisID()
264
265            // Update supply counters
266            ArenaBoyz.genesisSupply = ArenaBoyz.genesisSupply + UInt64(1)
267            ArenaBoyz.totalSupply = ArenaBoyz.totalSupply + UInt64(1)
268
269            self.mint(
270                recipient: recipient,
271                id: nextId,
272                type: ArenaBoyz.NFTType.genesis
273            )
274        }
275
276        pub fun mintNFT(
277            recipient: &Collection{NonFungibleToken.CollectionPublic},
278        ) {
279            // Determine the next available ID
280            var nextId = self.getNextCommonID()
281
282            // Update supply counters
283            ArenaBoyz.commonSupply = ArenaBoyz.commonSupply + UInt64(1)
284            ArenaBoyz.totalSupply = ArenaBoyz.totalSupply + UInt64(1)
285
286            self.mint(
287                recipient: recipient,
288                id: nextId,
289                type: ArenaBoyz.NFTType.common
290            )
291        }
292
293        
294
295        priv fun mint(
296            recipient: &Collection{NonFungibleToken.CollectionPublic},
297            id: UInt64,
298            type: ArenaBoyz.NFTType,
299        ) {
300            // create a new NFT
301            var newNFT <- create NFT(id: id, type: type)
302            switch newNFT.type {
303                case NFTType.custom:
304                    emit Mint(id: id, type: UInt8(0))
305                case NFTType.genesis:
306                    emit Mint(id: id, type: UInt8(1))
307                case NFTType.common:
308                    emit Mint(id: id, type: UInt8(2))
309            }
310            // deposit it in the recipient's account using their reference
311            recipient.deposit(token: <-newNFT)
312        }
313    }
314
315    pub resource Admin {
316     
317
318        pub fun setMetadataUrl(url: String) {
319            ArenaBoyz.metadataUrl = url
320        }
321
322        pub fun createNFTMinter(): @NFTMinter {
323            emit MinterCreated()
324            return <-create NFTMinter()
325        }
326    }
327
328    init() {
329        // Initialize supply counters
330        self.totalSupply = 0
331        self.customSupply = 0
332        self.genesisSupply = 0
333        self.commonSupply = 0
334
335        // Initialize burned counters
336        self.totalBurned = 0
337        self.customBurned = 0
338        self.genesisBurned = 0
339        self.commonBurned = 0
340
341        self.metadataUrl = "https://"
342
343        // Set the named paths
344        self.CollectionStoragePath = /storage/abCollection
345        self.CollectionPublicPath = /public/abCollection
346        self.AdminStoragePath = /storage/abAdmin
347        self.MinterStoragePath = /storage/abMinter
348
349        // Create a Collection resource and save it to storage
350        let collection <- create Collection()
351        self.account.save(<-collection, to: self.CollectionStoragePath)
352
353        // create a public capability for the collection
354        self.account.link<&ArenaBoyz.Collection{NonFungibleToken.CollectionPublic, CollectionPublic}>(
355            self.CollectionPublicPath,
356            target: self.CollectionStoragePath
357        )
358
359        let admin <- create Admin()
360        let minter <- admin.createNFTMinter()
361        self.account.save(<-admin, to: self.AdminStoragePath)
362        self.account.save(<-minter, to: self.MinterStoragePath)
363
364        emit ContractInitialized()
365    }
366}
367