Smart Contract

Sharks

A.1c7d5d603d4010e4.Sharks

Deployed

3d ago
Feb 25, 2026, 05:20:29 PM UTC

Dependents

2 imports
1// Description: Smart Contract for Sharks Virtual Commemorative Tickets
2// SPDX-License-Identifier: UNLICENSED
3
4import NonFungibleToken from 0x1d7e57aa55817448
5import MetadataViews from 0x1d7e57aa55817448
6import ViewResolver from 0x1d7e57aa55817448
7
8access(all) contract Sharks : NonFungibleToken {
9
10    access(all) var totalSupply: UInt64
11
12    access(all) event ContractInitialized()
13    access(all) event Withdraw(id: UInt64, from: Address?)
14    access(all) event Deposit(id: UInt64, to: Address?)
15
16    access(all) let CollectionStoragePath: StoragePath
17    access(all) let CollectionPublicPath: PublicPath
18    access(all) let MinterStoragePath: StoragePath
19
20    // Correct type from NonFungibleToken.INFT to NonFungibleToken.NFT
21    access(all) resource NFT : NonFungibleToken.NFT {
22        access(all) let id: UInt64
23        access(all) var link: String
24        access(all) var batch: UInt32
25        access(all) var sequence: UInt16
26        access(all) var limit: UInt16
27
28        init(
29            initID: UInt64,
30            initlink: String,
31            initbatch: UInt32,
32            initsequence: UInt16,
33            initlimit: UInt16
34        ) {
35            self.id = initID
36            self.link = initlink
37            self.batch = initbatch
38            self.sequence = initsequence
39            self.limit = initlimit
40        }
41
42        /// createEmptyCollection creates an empty Collection
43        /// and returns it to the caller so that they can own NFTs
44        /// @{NonFungibleToken.Collection}
45        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
46            return <-Sharks.createEmptyCollection(nftType: Type<@Sharks.NFT>())
47        }
48
49        access(all) view fun getViews(): [Type] {
50            return [
51                Type<MetadataViews.NFTCollectionData>()
52            ]
53        }
54
55        access(all) fun resolveView(_ view: Type): AnyStruct? {
56            switch view {
57                case Type<MetadataViews.NFTCollectionData>():
58                    return Sharks.resolveContractView(resourceType: Type<@Sharks.NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
59            }
60            return nil
61        }
62    }
63
64    // Ensure all type specifications conform to interface requirements
65    access(all) resource interface SharksCollectionPublic {
66        // Deprecated, only here for backwards compatibility
67    }
68
69    access(all) resource Collection : NonFungibleToken.Collection, SharksCollectionPublic {
70        access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
71
72        init() {
73            self.ownedNFTs <- {}
74        }
75
76        /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
77        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
78            let supportedTypes: {Type: Bool} = {}
79            supportedTypes[Type<@Sharks.NFT>()] = true
80            return supportedTypes
81        }
82
83        /// Returns whether or not the given type is accepted by the collection
84        /// A collection that can accept any type should just return true by default
85        access(all) view fun isSupportedNFTType(type: Type): Bool {
86            return type == Type<@Sharks.NFT>()
87        }
88
89        /// withdraw removes an NFT from the collection and moves it to the caller
90        access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
91            let token <- self.ownedNFTs.remove(key: withdrawID)
92                ?? panic("Could not withdraw an NFT with the provided ID from the collection")
93
94            return <-token
95        }
96
97        /// deposit takes a NFT and adds it to the collections dictionary
98        /// and adds the ID to the id array
99        access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
100            let token <- token as! @Sharks.NFT
101            let id = token.id
102
103            // add the new token to the dictionary which removes the old one
104            let oldToken <- self.ownedNFTs[token.id] <- token
105
106            destroy oldToken
107
108            // This code is for testing purposes only
109            // Do not add to your contract unless you have a specific
110            // reason to want to emit the NFTUpdated event somewhere
111            // in your contract
112            let authTokenRef = (&self.ownedNFTs[id] as auth(NonFungibleToken.Update) &{NonFungibleToken.NFT}?)!
113            //authTokenRef.updateTransferDate(date: getCurrentBlock().timestamp)
114            Sharks.emitNFTUpdated(authTokenRef)
115        }
116
117        /// getIDs returns an array of the IDs that are in the collection
118        access(all) view fun getIDs(): [UInt64] {
119            return self.ownedNFTs.keys
120        }
121
122        /// Gets the amount of NFTs stored in the collection
123        access(all) view fun getLength(): Int {
124            return self.ownedNFTs.length
125        }
126
127        /// Borrow the view resolver for the specified NFT ID
128        access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
129            if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
130                return nft as &{ViewResolver.Resolver}
131            }
132            return nil
133        }
134
135        access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
136            return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
137        }
138
139        /// createEmptyCollection creates an empty Collection of the same type
140        /// and returns it to the caller
141        /// @return A an empty collection of the same type
142        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
143            return <- Sharks.createEmptyCollection(nftType: Type<@Sharks.NFT>())
144        }
145    }
146
147    /// createEmptyCollection creates an empty Collection for the specified NFT type
148    /// and returns it to the caller so that they can own NFTs
149    access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
150        return <- create Collection()
151    }
152
153    /// Function that returns all the Metadata Views implemented by a Non Fungible Token
154    ///
155    /// @return An array of Types defining the implemented views. This value will be used by
156    ///         developers to know which parameter to pass to the resolveView() method.
157    ///
158    access(all) view fun getContractViews(resourceType: Type?): [Type] {
159        return [
160            Type<MetadataViews.NFTCollectionData>(),
161            Type<MetadataViews.NFTCollectionDisplay>(),
162            Type<MetadataViews.EVMBridgedMetadata>()
163        ]
164    }
165
166    /// Function that resolves a metadata view for this contract.
167    ///
168    /// @param view: The Type of the desired view.
169    /// @return A structure representing the requested view.
170    ///
171    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
172        switch viewType {
173            case Type<MetadataViews.NFTCollectionData>():
174                let collectionData = MetadataViews.NFTCollectionData(
175                    storagePath: self.CollectionStoragePath,
176                    publicPath: self.CollectionPublicPath,
177                    publicCollection: Type<&Sharks.Collection>(),
178                    publicLinkedType: Type<&Sharks.Collection>(),
179                    createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
180                        return <-Sharks.createEmptyCollection(nftType: Type<@Sharks.NFT>())
181                    })
182                )
183                return collectionData
184            case Type<MetadataViews.NFTCollectionDisplay>():
185                let media = MetadataViews.Media(
186                    file: MetadataViews.HTTPFile(
187                        url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg"
188                    ),
189                    mediaType: "image/svg+xml"
190                )
191                return MetadataViews.NFTCollectionDisplay(
192                    name: "Sharks Collection",
193                    description: "This collection represents Sharks Virtual Commemorative Tickets.",
194                    externalURL: MetadataViews.ExternalURL("https://sharks-nft.onflow.org"),
195                    squareImage: media,
196                    bannerImage: media,
197                    socials: {
198                        "twitter": MetadataViews.ExternalURL("https://twitter.com/sharks")
199                    }
200                )
201            case Type<MetadataViews.EVMBridgedMetadata>():
202                // Implementing this view gives the project control over how the bridged NFT is represented as an ERC721
203                // when bridged to EVM on Flow via the public infrastructure bridge.
204
205                // Compose the contract-level URI. In this case, the contract metadata is located on some HTTP host,
206                // but it could be IPFS, S3, a data URL containing the JSON directly, etc.
207                return MetadataViews.EVMBridgedMetadata(
208                    name: "Sharks",
209                    symbol: "SHRK",
210                    uri: MetadataViews.URI(
211                        baseURI: nil, // setting baseURI as nil sets the given value as the uri field value
212                        value: "https://sharks-nft.onflow.org/contract-metadata.json"
213                    )
214                )
215        }
216        return nil
217    }
218
219    /// Resource that an admin or something similar would own to be
220    /// able to mint new NFTs
221    ///
222    access(all) resource NFTMinter {
223
224        /// mintNFT mints a new NFT with a new ID
225        /// and returns it to the calling context
226        access(all) fun mintNFT(
227            glink: String,
228            gbatch: UInt32,
229            glimit: UInt16,
230            gsequence: UInt16
231        ): @Sharks.NFT {
232
233            let tokenID = (UInt64(gbatch) << 32) | (UInt64(glimit) << 16) | UInt64(gsequence)
234
235            let metadata: {String: AnyStruct} = {}
236            let currentBlock = getCurrentBlock()
237            metadata["mintedBlock"] = currentBlock.height
238            metadata["mintedTime"] = currentBlock.timestamp
239
240            // this piece of metadata will be used to show embedding rarity into a trait
241            metadata["foo"] = "bar"
242
243            // create a new NFT
244            var newNFT <- create NFT(
245                initID: tokenID,
246                initlink: glink,
247                initbatch: gbatch,
248                initsequence: gsequence,
249                initlimit: glimit
250            )
251            Sharks.totalSupply = Sharks.totalSupply + 1
252            return <-newNFT
253        }
254    }
255
256    init() {
257        self.CollectionStoragePath = /storage/SharksCollection
258        self.CollectionPublicPath = /public/SharksCollection
259        self.MinterStoragePath = /storage/SharksMinter
260        self.totalSupply = 0
261
262        let collection <- create Collection()
263        self.account.storage.save(<-collection, to: self.CollectionStoragePath)
264
265        let collectionCap = self.account.capabilities.storage.issue<&Sharks.Collection>(self.CollectionStoragePath)
266        self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
267
268        let minter <- create NFTMinter()
269        self.account.storage.save(<-minter, to: self.MinterStoragePath)
270    }
271}
272