Smart Contract

DimensionXComics

A.e3ad6030cbaff1c2.DimensionXComics

Deployed

1d ago
Feb 26, 2026, 11:03:37 PM UTC

Dependents

0 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3import MetadataViews from 0x1d7e57aa55817448
4import DimensionX from 0xe3ad6030cbaff1c2
5import ViewResolver from 0x1d7e57aa55817448
6
7access(all) contract DimensionXComics: NonFungibleToken {
8
9    access(all) var totalSupply: UInt64
10    access(all) var totalBurned: UInt64
11
12    access(all) var metadataUrl: String
13
14    access(all) event ContractInitialized()
15    access(all) event Withdraw(id: UInt64, from: Address?)
16    access(all) event Deposit(id: UInt64, to: Address?)
17    access(all) event Mint(id: UInt64)
18    access(all) event Burn(id: UInt64)
19    access(all) event TurnIn(id: UInt64, hero: UInt64)
20
21    access(all) event MinterCreated()
22
23    access(all) let CollectionStoragePath: StoragePath
24    access(all) let CollectionPublicPath: PublicPath
25    access(all) let AdminStoragePath: StoragePath
26    access(all) let MinterStoragePath: StoragePath
27
28
29    access(all) resource NFT: NonFungibleToken.NFT {
30
31        access(all) let id: UInt64
32
33        init(
34            id: UInt64
35        ) {
36            self.id = id
37        }
38
39        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
40            return <-DimensionXComics.createEmptyCollection(nftType: Type<@DimensionXComics.NFT>())
41        }
42
43        access(all) view fun getViews(): [Type] {
44            return [
45                Type<MetadataViews.ExternalURL>(),
46                Type<MetadataViews.Display>(),
47                Type<MetadataViews.Royalties>(),
48                Type<MetadataViews.NFTCollectionData>(),
49                Type<MetadataViews.NFTCollectionDisplay>()
50            ]
51        }
52
53        access(all) fun resolveView(_ view: Type): AnyStruct? {
54            switch view {
55                case Type<MetadataViews.ExternalURL>():
56                    return MetadataViews.ExternalURL(
57                        DimensionXComics.metadataUrl.concat("comics/").concat(self.id.toString())
58                    )
59                case Type<MetadataViews.Display>():
60                    return MetadataViews.Display(
61                        name: ("DimensionXComics #").concat(self.id.toString()),
62                        description: "A Comics NFT Project with Utility in the Dimension-X Game!",
63                        thumbnail: MetadataViews.HTTPFile(
64                        url: DimensionXComics.metadataUrl.concat("comics/i/").concat(self.id.toString()).concat(".jpg")
65                        )
66                    )
67                case Type<MetadataViews.Royalties>():
68                    let royalties : [MetadataViews.Royalty] = []
69                    royalties.append(MetadataViews.Royalty(
70                        receiver: DimensionXComics.account.capabilities.get<&{FungibleToken.Receiver}>(MetadataViews.getRoyaltyReceiverPublicPath()),
71                        cut: 0.10,
72                        description: "Crypthulhu royalties"))
73                    return MetadataViews.Royalties(royalties)
74                   
75                case Type<MetadataViews.NFTCollectionData>():
76                    return DimensionX.resolveContractView(resourceType: Type<@DimensionXComics.NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
77                case Type<MetadataViews.NFTCollectionDisplay>():
78                    return DimensionX.resolveContractView(resourceType: Type<@DimensionXComics.NFT>(), viewType: Type<MetadataViews.NFTCollectionDisplay>())
79                case Type<MetadataViews.Serial>():
80                    return MetadataViews.Serial(
81                        self.id
82                    )
83            }
84
85            return nil
86        }
87    }
88
89    access(all) resource interface CollectionPublic {}
90
91    access(all) resource Collection: NonFungibleToken.Collection, CollectionPublic {
92        // dictionary of NFT conforming tokens
93        // NFT is a resource type with an `UInt64` ID field
94        access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
95
96        init () {
97            self.ownedNFTs <- {}
98        }
99
100        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
101            let supportedTypes: {Type: Bool} = {}
102            supportedTypes[Type<@DimensionXComics.NFT>()] = true
103            return supportedTypes
104        }
105
106        access(all) view fun isSupportedNFTType(type: Type): Bool {
107            return type == Type<@DimensionXComics.NFT>()
108        }
109
110        // withdraw removes an NFT from the collection and moves it to the caller
111        access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
112    
113            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
114
115            emit Withdraw(id: token.id, from: self.owner?.address)
116
117            return <-token
118        }
119
120        // deposit takes a NFT and adds it to the collections dictionary
121        // and adds the ID to the id array
122        access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
123            let token <- token as! @DimensionXComics.NFT
124
125            let id: UInt64 = token.id
126
127            // add the new token to the dictionary which removes the old one
128            let oldToken <- self.ownedNFTs[id] <- token
129
130            emit Deposit(id: id, to: self.owner?.address)
131
132            destroy oldToken
133        }
134
135        // getIDs returns an array of the IDs that are in the collection
136        access(all) view fun getIDs(): [UInt64] {
137            return self.ownedNFTs.keys
138        }
139
140        // borrowNFT gets a reference to an NFT in the collection
141        // so that the caller can read its metadata and call its methods
142        access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
143            return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
144        }
145 
146        /// Borrow the view resolver for the specified NFT ID
147        access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
148            if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
149                return nft as &{ViewResolver.Resolver}
150            }
151            return nil
152        }
153
154        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
155            return <-DimensionXComics.createEmptyCollection(nftType: Type<@DimensionXComics.NFT>())
156        }
157
158        access(NonFungibleToken.Withdraw) fun turnInComics(comic_ids: [UInt64], hero: &DimensionX.NFT)  {
159            if (comic_ids.length > 4) {
160                panic("Too many comics being burned")
161            }
162
163            if (self.owner?.address != hero.owner?.address) {
164                panic("You must own the hero")
165            }
166
167            for id in comic_ids {
168                let token <- self.withdraw(withdrawID: id)
169                emit TurnIn(id: token.id, hero: hero.id)
170                destroy token
171            }
172        }
173    }
174
175    // public function that anyone can call to create a new empty collection
176    access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
177        return <- create Collection()
178    }
179
180    access(all) view fun getContractViews(resourceType: Type?): [Type] {
181        return [
182            Type<MetadataViews.NFTCollectionData>(),
183            Type<MetadataViews.NFTCollectionDisplay>()
184        ]
185    }
186
187    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
188        switch viewType {
189            case Type<MetadataViews.NFTCollectionData>():
190                return MetadataViews.NFTCollectionData(
191                    storagePath: DimensionXComics.CollectionStoragePath,
192                    publicPath: DimensionXComics.CollectionPublicPath,
193                    publicCollection: Type<&DimensionXComics.Collection>(),
194                    publicLinkedType: Type<&DimensionXComics.Collection>(),
195                    createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
196                        return <-DimensionXComics.createEmptyCollection(nftType: Type<@DimensionXComics.NFT>())
197                    })
198                )
199            case Type<MetadataViews.NFTCollectionDisplay>():
200                return MetadataViews.NFTCollectionDisplay(
201                    name: "Dimension X",
202                    description: "Dimension X is a Free-to-Play, Play-to-Earn strategic role playing game on the Flow blockchain set in the Dimension X comic book universe, where a pan-dimensional explosion created super powered humans, aliens and monsters with radical and terrifying superpowers!",
203                    externalURL: MetadataViews.ExternalURL("https://dimensionxnft.com"),
204                    squareImage: MetadataViews.Media(
205                        file: MetadataViews.HTTPFile(url: DimensionXComics.metadataUrl.concat("comics/collection_image.png")),
206                        mediaType: "image/png"
207                    ),
208                    bannerImage: MetadataViews.Media(
209                        file: MetadataViews.HTTPFile(url: DimensionXComics.metadataUrl.concat("comics/collection_banner.png")),
210                        mediaType: "image/png"
211                    ),
212                    socials: {
213                        "discord": MetadataViews.ExternalURL("https://discord.gg/dimensionx"),
214                        "twitter": MetadataViews.ExternalURL("https://twitter.com/DimensionX_NFT")
215                    }
216                )
217        }
218        return nil
219    }
220
221    // Resource that an admin or something similar would own to be
222    // able to mint new NFTs
223    //
224    access(all) resource NFTMinter {
225        // range if possible
226  
227        // Determine the next available ID for the rest of NFTs and take into
228        // account the custom NFTs that have been minted outside of the reserved
229        // range
230        access(all) fun getNextID(): UInt64 {
231       
232            return DimensionXComics.totalSupply + UInt64(1)
233        }
234
235        access(all) fun mintNFT(
236            recipient: &DimensionXComics.Collection,
237        ) {
238            // Determine the next available ID
239            var nextId = self.getNextID()
240
241            // Update supply counters
242            DimensionXComics.totalSupply = DimensionXComics.totalSupply + UInt64(1)
243
244            self.mint(
245                recipient: recipient,
246                id: nextId
247            )
248        }
249
250        access(self) fun mint(
251            recipient: &DimensionXComics.Collection,
252            id: UInt64
253        ) {
254            // create a new NFT
255            var newNFT <- create NFT(id: id)
256            emit Mint(id: id)
257              
258            // deposit it in the recipient's account using their reference
259            recipient.deposit(token: <-newNFT)
260        }
261    }
262
263    access(all) resource Admin {
264
265
266        access(all) fun setMetadataUrl(url: String) {
267            DimensionXComics.metadataUrl = url
268        }
269
270        access(all) fun createNFTMinter(): @NFTMinter {
271            emit MinterCreated()
272            return <-create NFTMinter()
273        }
274    
275    }
276
277    init() {
278        // Initialize supply counters
279        self.totalSupply = 0
280
281        // Initialize burned counters
282        self.totalBurned = 0
283 
284        self.metadataUrl = "https://metadata.dimensionx.com/"
285
286
287
288        // Set the named paths
289        self.CollectionStoragePath = /storage/dmxComicsCollection
290        self.CollectionPublicPath = /public/dmxComicsCollection
291        self.AdminStoragePath = /storage/dmxComicsAdmin
292        self.MinterStoragePath = /storage/dmxComicsMinter
293
294        // Create a Collection resource and save it to storage
295        let collection <- create Collection()
296        self.account.storage.save(<-collection, to: self.CollectionStoragePath)
297
298        // create a public capability for the collection
299        let collectionCap = self.account.capabilities.storage.issue<&DimensionXComics.Collection>(self.CollectionStoragePath)
300        self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
301
302        let admin <- create Admin()
303        let minter <- admin.createNFTMinter()
304        self.account.storage.save(<-admin, to: self.AdminStoragePath)
305        self.account.storage.save(<-minter, to: self.MinterStoragePath)
306
307        emit ContractInitialized()
308    }
309}
310