@flowtyio/flow-contracts 0.0.18 → 0.1.0-beta.10

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.
@@ -2,20 +2,17 @@
2
2
 
3
3
  ## The Flow Non-Fungible Token standard
4
4
 
5
- ## `NonFungibleToken` contract interface
5
+ ## `NonFungibleToken` contract
6
6
 
7
- The interface that all Non-Fungible Token contracts could conform to.
8
- If a user wants to deploy a new NFT contract, their contract would need
9
- to implement the NonFungibleToken interface.
7
+ The interface that all Non-Fungible Token contracts should conform to.
8
+ If a user wants to deploy a new NFT contract, their contract should implement
9
+ The types defined here
10
10
 
11
- Their contract would have to follow all the rules and naming
12
- that the interface specifies.
13
-
14
- ## `NFT` resource
11
+ ## `NFT` resource interface
15
12
 
16
13
  The core resource type that represents an NFT in the smart contract.
17
14
 
18
- ## `Collection` Resource
15
+ ## `Collection` Resource interface
19
16
 
20
17
  The resource that stores a user's NFT collection.
21
18
  It includes a few functions to allow the owner to easily
@@ -26,10 +23,8 @@ move tokens in and out of the collection.
26
23
  These interfaces declare functions with some pre and post conditions
27
24
  that require the Collection to follow certain naming and behavior standards.
28
25
 
29
- They are separate because it gives the user the ability to share a reference
30
- to their Collection that only exposes the fields and functions in one or more
31
- of the interfaces. It also gives users the ability to make custom resources
32
- that implement these interfaces to do various things with the tokens.
26
+ They are separate because it gives developers the ability to define functions
27
+ that can use any type that implements these interfaces
33
28
 
34
29
  By using resources and interfaces, users of NFT smart contracts can send
35
30
  and receive tokens peer-to-peer, without having to interact with a central ledger
@@ -41,162 +36,199 @@ Collection to complete the transfer.
41
36
 
42
37
  */
43
38
 
44
- /// The main NFT contract interface. Other NFT contracts will
45
- /// import and implement this interface
39
+ import "ViewResolver"
40
+
41
+ /// The main NFT contract. Other NFT contracts will
42
+ /// import and implement the interfaces defined in this contract
46
43
  ///
47
- pub contract interface NonFungibleToken {
44
+ access(all) contract interface NonFungibleToken: ViewResolver {
45
+
46
+ /// An entitlement for allowing the withdrawal of tokens from a Vault
47
+ access(all) entitlement Withdraw
48
+
49
+ /// An entitlement for allowing updates and update events for an NFT
50
+ access(all) entitlement Update
48
51
 
49
- /// The total number of tokens of this type in existence
50
- pub var totalSupply: UInt64
52
+ /// entitlement for owner that grants Withdraw and Update
53
+ access(all) entitlement Owner
51
54
 
52
- /// Event that emitted when the NFT contract is initialized
55
+ /// Event that contracts should emit when the metadata of an NFT is updated
56
+ /// It can only be emitted by calling the `emitNFTUpdated` function
57
+ /// with an `Updatable` entitled reference to the NFT that was updated
58
+ /// The entitlement prevents spammers from calling this from other users' collections
59
+ /// because only code within a collection or that has special entitled access
60
+ /// to the collections methods will be able to get the entitled reference
61
+ ///
62
+ /// The event makes it so that third-party indexers can monitor the events
63
+ /// and query the updated metadata from the owners' collections.
53
64
  ///
54
- pub event ContractInitialized()
65
+ access(all) event Updated(type: String, id: UInt64, uuid: UInt64, owner: Address?)
66
+ access(contract) view fun emitNFTUpdated(_ nftRef: auth(Update | Owner) &{NonFungibleToken.NFT})
67
+ {
68
+ emit Updated(type: nftRef.getType().identifier, id: nftRef.id, uuid: nftRef.uuid, owner: nftRef.owner?.address)
69
+ }
70
+
55
71
 
56
72
  /// Event that is emitted when a token is withdrawn,
57
- /// indicating the owner of the collection that it was withdrawn from.
73
+ /// indicating the type, id, uuid, the owner of the collection that it was withdrawn from,
74
+ /// and the UUID of the resource it was withdrawn from, usually a collection.
58
75
  ///
59
76
  /// If the collection is not in an account's storage, `from` will be `nil`.
60
77
  ///
61
- pub event Withdraw(id: UInt64, from: Address?)
78
+ access(all) event Withdrawn(type: String, id: UInt64, uuid: UInt64, from: Address?, providerUUID: UInt64)
62
79
 
63
80
  /// Event that emitted when a token is deposited to a collection.
81
+ /// Indicates the type, id, uuid, the owner of the collection that it was deposited to,
82
+ /// and the UUID of the collection it was deposited to
64
83
  ///
65
- /// It indicates the owner of the collection that it was deposited to.
84
+ /// If the collection is not in an account's storage, `from`, will be `nil`.
66
85
  ///
67
- pub event Deposit(id: UInt64, to: Address?)
86
+ access(all) event Deposited(type: String, id: UInt64, uuid: UInt64, to: Address?, collectionUUID: UInt64)
68
87
 
69
- /// Interface that the NFTs have to conform to
70
- /// The metadata views methods are included here temporarily
71
- /// because enforcing the metadata interfaces in the standard
72
- /// would break many contracts in an upgrade. Those breaking changes
73
- /// are being saved for the stable cadence milestone
88
+ /// Included for backwards-compatibility
89
+ access(all) resource interface INFT: NFT {}
90
+
91
+ /// Interface that the NFTs must conform to
74
92
  ///
75
- pub resource interface INFT {
76
- /// The unique ID that each NFT has
77
- pub let id: UInt64
93
+ access(all) resource interface NFT: ViewResolver.Resolver {
78
94
 
79
- /// Function that returns all the Metadata Views implemented by a Non Fungible Token
80
- ///
81
- /// @return An array of Types defining the implemented views. This value will be used by
82
- /// developers to know which parameter to pass to the resolveView() method.
83
- ///
84
- pub fun getViews(): [Type] {
85
- return []
95
+ /// unique ID for the NFT
96
+ access(all) let id: UInt64
97
+
98
+ /// Event that is emitted automatically every time a resource is destroyed
99
+ /// The type information is included in the metadata event so it is not needed as an argument
100
+ access(all) event ResourceDestroyed(id: UInt64 = self.id, uuid: UInt64 = self.uuid)
101
+
102
+ /// createEmptyCollection creates an empty Collection that is able to store the NFT
103
+ /// and returns it to the caller so that they can own NFTs
104
+ /// @return A an empty collection that can store this NFT
105
+ access(all) fun createEmptyCollection(): @{Collection} {
106
+ post {
107
+ result.getLength() == 0: "The created collection must be empty!"
108
+ }
109
+ }
110
+
111
+ /// Gets all the NFTs that this NFT directly owns
112
+ /// @return A dictionary of all subNFTS keyed by type
113
+ access(all) view fun getAvailableSubNFTS(): {Type: UInt64} {
114
+ return {}
86
115
  }
87
116
 
88
- /// Function that resolves a metadata view for this token.
117
+ /// Get a reference to an NFT that this NFT owns
118
+ /// Both arguments are optional to allow the NFT to choose
119
+ /// how it returns sub NFTs depending on what arguments are provided
120
+ /// For example, if `type` has a value, but `id` doesn't, the NFT
121
+ /// can choose which NFT of that type to return if there is a "default"
122
+ /// If both are `nil`, then NFTs that only store a single NFT can just return
123
+ /// that. This helps callers who aren't sure what they are looking for
89
124
  ///
90
- /// @param view: The Type of the desired view.
91
- /// @return A structure representing the requested view.
125
+ /// @param type: The Type of the desired NFT
126
+ /// @param id: The id of the NFT to borrow
92
127
  ///
93
- pub fun resolveView(_ view: Type): AnyStruct? {
128
+ /// @return A structure representing the requested view.
129
+ access(all) fun getSubNFT(type: Type, id: UInt64) : &{NonFungibleToken.NFT}? {
94
130
  return nil
95
131
  }
96
132
  }
97
133
 
98
- /// Requirement that all conforming NFT smart contracts have
99
- /// to define a resource called NFT that conforms to INFT
134
+ /// Interface to mediate withdrawals from a resource, usually a Collection
100
135
  ///
101
- pub resource NFT: INFT {
102
- pub let id: UInt64
103
- }
136
+ access(all) resource interface Provider {
104
137
 
105
- /// Interface to mediate withdraws from the Collection
106
- ///
107
- pub resource interface Provider {
108
- /// Removes an NFT from the resource implementing it and moves it to the caller
109
- ///
110
- /// @param withdrawID: The ID of the NFT that will be removed
111
- /// @return The NFT resource removed from the implementing resource
112
- ///
113
- pub fun withdraw(withdrawID: UInt64): @NFT {
138
+ // We emit withdraw events from the provider interface because conficting withdraw
139
+ // events aren't as confusing to event listeners as conflicting deposit events
140
+
141
+ /// withdraw removes an NFT from the collection and moves it to the caller
142
+ /// It does not specify whether the ID is UUID or not
143
+ /// @param withdrawID: The id of the NFT to withdraw from the collection
144
+ access(Withdraw | Owner) fun withdraw(withdrawID: UInt64): @{NFT} {
114
145
  post {
115
146
  result.id == withdrawID: "The ID of the withdrawn token must be the same as the requested ID"
147
+ emit Withdrawn(type: result.getType().identifier, id: result.id, uuid: result.uuid, from: self.owner?.address, providerUUID: self.uuid)
116
148
  }
117
149
  }
118
150
  }
119
151
 
120
152
  /// Interface to mediate deposits to the Collection
121
153
  ///
122
- pub resource interface Receiver {
123
-
124
- /// Adds an NFT to the resource implementing it
125
- ///
126
- /// @param token: The NFT resource that will be deposited
127
- ///
128
- pub fun deposit(token: @NFT)
154
+ access(all) resource interface Receiver {
155
+
156
+ /// deposit takes an NFT as an argument and adds it to the Collection
157
+ /// @param token: The NFT to deposit
158
+ access(all) fun deposit(token: @{NFT})
159
+
160
+ /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
161
+ /// @return A dictionary of types mapped to booleans indicating if this
162
+ /// reciever supports it
163
+ access(all) view fun getSupportedNFTTypes(): {Type: Bool}
164
+
165
+ /// Returns whether or not the given type is accepted by the collection
166
+ /// A collection that can accept any type should just return true by default
167
+ /// @param type: An NFT type
168
+ /// @return A boolean indicating if this receiver can recieve the desired NFT type
169
+ access(all) view fun isSupportedNFTType(type: Type): Bool
129
170
  }
130
171
 
131
- /// Interface that an account would commonly
132
- /// publish for their collection
133
- ///
134
- pub resource interface CollectionPublic {
135
- pub fun deposit(token: @NFT)
136
- pub fun getIDs(): [UInt64]
137
- pub fun borrowNFT(id: UInt64): &NFT
138
- /// Safe way to borrow a reference to an NFT that does not panic
139
- ///
140
- /// @param id: The ID of the NFT that want to be borrowed
141
- /// @return An optional reference to the desired NFT, will be nil if the passed id does not exist
142
- ///
143
- pub fun borrowNFTSafe(id: UInt64): &NFT? {
144
- post {
145
- result == nil || result!.id == id: "The returned reference's ID does not match the requested ID"
146
- }
147
- return nil
148
- }
172
+ /// Kept for backwards-compatibility reasons
173
+ access(all) resource interface CollectionPublic {
174
+ access(all) fun deposit(token: @{NFT})
175
+ access(all) view fun getLength(): Int
176
+ access(all) view fun getIDs(): [UInt64]
177
+ access(all) view fun borrowNFT(_ id: UInt64): &{NFT}?
149
178
  }
150
179
 
151
180
  /// Requirement for the concrete resource type
152
181
  /// to be declared in the implementing contract
153
182
  ///
154
- pub resource Collection: Provider, Receiver, CollectionPublic {
155
-
156
- /// Dictionary to hold the NFTs in the Collection
157
- pub var ownedNFTs: @{UInt64: NFT}
183
+ access(all) resource interface Collection: Provider, Receiver, CollectionPublic, ViewResolver.ResolverCollection {
158
184
 
159
- /// Removes an NFT from the collection and moves it to the caller
160
- ///
161
- /// @param withdrawID: The ID of the NFT that will be withdrawn
162
- /// @return The resource containing the desired NFT
163
- ///
164
- pub fun withdraw(withdrawID: UInt64): @NFT
185
+ /// deposit takes a NFT as an argument and stores it in the collection
186
+ /// @param token: The NFT to deposit into the collection
187
+ access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
188
+ pre {
189
+ // We emit the deposit event in the `Collection` interface
190
+ // because the `Collection` interface is almost always the final destination
191
+ // of tokens and deposit emissions from custom receivers could be confusing
192
+ // and hard to reconcile to event listeners
193
+ emit Deposited(type: token.getType().identifier, id: token.id, uuid: token.uuid, to: self.owner?.address, collectionUUID: self.uuid)
194
+ }
195
+ }
165
196
 
166
- /// Takes a NFT and adds it to the collections dictionary
167
- /// and adds the ID to the ID array
168
- ///
169
- /// @param token: An NFT resource
170
- ///
171
- pub fun deposit(token: @NFT)
197
+ /// Gets the amount of NFTs stored in the collection
198
+ /// @return An integer indicating the size of the collection
199
+ access(all) view fun getLength(): Int
172
200
 
173
- /// Returns an array of the IDs that are in the collection
174
- ///
175
- /// @return An array containing all the IDs on the collection
201
+ /// Borrows a reference to an NFT stored in the collection
202
+ /// If the NFT with the specified ID is not in the collection,
203
+ /// the function should return `nil` and not panic.
176
204
  ///
177
- pub fun getIDs(): [UInt64]
205
+ /// @param id: The desired nft id in the collection to return a referece for.
206
+ /// @return An optional reference to the NFT
207
+ access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
208
+ post {
209
+ (result == nil) || (result?.id == id):
210
+ "Cannot borrow NFT reference: The ID of the returned reference does not match the ID that was specified"
211
+ }
212
+ }
178
213
 
179
- /// Returns a borrowed reference to an NFT in the collection
180
- /// so that the caller can read data and call methods from it
181
- ///
182
- /// @param id: The ID of the NFT that want to be borrowed
183
- /// @return A reference to the NFT
184
- ///
185
- pub fun borrowNFT(id: UInt64): &NFT {
186
- pre {
187
- self.ownedNFTs[id] != nil: "NFT does not exist in the collection!"
214
+ /// createEmptyCollection creates an empty Collection of the same type
215
+ /// and returns it to the caller
216
+ /// @return A an empty collection of the same type
217
+ access(all) fun createEmptyCollection(): @{Collection} {
218
+ post {
219
+ result.getType() == self.getType(): "The created collection does not have the same type as this collection"
220
+ result.getLength() == 0: "The created collection must be empty!"
188
221
  }
189
222
  }
190
223
  }
191
224
 
192
- /// Creates an empty Collection and returns it to the caller so that they can own NFTs
193
- ///
194
- /// @return A new Collection resource
195
- ///
196
- pub fun createEmptyCollection(): @Collection {
225
+ /// createEmptyCollection creates an empty Collection for the specified NFT type
226
+ /// and returns it to the caller so that they can own NFTs
227
+ /// @param nftType: The desired nft type to return a collection for.
228
+ /// @return An array of NFT Types that the implementing contract defines.
229
+ access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
197
230
  post {
198
231
  result.getIDs().length == 0: "The created collection must be empty!"
199
232
  }
200
233
  }
201
234
  }
202
-
@@ -16,29 +16,37 @@ their tokens to.
16
16
 
17
17
  import "FungibleToken"
18
18
 
19
- pub contract TokenForwarding {
19
+ access(all) contract TokenForwarding {
20
20
 
21
21
  // Event that is emitted when tokens are deposited to the target receiver
22
- pub event ForwardedDeposit(amount: UFix64, from: Address?)
22
+ access(all) event ForwardedDeposit(amount: UFix64, from: Address?)
23
23
 
24
- pub resource interface ForwarderPublic {
25
- pub fun check(): Bool
26
- pub fun safeBorrow(): &{FungibleToken.Receiver}?
24
+ access(all) resource interface ForwarderPublic {
25
+ access(all) fun check(): Bool
26
+ access(all) fun safeBorrow(): &{FungibleToken.Receiver}?
27
27
  }
28
28
 
29
- pub resource Forwarder: FungibleToken.Receiver, ForwarderPublic {
29
+ access(all) resource Forwarder: FungibleToken.Receiver, ForwarderPublic {
30
30
 
31
31
  // This is where the deposited tokens will be sent.
32
32
  // The type indicates that it is a reference to a receiver
33
33
  //
34
34
  access(self) var recipient: Capability
35
35
 
36
+ access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
37
+ return {}
38
+ }
39
+
40
+ access(all) view fun isSupportedVaultType(type: Type): Bool {
41
+ return true
42
+ }
43
+
36
44
  // deposit
37
45
  //
38
46
  // Function that takes a Vault object as an argument and forwards
39
47
  // it to the recipient's Vault using the stored reference
40
48
  //
41
- pub fun deposit(from: @FungibleToken.Vault) {
49
+ access(all) fun deposit(from: @{FungibleToken.Vault}) {
42
50
  let receiverRef = self.recipient.borrow<&{FungibleToken.Receiver}>()!
43
51
 
44
52
  let balance = from.balance
@@ -48,17 +56,17 @@ pub contract TokenForwarding {
48
56
  emit ForwardedDeposit(amount: balance, from: self.owner?.address)
49
57
  }
50
58
 
51
- pub fun check(): Bool {
59
+ access(all) fun check(): Bool {
52
60
  return self.recipient.check<&{FungibleToken.Receiver}>()
53
61
  }
54
62
 
55
- pub fun safeBorrow(): &{FungibleToken.Receiver}? {
63
+ access(all) fun safeBorrow(): &{FungibleToken.Receiver}? {
56
64
  return self.recipient.borrow<&{FungibleToken.Receiver}>()
57
65
  }
58
66
 
59
67
  // changeRecipient changes the recipient of the forwarder to the provided recipient
60
68
  //
61
- pub fun changeRecipient(_ newRecipient: Capability) {
69
+ access(all) fun changeRecipient(_ newRecipient: Capability) {
62
70
  pre {
63
71
  newRecipient.borrow<&{FungibleToken.Receiver}>() != nil: "Could not borrow Receiver reference from the Capability"
64
72
  }
@@ -75,7 +83,7 @@ pub contract TokenForwarding {
75
83
 
76
84
  // createNewForwarder creates a new Forwarder reference with the provided recipient
77
85
  //
78
- pub fun createNewForwarder(recipient: Capability): @Forwarder {
86
+ access(all) fun createNewForwarder(recipient: Capability): @Forwarder {
79
87
  return <-create Forwarder(recipient: recipient)
80
88
  }
81
89
  }
@@ -3,23 +3,56 @@
3
3
  //
4
4
  // This will allow you to obtain information about a contract without necessarily knowing anything about it.
5
5
  // All you need is its address and name and you're good to go!
6
- pub contract interface ViewResolver {
7
- /// Function that returns all the Metadata Views implemented by the resolving contract
6
+ access(all) contract interface ViewResolver {
7
+
8
+ /// Function that returns all the Metadata Views implemented by the resolving contract.
9
+ /// Some contracts may have multiple resource types that support metadata views
10
+ /// so there there is an optional parameter for specify which resource type the caller
11
+ /// is looking for views for.
12
+ /// Some contract-level views may be type-agnostic. In that case, the contract
13
+ /// should return the same views regardless of what type is passed in.
8
14
  ///
15
+ /// @param resourceType: An optional resource type to return views for
9
16
  /// @return An array of Types defining the implemented views. This value will be used by
10
17
  /// developers to know which parameter to pass to the resolveView() method.
11
18
  ///
12
- pub fun getViews(): [Type] {
13
- return []
14
- }
19
+ access(all) view fun getContractViews(resourceType: Type?): [Type]
15
20
 
16
21
  /// Function that resolves a metadata view for this token.
22
+ /// Some contracts may have multiple resource types that support metadata views
23
+ /// so there there is an optional parameter for specify which resource type the caller
24
+ /// is looking for views for.
25
+ /// Some contract-level views may be type-agnostic. In that case, the contract
26
+ /// should return the same views regardless of what type is passed in.
17
27
  ///
28
+ /// @param resourceType: An optional resource type to return views for
18
29
  /// @param view: The Type of the desired view.
19
30
  /// @return A structure representing the requested view.
20
31
  ///
21
- pub fun resolveView(_ view: Type): AnyStruct? {
22
- return nil
32
+ access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct?
33
+
34
+ /// Provides access to a set of metadata views. A struct or
35
+ /// resource (e.g. an NFT) can implement this interface to provide access to
36
+ /// the views that it supports.
37
+ ///
38
+ access(all) resource interface Resolver {
39
+
40
+ /// Same as getViews above, but on a specific NFT instead of a contract
41
+ access(all) view fun getViews(): [Type]
42
+
43
+ /// Same as resolveView above, but on a specific NFT instead of a contract
44
+ access(all) fun resolveView(_ view: Type): AnyStruct?
45
+ }
46
+
47
+ /// A group of view resolvers indexed by ID.
48
+ ///
49
+ access(all) resource interface ResolverCollection {
50
+ access(all) view fun borrowViewResolver(id: UInt64): &{Resolver}? {
51
+ return nil
52
+ }
53
+
54
+ access(all) view fun getIDs(): [UInt64] {
55
+ return []
56
+ }
23
57
  }
24
58
  }
25
-