@flowtyio/flow-contracts 0.1.0-beta.9 → 0.1.1

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 (64) hide show
  1. package/README.md +1 -1
  2. package/contracts/FungibleTokenSwitchboard.cdc +360 -0
  3. package/contracts/MetadataViews.cdc +79 -6
  4. package/contracts/NonFungibleToken.cdc +17 -10
  5. package/contracts/capability-cache/CapabilityCache.cdc +97 -0
  6. package/contracts/dapper/TopShot.cdc +323 -259
  7. package/contracts/dapper/TopShotLocking.cdc +41 -15
  8. package/contracts/dapper/offers/DapperOffersV2.cdc +46 -43
  9. package/contracts/dapper/offers/OffersV2.cdc +40 -56
  10. package/contracts/dapper/offers/Resolver.cdc +20 -13
  11. package/contracts/emerald-city/FLOAT.cdc +259 -254
  12. package/contracts/evm/CrossVMNFT.cdc +50 -0
  13. package/contracts/evm/EVM.cdc +851 -0
  14. package/contracts/evm/FlowEVMBridgeConfig.cdc +454 -0
  15. package/contracts/evm/FlowEVMBridgeHandlerInterfaces.cdc +163 -0
  16. package/contracts/evm/FlowEVMBridgeHandlers.cdc +230 -0
  17. package/contracts/evm/FlowEVMBridgeUtils.cdc +1303 -0
  18. package/contracts/evm/IBridgePermissions.cdc +19 -0
  19. package/contracts/evm/ICrossVM.cdc +12 -0
  20. package/contracts/evm/ICrossVMAsset.cdc +19 -0
  21. package/contracts/evm/Serialize.cdc +141 -0
  22. package/contracts/evm/SerializeMetadata.cdc +221 -0
  23. package/contracts/example/ExampleNFT.cdc +2 -2
  24. package/contracts/find/FindViews.cdc +357 -353
  25. package/contracts/flow-utils/ScopedFTProviders.cdc +5 -2
  26. package/contracts/flow-utils/ScopedNFTProviders.cdc +6 -2
  27. package/contracts/flowty-drops/ContractManager.cdc +73 -0
  28. package/contracts/flowty-drops/DropFactory.cdc +75 -0
  29. package/contracts/flowty-drops/DropTypes.cdc +282 -0
  30. package/contracts/flowty-drops/FlowtyActiveCheckers.cdc +113 -0
  31. package/contracts/flowty-drops/FlowtyAddressVerifiers.cdc +64 -0
  32. package/contracts/flowty-drops/FlowtyDrops.cdc +461 -0
  33. package/contracts/flowty-drops/FlowtyPricers.cdc +48 -0
  34. package/contracts/flowty-drops/initializers/ContractBorrower.cdc +14 -0
  35. package/contracts/flowty-drops/initializers/ContractInitializer.cdc +7 -0
  36. package/contracts/flowty-drops/initializers/OpenEditionInitializer.cdc +57 -0
  37. package/contracts/flowty-drops/nft/BaseCollection.cdc +97 -0
  38. package/contracts/flowty-drops/nft/BaseNFT.cdc +107 -0
  39. package/contracts/flowty-drops/nft/ContractFactory.cdc +13 -0
  40. package/contracts/flowty-drops/nft/ContractFactoryTemplate.cdc +48 -0
  41. package/contracts/flowty-drops/nft/NFTMetadata.cdc +140 -0
  42. package/contracts/flowty-drops/nft/OpenEditionNFT.cdc +42 -0
  43. package/contracts/flowty-drops/nft/OpenEditionTemplate.cdc +54 -0
  44. package/contracts/flowty-drops/nft/UniversalCollection.cdc +29 -0
  45. package/contracts/fungible-token-router/FungibleTokenRouter.cdc +103 -0
  46. package/contracts/hybrid-custody/CapabilityDelegator.cdc +28 -26
  47. package/contracts/hybrid-custody/CapabilityFactory.cdc +20 -18
  48. package/contracts/hybrid-custody/CapabilityFilter.cdc +41 -24
  49. package/contracts/hybrid-custody/HybridCustody.cdc +303 -242
  50. package/contracts/hybrid-custody/factories/FTAllFactory.cdc +16 -4
  51. package/contracts/hybrid-custody/factories/FTBalanceFactory.cdc +16 -4
  52. package/contracts/hybrid-custody/factories/FTProviderFactory.cdc +17 -5
  53. package/contracts/hybrid-custody/factories/FTReceiverBalanceFactory.cdc +16 -4
  54. package/contracts/hybrid-custody/factories/FTReceiverFactory.cdc +16 -4
  55. package/contracts/hybrid-custody/factories/FTVaultFactory.cdc +46 -0
  56. package/contracts/hybrid-custody/factories/NFTCollectionFactory.cdc +45 -0
  57. package/contracts/hybrid-custody/factories/NFTCollectionPublicFactory.cdc +16 -4
  58. package/contracts/hybrid-custody/factories/NFTProviderAndCollectionFactory.cdc +22 -0
  59. package/contracts/hybrid-custody/factories/NFTProviderFactory.cdc +16 -4
  60. package/contracts/lost-and-found/LostAndFound.cdc +21 -17
  61. package/contracts/tokens/USDCFlow.cdc +232 -0
  62. package/flow.json +278 -7
  63. package/package.json +1 -1
  64. package/contracts/hybrid-custody/factories/NFTProviderAndCollectionPublicFactory.cdc +0 -10
package/README.md CHANGED
@@ -49,7 +49,7 @@ Currently, the list includes:
49
49
  | FTProviderFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
50
50
  | FTReceiverFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
51
51
  | NFTCollectionPublicFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
52
- | NFTProviderAndCollectionPublicFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
52
+ | NFTProviderAndCollectionFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
53
53
  | NFTProviderFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
54
54
  | NFTCatalog | 0x49a7cda3a1eecc29 | 0x324c34e1c517e4db |
55
55
  | NFTCatalogAdmin | 0x49a7cda3a1eecc29 | 0x324c34e1c517e4db |
@@ -0,0 +1,360 @@
1
+ import "FungibleToken"
2
+
3
+ /// The contract that allows an account to receive payments in multiple fungible
4
+ /// tokens using a single `{FungibleToken.Receiver}` capability.
5
+ /// This capability should ideally be stored at the
6
+ /// `FungibleTokenSwitchboard.ReceiverPublicPath = /public/GenericFTReceiver`
7
+ /// but it can be stored anywhere.
8
+ ///
9
+ access(all) contract FungibleTokenSwitchboard {
10
+
11
+ // Storage and Public Paths
12
+ access(all) let StoragePath: StoragePath
13
+ access(all) let PublicPath: PublicPath
14
+ access(all) let ReceiverPublicPath: PublicPath
15
+
16
+ access(all) entitlement Owner
17
+
18
+ /// The event that is emitted when a new vault capability is added to a
19
+ /// switchboard resource.
20
+ ///
21
+ access(all) event VaultCapabilityAdded(type: Type, switchboardOwner: Address?,
22
+ capabilityOwner: Address?)
23
+
24
+ /// The event that is emitted when a vault capability is removed from a
25
+ /// switchboard resource.
26
+ ///
27
+ access(all) event VaultCapabilityRemoved(type: Type, switchboardOwner: Address?,
28
+ capabilityOwner: Address?)
29
+
30
+ /// The event that is emitted when a deposit can not be completed.
31
+ ///
32
+ access(all) event NotCompletedDeposit(type: Type, amount: UFix64,
33
+ switchboardOwner: Address?)
34
+
35
+ /// The interface that enforces the method to allow anyone to check on the
36
+ /// available capabilities of a switchboard resource and also exposes the
37
+ /// deposit methods to deposit funds on it.
38
+ ///
39
+ access(all) resource interface SwitchboardPublic {
40
+ access(all) view fun getVaultTypesWithAddress(): {Type: Address}
41
+ access(all) view fun getSupportedVaultTypes(): {Type: Bool}
42
+ access(all) view fun isSupportedVaultType(type: Type): Bool
43
+ access(all) fun deposit(from: @{FungibleToken.Vault})
44
+ access(all) fun safeDeposit(from: @{FungibleToken.Vault}): @{FungibleToken.Vault}?
45
+ access(all) view fun safeBorrowByType(type: Type): &{FungibleToken.Receiver}?
46
+ }
47
+
48
+ /// The resource that stores the multiple fungible token receiver
49
+ /// capabilities, allowing the owner to add and remove them and anyone to
50
+ /// deposit any fungible token among the available types.
51
+ ///
52
+ access(all) resource Switchboard: FungibleToken.Receiver, SwitchboardPublic {
53
+
54
+ /// Dictionary holding the fungible token receiver capabilities,
55
+ /// indexed by the fungible token vault type.
56
+ ///
57
+ access(contract) var receiverCapabilities: {Type: Capability<&{FungibleToken.Receiver}>}
58
+
59
+ /// Adds a new fungible token receiver capability to the switchboard
60
+ /// resource.
61
+ ///
62
+ /// @param capability: The capability to expose a certain fungible
63
+ /// token vault deposit function through `{FungibleToken.Receiver}` that
64
+ /// will be added to the switchboard.
65
+ ///
66
+ access(Owner) fun addNewVault(capability: Capability<&{FungibleToken.Receiver}>) {
67
+ // Borrow a reference to the vault pointed to by the capability we
68
+ // want to store inside the switchboard
69
+ let vaultRef = capability.borrow()
70
+ ?? panic ("Cannot borrow reference to vault from capability")
71
+ // Check if there is a previous capability for this token, if not
72
+ if (self.receiverCapabilities[vaultRef.getType()] == nil) {
73
+ // use the vault reference type as key for storing the
74
+ // capability and then
75
+ self.receiverCapabilities[vaultRef.getType()] = capability
76
+ // emit the event that indicates that a new capability has been
77
+ // added
78
+ emit VaultCapabilityAdded(type: vaultRef.getType(),
79
+ switchboardOwner: self.owner?.address,
80
+ capabilityOwner: capability.address)
81
+ } else {
82
+ // If there was already a capability for that token, panic
83
+ panic("There is already a vault in the Switchboard for this token")
84
+ }
85
+ }
86
+
87
+ /// Adds a number of new fungible token receiver capabilities by using
88
+ /// the paths where they are stored.
89
+ ///
90
+ /// @param paths: The paths where the public capabilities are stored.
91
+ /// @param address: The address of the owner of the capabilities.
92
+ ///
93
+ access(Owner) fun addNewVaultsByPath(paths: [PublicPath], address: Address) {
94
+ // Get the account where the public capabilities are stored
95
+ let owner = getAccount(address)
96
+ // For each path, get the saved capability and store it
97
+ // into the switchboard's receiver capabilities dictionary
98
+ for path in paths {
99
+ let capability = owner.capabilities.get<&{FungibleToken.Receiver}>(path)
100
+ // Borrow a reference to the vault pointed to by the capability
101
+ // we want to store inside the switchboard
102
+ // If the vault was borrowed successfully...
103
+ if let vaultRef = capability.borrow() {
104
+ // ...and if there is no previous capability added for that token
105
+ if (self.receiverCapabilities[vaultRef!.getType()] == nil) {
106
+ // Use the vault reference type as key for storing the
107
+ // capability
108
+ self.receiverCapabilities[vaultRef!.getType()] = capability
109
+ // and emit the event that indicates that a new
110
+ // capability has been added
111
+ emit VaultCapabilityAdded(type: vaultRef.getType(),
112
+ switchboardOwner: self.owner?.address,
113
+ capabilityOwner: address,
114
+ )
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ /// Adds a new fungible token receiver capability to the switchboard
121
+ /// resource specifying which `Type` of `@{FungibleToken.Vault}` can be
122
+ /// deposited to it. Use it to include in your switchboard "wrapper"
123
+ /// receivers such as a `@TokenForwarding.Forwarder`. It can also be
124
+ /// used to overwrite the type attached to a certain capability without
125
+ /// having to remove that capability first.
126
+ ///
127
+ /// @param capability: The capability to expose a certain fungible
128
+ /// token vault deposit function through `{FungibleToken.Receiver}` that
129
+ /// will be added to the switchboard.
130
+ ///
131
+ /// @param type: The type of fungible token that can be deposited to that
132
+ /// capability, rather than the `Type` from the reference borrowed from
133
+ /// said capability
134
+ ///
135
+ access(Owner) fun addNewVaultWrapper(capability: Capability<&{FungibleToken.Receiver}>,
136
+ type: Type) {
137
+ // Check if the capability is working
138
+ assert(capability.check(), message: "The passed capability is not valid")
139
+ // Use the type parameter as key for the capability
140
+ self.receiverCapabilities[type] = capability
141
+ // emit the event that indicates that a new capability has been
142
+ // added
143
+ emit VaultCapabilityAdded(
144
+ type: type,
145
+ switchboardOwner: self.owner?.address,
146
+ capabilityOwner: capability.address,
147
+ )
148
+ }
149
+
150
+ /// Adds zero or more new fungible token receiver capabilities to the
151
+ /// switchboard resource specifying which `Type`s of `@{FungibleToken.Vault}`s
152
+ /// can be deposited to it. Use it to include in your switchboard "wrapper"
153
+ /// receivers such as a `@TokenForwarding.Forwarder`. It can also be
154
+ /// used to overwrite the types attached to certain capabilities without
155
+ /// having to remove those capabilities first.
156
+ ///
157
+ /// @param paths: The paths where the public capabilities are stored.
158
+ /// @param types: The types of the fungible token to be deposited on each path.
159
+ /// @param address: The address of the owner of the capabilities.
160
+ ///
161
+ access(Owner) fun addNewVaultWrappersByPath(paths: [PublicPath], types: [Type],
162
+ address: Address) {
163
+ // Get the account where the public capabilities are stored
164
+ let owner = getAccount(address)
165
+ // For each path, get the saved capability and store it
166
+ // into the switchboard's receiver capabilities dictionary
167
+ for i, path in paths {
168
+ let capability = owner.capabilities.get<&{FungibleToken.Receiver}>(path)
169
+ // Borrow a reference to the vault pointed to by the capability
170
+ // we want to store inside the switchboard
171
+ // If the vault was borrowed successfully...
172
+ if let vaultRef = capability.borrow() {
173
+ // Use the vault reference type as key for storing the capability
174
+ self.receiverCapabilities[types[i]] = capability
175
+ // and emit the event that indicates that a new capability has been added
176
+ emit VaultCapabilityAdded(
177
+ type: types[i],
178
+ switchboardOwner: self.owner?.address,
179
+ capabilityOwner: address,
180
+ )
181
+ }
182
+ }
183
+ }
184
+
185
+ /// Removes a fungible token receiver capability from the switchboard
186
+ /// resource.
187
+ ///
188
+ /// @param capability: The capability to a fungible token vault to be
189
+ /// removed from the switchboard.
190
+ ///
191
+ access(Owner) fun removeVault(capability: Capability<&{FungibleToken.Receiver}>) {
192
+ // Borrow a reference to the vault pointed to by the capability we
193
+ // want to remove from the switchboard
194
+ let vaultRef = capability.borrow()
195
+ ?? panic ("Cannot borrow reference to vault from capability")
196
+ // Use the vault reference to find the capability to remove
197
+ self.receiverCapabilities.remove(key: vaultRef.getType())
198
+ // Emit the event that indicates that a new capability has been
199
+ // removed
200
+ emit VaultCapabilityRemoved(
201
+ type: vaultRef.getType(),
202
+ switchboardOwner: self.owner?.address,
203
+ capabilityOwner: capability.address,
204
+ )
205
+ }
206
+
207
+ /// Takes a fungible token vault and routes it to the proper fungible
208
+ /// token receiver capability for depositing it.
209
+ ///
210
+ /// @param from: The deposited fungible token vault resource.
211
+ ///
212
+ access(all) fun deposit(from: @{FungibleToken.Vault}) {
213
+ // Get the capability from the ones stored at the switchboard
214
+ let depositedVaultCapability = self.receiverCapabilities[from.getType()]
215
+ ?? panic ("The deposited vault is not available on this switchboard")
216
+
217
+ // Borrow the reference to the desired vault
218
+ let vaultRef = depositedVaultCapability.borrow()
219
+ ?? panic ("Can not borrow a reference to the the vault")
220
+
221
+ vaultRef.deposit(from: <-from)
222
+ }
223
+
224
+ /// Takes a fungible token vault and tries to route it to the proper
225
+ /// fungible token receiver capability for depositing the funds,
226
+ /// avoiding panicking if the vault is not available.
227
+ ///
228
+ /// @param vaultType: The type of the ft vault that wants to be
229
+ /// deposited.
230
+ ///
231
+ /// @return The deposited fungible token vault resource, without the
232
+ /// funds if the deposit was successful, or still containing the funds
233
+ /// if the reference to the needed vault was not found.
234
+ ///
235
+ access(all) fun safeDeposit(from: @{FungibleToken.Vault}): @{FungibleToken.Vault}? {
236
+ // Try to get the proper vault capability from the switchboard
237
+ // If the desired vault is present on the switchboard...
238
+ if let depositedVaultCapability = self.receiverCapabilities[from.getType()] {
239
+ // We try to borrow a reference to the vault from the capability
240
+ // If we can borrow a reference to the vault...
241
+ if let vaultRef = depositedVaultCapability.borrow() {
242
+ // We deposit the funds on said vault
243
+ vaultRef.deposit(from: <-from.withdraw(amount: from.balance))
244
+ }
245
+ }
246
+ // if deposit failed for some reason
247
+ if from.balance > 0.0 {
248
+ emit NotCompletedDeposit(
249
+ type: from.getType(),
250
+ amount: from.balance,
251
+ switchboardOwner: self.owner?.address,
252
+ )
253
+ return <-from
254
+ }
255
+ destroy from
256
+ return nil
257
+ }
258
+
259
+ /// Checks that the capability tied to a type is valid
260
+ ///
261
+ /// @param vaultType: The type of the ft vault whose capability needs to be checked
262
+ ///
263
+ /// @return a boolean marking the capability for a type as valid or not
264
+ access(all) view fun checkReceiverByType(type: Type): Bool {
265
+ if self.receiverCapabilities[type] == nil {
266
+ return false
267
+ }
268
+
269
+ return self.receiverCapabilities[type]!.check()
270
+ }
271
+
272
+ /// Gets the receiver assigned to a provided vault type.
273
+ /// This is necessary because without it, it is not possible to look under the hood and see if a capability
274
+ /// is of an expected type or not. This helps guard against infinitely chained TokenForwarding or other invalid
275
+ /// malicious kinds of updates that could prevent listings from being made that are valid on storefronts.
276
+ ///
277
+ /// @param vaultType: The type of the ft vault whose capability needs to be checked
278
+ ///
279
+ /// @return an optional receiver capability for consumers of the switchboard to check/validate on their own
280
+ access(all) view fun safeBorrowByType(type: Type): &{FungibleToken.Receiver}? {
281
+ if !self.checkReceiverByType(type: type) {
282
+ return nil
283
+ }
284
+
285
+ return self.receiverCapabilities[type]!.borrow()
286
+ }
287
+
288
+ /// A getter function to know which tokens a certain switchboard
289
+ /// resource is prepared to receive along with the address where
290
+ /// those tokens will be deposited.
291
+ ///
292
+ /// @return A dictionary mapping the `{FungibleToken.Receiver}`
293
+ /// type to the receiver owner's address
294
+ ///
295
+ access(all) view fun getVaultTypesWithAddress(): {Type: Address} {
296
+ let effectiveTypesWithAddress: {Type: Address} = {}
297
+ // Check if each capability is live
298
+ for vaultType in self.receiverCapabilities.keys {
299
+ if self.receiverCapabilities[vaultType]!.check() {
300
+ // and attach it to the owner's address
301
+ effectiveTypesWithAddress[vaultType] = self.receiverCapabilities[vaultType]!.address
302
+ }
303
+ }
304
+ return effectiveTypesWithAddress
305
+ }
306
+
307
+ /// A getter function that returns the token types supported by this resource,
308
+ /// which can be deposited using the 'deposit' function.
309
+ ///
310
+ /// @return Dictionary of FT types that can be deposited.
311
+ access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
312
+ let supportedVaults: {Type: Bool} = {}
313
+ for receiverType in self.receiverCapabilities.keys {
314
+ if self.receiverCapabilities[receiverType]!.check() {
315
+ if receiverType.isSubtype(of: Type<@{FungibleToken.Vault}>()) {
316
+ supportedVaults[receiverType] = true
317
+ }
318
+ if receiverType.isSubtype(of: Type<@{FungibleToken.Receiver}>()) {
319
+ let receiverRef = self.receiverCapabilities[receiverType]!.borrow()!
320
+ let subReceiverSupportedTypes = receiverRef.getSupportedVaultTypes()
321
+ for subReceiverType in subReceiverSupportedTypes.keys {
322
+ if subReceiverType.isSubtype(of: Type<@{FungibleToken.Vault}>()) {
323
+ supportedVaults[subReceiverType] = true
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+ return supportedVaults
330
+ }
331
+
332
+ /// Returns whether or not the given type is accepted by the Receiver
333
+ /// A vault that can accept any type should just return true by default
334
+ access(all) view fun isSupportedVaultType(type: Type): Bool {
335
+ let supportedVaults = self.getSupportedVaultTypes()
336
+ if let supported = supportedVaults[type] {
337
+ return supported
338
+ } else { return false }
339
+ }
340
+
341
+ init() {
342
+ // Initialize the capabilities dictionary
343
+ self.receiverCapabilities = {}
344
+ }
345
+
346
+ }
347
+
348
+ /// Function that allows to create a new blank switchboard. A user must call
349
+ /// this function and store the returned resource in their storage.
350
+ ///
351
+ access(all) fun createSwitchboard(): @Switchboard {
352
+ return <-create Switchboard()
353
+ }
354
+
355
+ init() {
356
+ self.StoragePath = /storage/fungibleTokenSwitchboard
357
+ self.PublicPath = /public/fungibleTokenSwitchboardPublic
358
+ self.ReceiverPublicPath = /public/GenericFTReceiver
359
+ }
360
+ }
@@ -126,8 +126,32 @@ access(all) contract MetadataViews {
126
126
  }
127
127
  }
128
128
 
129
- /// View to represent a file with an correspoiding mediaType.
130
- ///
129
+ /// A struct to represent a generic URI. May be used to represent the URI of
130
+ /// the NFT where the type of URI is not able to be determined (i.e. HTTP,
131
+ /// IPFS, etc.)
132
+ ///
133
+ access(all) struct URI: File {
134
+ /// The base URI prefix, if any. Not needed for all URIs, but helpful
135
+ /// for some use cases For example, updating a whole NFT collection's
136
+ /// image host easily
137
+ ///
138
+ access(all) let baseURI: String?
139
+ /// The URI string value
140
+ /// NOTE: this is set on init as a concatenation of the baseURI and the
141
+ /// value if baseURI != nil
142
+ ///
143
+ access(self) let value: String
144
+
145
+ access(all) view fun uri(): String {
146
+ return self.value
147
+ }
148
+
149
+ init(baseURI: String?, value: String) {
150
+ self.baseURI = baseURI
151
+ self.value = baseURI != nil ? baseURI!.concat(value) : value
152
+ }
153
+ }
154
+
131
155
  access(all) struct Media {
132
156
 
133
157
  /// File for the media
@@ -185,7 +209,7 @@ access(all) contract MetadataViews {
185
209
  /// Helper to get License in a typesafe way
186
210
  ///
187
211
  /// @param viewResolver: A reference to the resolver resource
188
- /// @return A optional License struct
212
+ /// @return An optional License struct
189
213
  ///
190
214
  access(all) fun getLicense(_ viewResolver: &{ViewResolver.Resolver}) : License? {
191
215
  if let view = viewResolver.resolveView(Type<License>()) {
@@ -212,7 +236,7 @@ access(all) contract MetadataViews {
212
236
  /// Helper to get ExternalURL in a typesafe way
213
237
  ///
214
238
  /// @param viewResolver: A reference to the resolver resource
215
- /// @return A optional ExternalURL struct
239
+ /// @return An optional ExternalURL struct
216
240
  ///
217
241
  access(all) fun getExternalURL(_ viewResolver: &{ViewResolver.Resolver}) : ExternalURL? {
218
242
  if let view = viewResolver.resolveView(Type<ExternalURL>()) {
@@ -665,7 +689,7 @@ access(all) contract MetadataViews {
665
689
  // Square-sized image to represent this collection.
666
690
  access(all) let squareImage: MetadataViews.Media
667
691
 
668
- // Banner-sized image for this collection, recommended to have a size near 1200x630.
692
+ // Banner-sized image for this collection, recommended to have a size near 1400x350.
669
693
  access(all) let bannerImage: MetadataViews.Media
670
694
 
671
695
  // Social links to reach this collection's social homepages.
@@ -703,4 +727,53 @@ access(all) contract MetadataViews {
703
727
  }
704
728
  return nil
705
729
  }
706
- }
730
+ /// This view may be used by Cadence-native projects to define their
731
+ /// contract- and token-level metadata according to EVM-compatible formats.
732
+ /// Several ERC standards (e.g. ERC20, ERC721, etc.) expose name and symbol
733
+ /// values to define assets as well as contract- & token-level metadata view
734
+ /// `tokenURI(uint256)` and `contractURI()` methods. This view enables
735
+ /// Cadence projects to define in their own contracts how they would like
736
+ /// their metadata to be defined when bridged to EVM.
737
+ ///
738
+ access(all) struct EVMBridgedMetadata {
739
+
740
+ /// The name of the asset
741
+ ///
742
+ access(all) let name: String
743
+
744
+ /// The symbol of the asset
745
+ ///
746
+ access(all) let symbol: String
747
+
748
+ /// The URI of the asset - this can either be contract-level or
749
+ /// token-level URI depending on where the metadata is resolved. It
750
+ /// is recommended to reference EVM metadata standards for how to best
751
+ /// prepare your view's formatted value.
752
+ ///
753
+ /// For example, while you may choose to take advantage of onchain
754
+ /// metadata, as is the case for most Cadence NFTs, you may also choose
755
+ /// to represent your asset's metadata in IPFS and assign this value as
756
+ /// an IPFSFile struct pointing to that IPFS file. Alternatively, you
757
+ /// may serialize your NFT's metadata and assign it as a JSON string
758
+ /// data URL representating the NFT's onchain metadata at the time this
759
+ /// view is resolved.
760
+ ///
761
+ access(all) let uri: {File}
762
+
763
+ init(name: String, symbol: String, uri: {File}) {
764
+ self.name = name
765
+ self.symbol = symbol
766
+ self.uri = uri
767
+ }
768
+ }
769
+
770
+ access(all) fun getEVMBridgedMetadata(_ viewResolver: &{ViewResolver.Resolver}) : EVMBridgedMetadata? {
771
+ if let view = viewResolver.resolveView(Type<EVMBridgedMetadata>()) {
772
+ if let v = view as? EVMBridgedMetadata {
773
+ return v
774
+ }
775
+ }
776
+ return nil
777
+ }
778
+
779
+ }
@@ -49,9 +49,6 @@ access(all) contract interface NonFungibleToken: ViewResolver {
49
49
  /// An entitlement for allowing updates and update events for an NFT
50
50
  access(all) entitlement Update
51
51
 
52
- /// entitlement for owner that grants Withdraw and Update
53
- access(all) entitlement Owner
54
-
55
52
  /// Event that contracts should emit when the metadata of an NFT is updated
56
53
  /// It can only be emitted by calling the `emitNFTUpdated` function
57
54
  /// with an `Updatable` entitled reference to the NFT that was updated
@@ -63,7 +60,7 @@ access(all) contract interface NonFungibleToken: ViewResolver {
63
60
  /// and query the updated metadata from the owners' collections.
64
61
  ///
65
62
  access(all) event Updated(type: String, id: UInt64, uuid: UInt64, owner: Address?)
66
- access(contract) view fun emitNFTUpdated(_ nftRef: auth(Update | Owner) &{NonFungibleToken.NFT})
63
+ access(all) view fun emitNFTUpdated(_ nftRef: auth(Update) &{NonFungibleToken.NFT})
67
64
  {
68
65
  emit Updated(type: nftRef.getType().identifier, id: nftRef.id, uuid: nftRef.uuid, owner: nftRef.owner?.address)
69
66
  }
@@ -85,9 +82,6 @@ access(all) contract interface NonFungibleToken: ViewResolver {
85
82
  ///
86
83
  access(all) event Deposited(type: String, id: UInt64, uuid: UInt64, to: Address?, collectionUUID: UInt64)
87
84
 
88
- /// Included for backwards-compatibility
89
- access(all) resource interface INFT: NFT {}
90
-
91
85
  /// Interface that the NFTs must conform to
92
86
  ///
93
87
  access(all) resource interface NFT: ViewResolver.Resolver {
@@ -105,6 +99,7 @@ access(all) contract interface NonFungibleToken: ViewResolver {
105
99
  access(all) fun createEmptyCollection(): @{Collection} {
106
100
  post {
107
101
  result.getLength() == 0: "The created collection must be empty!"
102
+ result.isSupportedNFTType(type: self.getType()): "The created collection must support this NFT type"
108
103
  }
109
104
  }
110
105
 
@@ -141,7 +136,7 @@ access(all) contract interface NonFungibleToken: ViewResolver {
141
136
  /// withdraw removes an NFT from the collection and moves it to the caller
142
137
  /// It does not specify whether the ID is UUID or not
143
138
  /// @param withdrawID: The id of the NFT to withdraw from the collection
144
- access(Withdraw | Owner) fun withdraw(withdrawID: UInt64): @{NFT} {
139
+ access(Withdraw) fun withdraw(withdrawID: UInt64): @{NFT} {
145
140
  post {
146
141
  result.id == withdrawID: "The ID of the withdrawn token must be the same as the requested ID"
147
142
  emit Withdrawn(type: result.getType().identifier, id: result.id, uuid: result.uuid, from: self.owner?.address, providerUUID: self.uuid)
@@ -174,6 +169,7 @@ access(all) contract interface NonFungibleToken: ViewResolver {
174
169
  access(all) fun deposit(token: @{NFT})
175
170
  access(all) view fun getLength(): Int
176
171
  access(all) view fun getIDs(): [UInt64]
172
+ access(all) fun forEachID(_ f: fun (UInt64): Bool): Void
177
173
  access(all) view fun borrowNFT(_ id: UInt64): &{NFT}?
178
174
  }
179
175
 
@@ -182,6 +178,8 @@ access(all) contract interface NonFungibleToken: ViewResolver {
182
178
  ///
183
179
  access(all) resource interface Collection: Provider, Receiver, CollectionPublic, ViewResolver.ResolverCollection {
184
180
 
181
+ access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
182
+
185
183
  /// deposit takes a NFT as an argument and stores it in the collection
186
184
  /// @param token: The NFT to deposit into the collection
187
185
  access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
@@ -196,7 +194,16 @@ access(all) contract interface NonFungibleToken: ViewResolver {
196
194
 
197
195
  /// Gets the amount of NFTs stored in the collection
198
196
  /// @return An integer indicating the size of the collection
199
- access(all) view fun getLength(): Int
197
+ access(all) view fun getLength(): Int {
198
+ return self.ownedNFTs.length
199
+ }
200
+
201
+ /// Allows a given function to iterate through the list
202
+ /// of owned NFT IDs in a collection without first
203
+ /// having to load the entire list into memory
204
+ access(all) fun forEachID(_ f: fun (UInt64): Bool): Void {
205
+ self.ownedNFTs.forEachKey(f)
206
+ }
200
207
 
201
208
  /// Borrows a reference to an NFT stored in the collection
202
209
  /// If the NFT with the specified ID is not in the collection,
@@ -231,4 +238,4 @@ access(all) contract interface NonFungibleToken: ViewResolver {
231
238
  result.getIDs().length == 0: "The created collection must be empty!"
232
239
  }
233
240
  }
234
- }
241
+ }
@@ -0,0 +1,97 @@
1
+ /*
2
+ https://github.com/Flowtyio/capability-cache
3
+
4
+ CapabilityCache helps manage capabilities which are issued but are not in public paths.
5
+ Rather than looping through all capabilities under a storage path and finding one that
6
+ matches the Capability type you want, the cache can be used to retrieve them
7
+ */
8
+ access(all) contract CapabilityCache {
9
+
10
+ access(all) let basePathIdentifier: String
11
+
12
+ access(all) event CapabilityAdded(owner: Address?, cacheUuid: UInt64, namespace: String, resourceType: Type, capabilityType: Type, capabilityID: UInt64)
13
+ access(all) event CapabilityRemoved(owner: Address?, cacheUuid: UInt64, namespace: String, resourceType: Type, capabilityType: Type, capabilityID: UInt64)
14
+
15
+ // Add to a namespace
16
+ access(all) entitlement Add
17
+
18
+ // Remove from a namespace
19
+ access(all) entitlement Delete
20
+
21
+ // Retrieve a cap from the namespace
22
+ access(all) entitlement Get
23
+
24
+ // Resource that manages capabilities for a provided namespace. Only one capability is permitted per type.
25
+ access(all) resource Cache {
26
+ // A dictionary of resourceType -> CapabilityType -> Capability
27
+ // For example, one might store a Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}> for the @TopShot.NFT resource.
28
+ // Note that the resource type is not necessarily the type that the borrowed capability is an instance of. This is because some resource definitions
29
+ // might be reused.
30
+ access(self) let caps: {Type: {Type: Capability}}
31
+
32
+ // who is this capability cache maintained by? e.g. flowty, dapper, find?
33
+ access(all) let namespace: String
34
+
35
+ // Remove a capability, if it exists,
36
+ access(Delete) fun removeCapabilityByType(resourceType: Type, capabilityType: Type): Capability? {
37
+ if let ref = &self.caps[resourceType] as auth(Mutate) &{Type: Capability}? {
38
+ let cap = ref.remove(key: capabilityType)
39
+ if cap != nil {
40
+ emit CapabilityRemoved(owner: self.owner?.address, cacheUuid: self.uuid, namespace: self.namespace, resourceType: resourceType, capabilityType: capabilityType, capabilityID: cap!.id)
41
+ }
42
+ }
43
+
44
+ return nil
45
+ }
46
+
47
+ // Adds a capability to the cache. If there is already an entry for the given type,
48
+ // it will be returned
49
+ access(Add) fun addCapability(resourceType: Type, cap: Capability): Capability? {
50
+ pre {
51
+ cap.id != 0: "cannot add a capability with id 0"
52
+ }
53
+
54
+ let capType = cap.getType()
55
+ emit CapabilityAdded(owner: self.owner?.address, cacheUuid: self.uuid, namespace: self.namespace, resourceType: resourceType, capabilityType: capType, capabilityID: cap.id)
56
+ if let ref = &self.caps[resourceType] as auth(Mutate) &{Type: Capability}? {
57
+ return ref.insert(key: capType, cap)
58
+ }
59
+
60
+ self.caps[resourceType] = {
61
+ capType: cap
62
+ }
63
+
64
+ return nil
65
+ }
66
+
67
+ // Retrieve a capability key'd by a given type.
68
+ access(Get) fun getCapabilityByType(resourceType: Type, capabilityType: Type): Capability? {
69
+ if let tmp = self.caps[resourceType] {
70
+ return tmp[capabilityType]
71
+ }
72
+
73
+ return nil
74
+ }
75
+
76
+ init(namespace: String) {
77
+ self.caps = {}
78
+
79
+ self.namespace = namespace
80
+ }
81
+ }
82
+
83
+ // There is no uniform storage path for the Capability Cache. Instead, each platform which issues capabilities
84
+ // should manage their own cache, and can generate the storage path to store it in with this helper method
85
+ access(all) fun getPathForCache(_ namespace: String): StoragePath {
86
+ return StoragePath(identifier: self.basePathIdentifier.concat(namespace))
87
+ ?? panic("invalid namespace value")
88
+ }
89
+
90
+ access(all) fun createCache(namespace: String): @Cache {
91
+ return <- create Cache(namespace: namespace)
92
+ }
93
+
94
+ init() {
95
+ self.basePathIdentifier = "CapabilityCache_".concat(self.account.address.toString()).concat("_")
96
+ }
97
+ }