@flowtyio/flow-contracts 0.1.0-beta.2 → 0.1.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/contracts/Burner.cdc +44 -0
  2. package/contracts/FlowStorageFees.cdc +15 -15
  3. package/contracts/FlowToken.cdc +29 -78
  4. package/contracts/FungibleToken.cdc +80 -53
  5. package/contracts/FungibleTokenMetadataViews.cdc +13 -25
  6. package/contracts/MetadataViews.cdc +107 -50
  7. package/contracts/NonFungibleToken.cdc +110 -60
  8. package/contracts/TokenForwarding.cdc +19 -11
  9. package/contracts/ViewResolver.cdc +20 -16
  10. package/contracts/dapper/DapperUtilityCoin.cdc +106 -39
  11. package/contracts/dapper/FlowUtilityToken.cdc +107 -40
  12. package/contracts/dapper/TopShot.cdc +323 -259
  13. package/contracts/dapper/TopShotLocking.cdc +41 -15
  14. package/contracts/dapper/offers/DapperOffersV2.cdc +36 -40
  15. package/contracts/dapper/offers/OffersV2.cdc +52 -51
  16. package/contracts/dapper/offers/Resolver.cdc +13 -12
  17. package/contracts/emerald-city/FLOAT.cdc +259 -254
  18. package/contracts/example/ExampleNFT.cdc +419 -0
  19. package/contracts/example/ExampleToken.cdc +302 -0
  20. package/contracts/find/FindViews.cdc +357 -353
  21. package/contracts/flow-utils/AddressUtils.cdc +20 -23
  22. package/contracts/flow-utils/ArrayUtils.cdc +10 -11
  23. package/contracts/flow-utils/ScopedFTProviders.cdc +27 -19
  24. package/contracts/flow-utils/ScopedNFTProviders.cdc +31 -26
  25. package/contracts/flow-utils/StringUtils.cdc +24 -37
  26. package/contracts/hybrid-custody/CapabilityDelegator.cdc +29 -26
  27. package/contracts/hybrid-custody/CapabilityFactory.cdc +21 -18
  28. package/contracts/hybrid-custody/CapabilityFilter.cdc +42 -24
  29. package/contracts/hybrid-custody/HybridCustody.cdc +303 -242
  30. package/contracts/hybrid-custody/factories/FTAllFactory.cdc +16 -4
  31. package/contracts/hybrid-custody/factories/FTBalanceFactory.cdc +16 -4
  32. package/contracts/hybrid-custody/factories/FTProviderFactory.cdc +17 -5
  33. package/contracts/hybrid-custody/factories/FTReceiverBalanceFactory.cdc +16 -4
  34. package/contracts/hybrid-custody/factories/FTReceiverFactory.cdc +16 -4
  35. package/contracts/hybrid-custody/factories/FTVaultFactory.cdc +45 -0
  36. package/contracts/hybrid-custody/factories/NFTCollectionFactory.cdc +45 -0
  37. package/contracts/hybrid-custody/factories/NFTCollectionPublicFactory.cdc +16 -4
  38. package/contracts/hybrid-custody/factories/NFTProviderAndCollectionPublicFactory.cdc +16 -4
  39. package/contracts/hybrid-custody/factories/NFTProviderFactory.cdc +16 -4
  40. package/contracts/lost-and-found/LostAndFound.cdc +14 -14
  41. package/contracts/nft-catalog/NFTCatalog.cdc +60 -64
  42. package/contracts/nft-catalog/NFTCatalogAdmin.cdc +28 -27
  43. package/flow.json +38 -1
  44. package/package.json +1 -1
@@ -0,0 +1,419 @@
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 NFTs would implement the core functionality.
6
+ *
7
+ * This contract does not implement any sophisticated classification
8
+ * system for its NFTs. It defines a simple NFT with minimal metadata.
9
+ *
10
+ */
11
+
12
+ import "NonFungibleToken"
13
+ import "MetadataViews"
14
+ import "ViewResolver"
15
+ import "FungibleToken"
16
+
17
+ // THIS CONTRACT IS FOR TESTING PURPOSES ONLY!
18
+ access(all) contract ExampleNFT: ViewResolver {
19
+
20
+ access(all) var totalSupply: UInt64
21
+
22
+ access(all) event ContractInitialized()
23
+ access(all) event Withdraw(id: UInt64, from: Address?)
24
+ access(all) event Deposit(id: UInt64, to: Address?)
25
+ access(all) event Mint(id: UInt64)
26
+
27
+ access(all) event CollectionCreated(id: UInt64)
28
+ access(all) event CollectionDestroyed(id: UInt64)
29
+
30
+ access(all) let CollectionStoragePath: StoragePath
31
+ access(all) let CollectionPublicPath: PublicPath
32
+ access(all) let MinterStoragePath: StoragePath
33
+ access(all) let MinterPublicPath: PublicPath
34
+
35
+ access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver {
36
+ access(all) let id: UInt64
37
+
38
+ access(all) let name: String
39
+ access(all) let description: String
40
+ access(all) let thumbnail: String
41
+ access(self) var royalties: [MetadataViews.Royalty]
42
+
43
+ access(all) view fun getID(): UInt64 {
44
+ return self.id
45
+ }
46
+
47
+ init(
48
+ id: UInt64,
49
+ name: String,
50
+ description: String,
51
+ thumbnail: String,
52
+ royalties: [MetadataViews.Royalty]
53
+ ) {
54
+ self.id = id
55
+ self.name = name
56
+ self.description = description
57
+ self.thumbnail = thumbnail
58
+ self.royalties = royalties
59
+
60
+ emit Mint(id: self.id)
61
+ }
62
+
63
+ access(Mutate) fun setRoyalties(_ royalties: [MetadataViews.Royalty]) {
64
+ self.royalties = royalties
65
+ }
66
+
67
+ access(all) view fun getViews(): [Type] {
68
+ return [
69
+ Type<MetadataViews.Display>(),
70
+ Type<MetadataViews.Royalties>(),
71
+ Type<MetadataViews.Editions>(),
72
+ Type<MetadataViews.ExternalURL>(),
73
+ Type<MetadataViews.NFTCollectionData>(),
74
+ Type<MetadataViews.NFTCollectionDisplay>(),
75
+ Type<MetadataViews.Serial>(),
76
+ Type<MetadataViews.Traits>()
77
+ ]
78
+ }
79
+
80
+ access(all) fun resolveView(_ view: Type): AnyStruct? {
81
+ switch view {
82
+ case Type<MetadataViews.Display>():
83
+ return MetadataViews.Display(
84
+ name: self.name,
85
+ description: self.description,
86
+ thumbnail: MetadataViews.HTTPFile(
87
+ url: self.thumbnail
88
+ )
89
+ )
90
+ case Type<MetadataViews.Editions>():
91
+ // There is no max number of NFTs that can be minted from this contract
92
+ // so the max edition field value is set to nil
93
+ let editionName = self.id % 2 == 0 ? "Example NFT Edition (even)" : "Example NFT Edition (odd)"
94
+ let editionInfo = MetadataViews.Edition(name: editionName, number: self.id, max: nil)
95
+ let editionList: [MetadataViews.Edition] = [editionInfo]
96
+ return MetadataViews.Editions(
97
+ editionList
98
+ )
99
+ case Type<MetadataViews.Serial>():
100
+ return MetadataViews.Serial(
101
+ self.id
102
+ )
103
+ case Type<MetadataViews.Royalties>():
104
+ return MetadataViews.Royalties(
105
+ self.royalties
106
+ )
107
+ case Type<MetadataViews.ExternalURL>():
108
+ return MetadataViews.ExternalURL("https://example-nft.onflow.org/".concat(self.id.toString()))
109
+ case Type<MetadataViews.NFTCollectionData>():
110
+ return MetadataViews.NFTCollectionData(
111
+ storagePath: ExampleNFT.CollectionStoragePath,
112
+ publicPath: ExampleNFT.CollectionPublicPath,
113
+ publicCollection: Type<&ExampleNFT.Collection>(),
114
+ publicLinkedType: Type<&ExampleNFT.Collection>(),
115
+ createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
116
+ return <-ExampleNFT.createEmptyCollection()
117
+ })
118
+ )
119
+ case Type<MetadataViews.NFTCollectionDisplay>():
120
+ let media = MetadataViews.Media(
121
+ file: MetadataViews.HTTPFile(
122
+ url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg"
123
+ ),
124
+ mediaType: "image/svg+xml"
125
+ )
126
+ return MetadataViews.NFTCollectionDisplay(
127
+ name: "The Example Collection",
128
+ description: "This collection is used as an example to help you develop your next Flow NFT.",
129
+ externalURL: MetadataViews.ExternalURL("https://example-nft.onflow.org"),
130
+ squareImage: media,
131
+ bannerImage: media,
132
+ socials: {
133
+ "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain")
134
+ }
135
+ )
136
+ case Type<MetadataViews.Traits>():
137
+ let dict: {String: AnyStruct} = {
138
+ "name": self.name,
139
+ "even": self.id % 2 == 0,
140
+ "id": self.id
141
+ }
142
+ return MetadataViews.dictToTraits(dict: dict, excludedNames: [])
143
+ }
144
+ return nil
145
+ }
146
+
147
+ access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
148
+ return <- ExampleNFT.createEmptyCollection()
149
+ }
150
+ }
151
+
152
+ access(all) resource interface ExampleNFTCollectionPublic: NonFungibleToken.Collection {
153
+ access(all) fun deposit(token: @{NonFungibleToken.NFT})
154
+ access(all) fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? {
155
+ post {
156
+ (result == nil) || (result?.id == id):
157
+ "Cannot borrow ExampleNFT reference: the ID of the returned reference is incorrect"
158
+ }
159
+ }
160
+ }
161
+
162
+ access(all) resource Collection: ExampleNFTCollectionPublic {
163
+ access(all) event ResourceDestroyed(id: UInt64 = self.uuid)
164
+
165
+ // dictionary of NFT conforming tokens
166
+ // NFT is a resource type with an `UInt64` ID field
167
+ access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
168
+
169
+ init () {
170
+ self.ownedNFTs <- {}
171
+ emit CollectionCreated(id: self.uuid)
172
+ }
173
+
174
+ access(all) view fun getDefaultStoragePath(): StoragePath? {
175
+ return ExampleNFT.CollectionStoragePath
176
+ }
177
+
178
+ access(all) view fun getDefaultPublicPath(): PublicPath? {
179
+ return ExampleNFT.CollectionPublicPath
180
+ }
181
+
182
+ access(all) view fun getLength(): Int {
183
+ return self.ownedNFTs.length
184
+ }
185
+
186
+ access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
187
+ return {
188
+ Type<@ExampleNFT.NFT>(): true
189
+ }
190
+ }
191
+
192
+ access(all) view fun getIDs(): [UInt64] {
193
+ return self.ownedNFTs.keys
194
+ }
195
+
196
+ access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
197
+ return &self.ownedNFTs[id]
198
+ }
199
+
200
+ access(all) view fun isSupportedNFTType(type: Type): Bool {
201
+ return type == Type<@ExampleNFT.NFT>()
202
+ }
203
+
204
+ access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
205
+ return <- ExampleNFT.createEmptyCollection()
206
+ }
207
+
208
+ // withdraw removes an NFT from the collection and moves it to the caller
209
+ access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
210
+ let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
211
+
212
+ emit Withdraw(id: token.id, from: self.owner?.address)
213
+
214
+ return <-token
215
+ }
216
+
217
+ // deposit takes a NFT and adds it to the collections dictionary
218
+ // and adds the ID to the id array
219
+ access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
220
+ let token <- token as! @ExampleNFT.NFT
221
+
222
+ let id: UInt64 = token.id
223
+
224
+ // add the new token to the dictionary which removes the old one
225
+ let oldToken <- self.ownedNFTs[id] <- token
226
+
227
+ emit Deposit(id: id, to: self.owner?.address)
228
+
229
+ destroy oldToken
230
+ }
231
+
232
+ access(all) fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? {
233
+ if self.ownedNFTs[id] != nil {
234
+ // Create an authorized reference to allow downcasting
235
+ let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
236
+ return ref as! &ExampleNFT.NFT
237
+ }
238
+
239
+ return nil
240
+ }
241
+ }
242
+
243
+ // public function that anyone can call to create a new empty collection
244
+ access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
245
+ return <- create Collection()
246
+ }
247
+
248
+ // Resource that an admin or something similar would own to be
249
+ // able to mint new NFTs
250
+ //
251
+ access(all) resource NFTMinter {
252
+ // mintNFT mints a new NFT with a new ID
253
+ // and deposit it in the recipients collection using their collection reference
254
+ access(all) fun mintNFT(
255
+ recipient: &{NonFungibleToken.Collection},
256
+ name: String,
257
+ description: String,
258
+ thumbnail: String,
259
+ royaltyReceipient: Address,
260
+ ) {
261
+ ExampleNFT.totalSupply = ExampleNFT.totalSupply + 1
262
+ self.mintNFTWithId(recipient: recipient, name: name, description: description, thumbnail: thumbnail, royaltyReceipient: royaltyReceipient, id: ExampleNFT.totalSupply)
263
+ }
264
+
265
+ access(all) fun mint(
266
+ name: String,
267
+ description: String,
268
+ thumbnail: String,
269
+ ): @NFT {
270
+ ExampleNFT.totalSupply = ExampleNFT.totalSupply + 1
271
+ let newNFT <- create NFT(
272
+ id: ExampleNFT.totalSupply,
273
+ name: name,
274
+ description: description,
275
+ thumbnail: thumbnail,
276
+ royalties: []
277
+ )
278
+
279
+ return <- newNFT
280
+ }
281
+
282
+ access(all) fun mintNFTWithId(
283
+ recipient: &{NonFungibleToken.Collection},
284
+ name: String,
285
+ description: String,
286
+ thumbnail: String,
287
+ royaltyReceipient: Address,
288
+ id: UInt64
289
+ ) {
290
+ let royaltyRecipient = getAccount(royaltyReceipient).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)!
291
+ let cutInfo = MetadataViews.Royalty(receiver: royaltyRecipient, cut: 0.05, description: "")
292
+ // create a new NFT
293
+ var newNFT <- create NFT(
294
+ id: id,
295
+ name: name,
296
+ description: description,
297
+ thumbnail: thumbnail,
298
+ royalties: [cutInfo]
299
+ )
300
+
301
+ // deposit it in the recipient's account using their reference
302
+ recipient.deposit(token: <-newNFT)
303
+ }
304
+
305
+ // mintNFT mints a new NFT with a new ID
306
+ // and deposit it in the recipients collection using their collection reference
307
+ access(all) fun mintNFTWithRoyaltyCuts(
308
+ recipient: &{NonFungibleToken.Collection},
309
+ name: String,
310
+ description: String,
311
+ thumbnail: String,
312
+ royaltyReceipients: [Address],
313
+ royaltyCuts: [UFix64]
314
+ ) {
315
+ assert(royaltyReceipients.length == royaltyCuts.length, message: "mismatched royalty recipients and cuts")
316
+ let royalties: [MetadataViews.Royalty] = []
317
+
318
+ var index = 0
319
+ while index < royaltyReceipients.length {
320
+ let royaltyRecipient = getAccount(royaltyReceipients[index]).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)!
321
+ let cutInfo = MetadataViews.Royalty(receiver: royaltyRecipient, cut: royaltyCuts[index], description: "")
322
+ royalties.append(cutInfo)
323
+ index = index + 1
324
+ }
325
+
326
+ ExampleNFT.totalSupply = ExampleNFT.totalSupply + 1
327
+
328
+ // create a new NFT
329
+ var newNFT <- create NFT(
330
+ id: ExampleNFT.totalSupply,
331
+ name: name,
332
+ description: description,
333
+ thumbnail: thumbnail,
334
+ royalties: royalties
335
+ )
336
+
337
+ // deposit it in the recipient's account using their reference
338
+ recipient.deposit(token: <-newNFT)
339
+ }
340
+ }
341
+
342
+ /// Function that resolves a metadata view for this contract.
343
+ ///
344
+ /// @param view: The Type of the desired view.
345
+ /// @return A structure representing the requested view.
346
+ ///
347
+ access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
348
+ switch viewType {
349
+ case Type<MetadataViews.NFTCollectionData>():
350
+ return MetadataViews.NFTCollectionData(
351
+ storagePath: ExampleNFT.CollectionStoragePath,
352
+ publicPath: ExampleNFT.CollectionPublicPath,
353
+ publicCollection: Type<&ExampleNFT.Collection>(),
354
+ publicLinkedType: Type<&ExampleNFT.Collection>(),
355
+ createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
356
+ return <-ExampleNFT.createEmptyCollection()
357
+ })
358
+ )
359
+ case Type<MetadataViews.NFTCollectionDisplay>():
360
+ let media = MetadataViews.Media(
361
+ file: MetadataViews.HTTPFile(
362
+ url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg"
363
+ ),
364
+ mediaType: "image/svg+xml"
365
+ )
366
+ return MetadataViews.NFTCollectionDisplay(
367
+ name: "The Example Collection",
368
+ description: "This collection is used as an example to help you develop your next Flow NFT.",
369
+ externalURL: MetadataViews.ExternalURL("https://example-nft.onflow.org"),
370
+ squareImage: media,
371
+ bannerImage: media,
372
+ socials: {
373
+ "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain")
374
+ }
375
+ )
376
+ }
377
+ return nil
378
+ }
379
+
380
+ /// Function that returns all the Metadata Views implemented by a Non Fungible Token
381
+ ///
382
+ /// @return An array of Types defining the implemented views. This value will be used by
383
+ /// developers to know which parameter to pass to the resolveView() method.
384
+ ///
385
+ access(all) view fun getContractViews(resourceType: Type?): [Type] {
386
+ return [
387
+ Type<MetadataViews.NFTCollectionData>(),
388
+ Type<MetadataViews.NFTCollectionDisplay>()
389
+ ]
390
+ }
391
+
392
+ init() {
393
+ // Initialize the total supply
394
+ self.totalSupply = 0
395
+
396
+ // Set the named paths
397
+ self.CollectionStoragePath = /storage/exampleNFTCollection
398
+ self.CollectionPublicPath = /public/exampleNFTCollection
399
+ self.MinterStoragePath = /storage/exampleNFTMinter
400
+ self.MinterPublicPath = /public/exampleNFTMinter
401
+
402
+ // Create a Collection resource and save it to storage
403
+ let collection <- create Collection()
404
+ self.account.storage.save(<-collection, to: self.CollectionStoragePath)
405
+
406
+ // create a public capability for the collection
407
+ let cap = self.account.capabilities.storage.issue<&ExampleNFT.Collection>(self.CollectionStoragePath)
408
+ self.account.capabilities.publish(cap, at: self.CollectionPublicPath)
409
+
410
+ // Create a Minter resource and save it to storage
411
+ let minter <- create NFTMinter()
412
+ self.account.storage.save(<-minter, to: self.MinterStoragePath)
413
+ let minterCap = self.account.capabilities.storage.issue<&ExampleNFT.NFTMinter>(self.MinterStoragePath)
414
+ self.account.capabilities.publish(minterCap, at: self.MinterPublicPath)
415
+
416
+ emit ContractInitialized()
417
+ }
418
+ }
419
+