Smart Contract

Inscription

A.88dd257fcf26d3cc.Inscription

Deployed

3d ago
Feb 25, 2026, 04:01:00 AM UTC

Dependents

3 imports
1/*
2*
3*  This is an example implementation of a Flow Non-Fungible Token
4*  It is not part of the official standard but it assumed to be
5*  similar to how many Inscriptions would implement the core functionality.
6*
7*  This contract does not implement any sophisticated classification
8*  system for its Inscriptions. It defines a simple Inscription with minimal metadata.
9*
10*/
11
12import NonFungibleToken from 0x1d7e57aa55817448
13import InscriptionMetadata from 0x88dd257fcf26d3cc
14import ViewResolver from 0x1d7e57aa55817448
15
16pub contract Inscription: NonFungibleToken, ViewResolver {
17
18    /// Total supply of Inscriptions in existence
19    pub var totalSupply: UInt64
20
21    /// Total supply of Inscriptions in existence
22    pub var hardCap: UInt64
23
24    /// The event that is emitted when the contract is created
25    pub event ContractInitialized()
26
27    /// The event that is emitted when an Inscription is withdrawn from a Collection
28    pub event Withdraw(id: UInt64, from: Address?)
29
30    /// The event that is emitted when Inscriptions are withdrawn from a Collection
31    pub event BatchWithdraw(ids: [UInt64], from: Address?)
32
33    /// The event that is emitted when an Inscription is deposited to a Collection
34    pub event Deposit(id: UInt64, to: Address?)
35
36    /// The event that is emitted when Inscriptions are deposited to a Collection
37    pub event BatchDeposit(ids: [UInt64], to: Address?)
38
39    /// The event that is emitted when an Inscription is burned from a address
40    pub event Burn(id: UInt64, from: Address?)
41
42    /// The event that is emitted when Inscription are burned from a address
43    pub event BatchBurn(ids: [UInt64], from: Address?)
44
45    /// Storage and Public Paths
46    pub let CollectionStoragePath: StoragePath
47    pub let CollectionPublicPath: PublicPath
48    pub let MinterStoragePath: StoragePath
49
50    /// The core resource that represents a Non Fungible Token.
51    /// New instances will be created using the InscriptionMinter resource
52    /// and stored in the Collection resource
53    ///
54    pub resource NFT: NonFungibleToken.INFT, InscriptionMetadata.Resolver {
55
56        /// The unique ID that each Inscription has
57        pub let id: UInt64
58
59        /// Metadata fields
60        pub let inscription: String
61
62        init(
63            id: UInt64,
64            inscription: String
65        ) {
66            self.id = id
67            self.inscription = inscription
68        }
69
70        /// Function that returns all the Metadata Views implemented by a Non Fungible Token
71        ///
72        /// @return An array of Types defining the implemented views. This value will be used by
73        ///         developers to know which parameter to pass to the resolveView() method.
74        ///
75        pub fun getViews(): [Type] {
76            return [
77                Type<InscriptionMetadata.InscriptionView>()
78            ]
79        }
80
81        /// Function that resolves a metadata view for this token.
82        ///
83        /// @param view: The Type of the desired view.
84        /// @return A structure representing the requested view.
85        ///
86        pub fun resolveView(_ view: Type): AnyStruct? {
87            switch view {
88                case Type<InscriptionMetadata.InscriptionView>():
89                    return InscriptionMetadata.InscriptionView(
90                        id : self.id,
91                        uuid: self.uuid,
92                        inscription : self.inscription,
93                    )
94                default:
95                    panic("Run-time Type: ".concat(view.identifier).concat(" not supported."))
96            }
97            return nil
98        }
99    }
100
101    /// Defines the methods that are particular to this Inscription contract collection
102    ///
103    pub resource interface InscriptionCollectionPublic {
104        pub fun deposit(token: @NonFungibleToken.NFT)
105        pub fun depositCollection(collection: @Inscription.Collection)
106        pub fun getIDs(): [UInt64]
107        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
108        pub fun borrowInscription(id: UInt64): &Inscription.NFT? {
109            post {
110                (result == nil) || (result?.id == id):
111                    "Cannot borrow Inscription reference: the ID of the returned reference is incorrect"
112            }
113        }
114    }
115
116    /// The resource that will be holding the Inscriptions inside any account.
117    /// In order to be able to manage Inscriptions any account will need to create
118    /// an empty collection first
119    ///
120    pub resource Collection: InscriptionCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, InscriptionMetadata.ResolverCollection {
121        // dictionary of Inscription conforming tokens
122        // Inscription is a resource type with an `UInt64` ID field
123        pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
124
125        init () {
126            self.ownedNFTs <- {}
127        }
128
129        /// Removes an Inscription from the collection and moves it to the caller
130        ///
131        /// @param withdrawID: The ID of the Inscription that wants to be withdrawn
132        /// @return The Inscription resource that has been taken out of the collection
133        ///
134        pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
135            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing Inscription")
136
137            emit Withdraw(id: token.id, from: self.owner?.address)
138
139            return <-token
140        }
141
142        /// Removes an Inscription from the collection and moves it to the caller
143        ///
144        /// @param withdrawID: The ID of the Inscription that wants to be withdrawn
145        /// @return The Inscription resource that has been taken out of the collection
146        ///
147        pub fun batchWithdraw(withdrawIDs: [UInt64]): @Collection {
148            var tokens: @Collection <- Inscription.createEmptyCollection()
149            for id in withdrawIDs {
150                let token <- self.ownedNFTs.remove(key: id) ?? panic("missing Inscription")
151                tokens.deposit(token: <- token)
152            }
153
154            emit BatchWithdraw(ids: withdrawIDs, from: self.owner?.address)
155
156            return <-tokens
157        }
158
159        /// Adds an Inscription to the collections dictionary and adds the ID to the id array
160        ///
161        /// @param token: The Inscription resource to be included in the collection
162        ///
163        pub fun deposit(token: @NonFungibleToken.NFT) {
164            let token <- token as! @Inscription.NFT
165
166            let id: UInt64 = token.id
167
168            // add the new token to the dictionary which removes the old one
169            let oldToken <- self.ownedNFTs[id] <- token
170
171            emit Deposit(id: id, to: self.owner?.address)
172
173            destroy oldToken
174        }
175
176        pub fun depositCollection(collection: @Inscription.Collection) {
177            let withdrawIds: [UInt64] = collection.getIDs()
178            for id in collection.getIDs() {
179                let token <- collection.ownedNFTs.remove(key: id) ?? panic("missing Inscription")
180                let oldToken <- self.ownedNFTs[id] <- token
181                destroy oldToken
182            }
183            emit BatchDeposit(ids: withdrawIds, to: self.owner?.address)
184            destroy collection
185        }
186
187        /// Helper method for getting the collection IDs
188        ///
189        /// @return An array containing the IDs of the Inscriptions in the collection
190        ///
191        pub fun getIDs(): [UInt64] {
192            return self.ownedNFTs.keys
193        }
194
195        /// Gets a reference to an Inscription in the collection so that
196        /// the caller can read its metadata and call its methods
197        ///
198        /// @param id: The ID of the wanted Inscription
199        /// @return A reference to the wanted Inscription resource
200        ///
201        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
202            return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
203        }
204
205        /// Gets a reference to an Inscription in the collection so that
206        /// the caller can read its metadata and call its methods
207        ///
208        /// @param id: The ID of the wanted Inscription
209        /// @return A reference to the wanted Inscription resource
210        ///
211        pub fun borrowInscription(id: UInt64): &Inscription.NFT? {
212            if self.ownedNFTs[id] != nil {
213                // Create an authorized reference to allow downcasting
214                let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
215                return ref as! &Inscription.NFT
216            }
217
218            return nil
219        }
220
221        pub fun burnInscription(ids: [UInt64]): [UInt64] {
222            var burnedId: [UInt64] = ids
223            let collection <- self.batchWithdraw(withdrawIDs: ids)
224            destroy collection
225            emit BatchBurn(ids: ids, from: self.owner?.address)
226            return burnedId
227        }
228
229        destroy() {
230            destroy self.ownedNFTs
231        }
232    }
233
234    /// Allows anyone to create a new empty collection
235    ///
236    /// @return The new Collection resource
237    ///
238    pub fun createEmptyCollection(): @Inscription.Collection {
239        return <- create Collection()
240    }
241
242    /// Mints a new Inscription with a new ID and deposit it in the
243    /// recipients collection using their collection reference
244    ///
245    /// @param recipient: A capability to the collection where the new Inscription will be deposited
246    /// @param amount: The amount in the inscription
247    ///
248    pub fun mintInscription(
249        recipient: &{NonFungibleToken.CollectionPublic},
250        amount: UInt64,
251    ) {
252        pre {
253            amount == UInt64(1000): "The amount minted must be equal to 1000"
254        }
255
256        post {
257            Inscription.totalSupply <= Inscription.hardCap: "Total supply must less than or equal to hard cap."
258        }
259
260        let inscription = "{\"p\":\"frc-20\",\"op\":\"mint\",\"tick\":\"ff\",\"amt\":\""
261            .concat(amount.toString())
262            .concat("\"}")
263
264        // create a new Inscription
265        var newInscription <- create NFT(
266            id: Inscription.totalSupply,
267            inscription: inscription,
268        )
269
270        // deposit it in the recipient's account using their reference
271        recipient.deposit(token: <-newInscription)
272
273        Inscription.totalSupply = Inscription.totalSupply + amount
274    }
275
276    /// Function that resolves a metadata view for this contract.
277    ///
278    /// @param view: The Type of the desired view.
279    /// @return A structure representing the requested view.
280    ///
281    pub fun resolveView(_ view: Type): AnyStruct? {
282        return nil
283    }
284
285    /// Function that returns all the Metadata Views implemented by a Non Fungible Token
286    ///
287    /// @return An array of Types defining the implemented views. This value will be used by
288    ///         developers to know which parameter to pass to the resolveView() method.
289    ///
290    pub fun getViews(): [Type] {
291        return []
292    }
293
294    init() {
295        // Initialize the total supply
296        self.totalSupply = 0
297        self.hardCap = 2_100_000_000
298
299        // Set the named paths
300        self.CollectionStoragePath = /storage/inscriptionCollection
301        self.CollectionPublicPath = /public/inscriptionCollection
302        self.MinterStoragePath = /storage/inscriptionMinter
303
304        // Create a Collection resource and save it to storage
305        let collection <- create Collection()
306        self.account.save(<-collection, to: self.CollectionStoragePath)
307
308        // create a public capability for the collection
309        self.account.link<&Inscription.Collection{NonFungibleToken.CollectionPublic, Inscription.InscriptionCollectionPublic, InscriptionMetadata.ResolverCollection}>(
310            self.CollectionPublicPath,
311            target: self.CollectionStoragePath
312        )
313
314        // Create a Minter resource and save it to storage
315        // let minter <- create InscriptionMinter()
316        // self.account.save(<-minter, to: self.MinterStoragePath)
317
318        emit ContractInitialized()
319    }
320}
321