Smart Contract
Inscription
A.88dd257fcf26d3cc.Inscription
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