@flowtyio/flow-contracts 0.0.9 → 0.0.11

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.
package/README.md CHANGED
@@ -40,17 +40,17 @@ Currently, the list includes:
40
40
  | NonFungibleToken | 0x1d7e57aa55817448 | 0x631e88ae7f1d7c20 |
41
41
  | MetadataViews | 0x1d7e57aa55817448 | 0x631e88ae7f1d7c20 |
42
42
  | ViewResolver | 0x1d7e57aa55817448 | 0x631e88ae7f1d7c20 |
43
- | HybridCusody | 0x294e44e1ec6993c6 | N/A |
44
- | CapabilityFactory | 0x294e44e1ec6993c6 | N/A |
45
- | CapabilityFilter | 0x294e44e1ec6993c6 | N/A |
46
- | CapabilityDelegator | 0x294e44e1ec6993c6 | N/A |
47
- | FTAllFactory | 0x294e44e1ec6993c6 | N/A |
48
- | FTBalanceFactory | 0x294e44e1ec6993c6 | N/A |
49
- | FTProviderFactory | 0x294e44e1ec6993c6 | N/A |
50
- | FTReceiverFactory | 0x294e44e1ec6993c6 | N/A |
51
- | NFTCollectionPublicFactory | 0x294e44e1ec6993c6 | N/A |
52
- | NFTProviderAndCollectionPublicFactory | 0x294e44e1ec6993c6 | N/A |
53
- | NFTProviderFactory | 0x294e44e1ec6993c6 | N/A |
43
+ | HybridCusody | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
44
+ | CapabilityFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
45
+ | CapabilityFilter | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
46
+ | CapabilityDelegator | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
47
+ | FTAllFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
48
+ | FTBalanceFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
49
+ | FTProviderFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
50
+ | FTReceiverFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
51
+ | NFTCollectionPublicFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
52
+ | NFTProviderAndCollectionPublicFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
53
+ | NFTProviderFactory | 0x294e44e1ec6993c6 | 0xd8a7e05a7ac670c0 |
54
54
 
55
55
 
56
56
  ## Using a contract
@@ -0,0 +1,174 @@
1
+ /// CapabilityDelegator is a contract used to share Capabiltities to other accounts. It is used by the
2
+ /// HybridCustody contract to allow more flexible sharing of Capabilities when an app wants to share things
3
+ /// that aren't the NFT-standard interface types.
4
+ ///
5
+ /// Inside of CapabilityDelegator is a resource called `Delegator` which maintains a mapping of public and private
6
+ /// Capabilities. They cannot and should not be mixed. A public `Delegator` is able to be borrowed by anyone, whereas a
7
+ /// private `Delegator` can only be borrowed from the child account when you have access to the full `ChildAccount`
8
+ /// resource.
9
+ ///
10
+ pub contract CapabilityDelegator {
11
+
12
+ /* --- Canonical Paths --- */
13
+ //
14
+ pub let StoragePath: StoragePath
15
+ pub let PrivatePath: PrivatePath
16
+ pub let PublicPath: PublicPath
17
+
18
+ /* --- Events --- */
19
+ //
20
+ pub event DelegatorCreated(id: UInt64)
21
+ pub event DelegatorUpdated(id: UInt64, capabilityType: Type, isPublic: Bool, active: Bool)
22
+
23
+ /// Private interface for Capability retrieval
24
+ ///
25
+ pub resource interface GetterPrivate {
26
+ pub fun getPrivateCapability(_ type: Type): Capability? {
27
+ post {
28
+ result == nil || type.isSubtype(of: result.getType()): "incorrect returned capability type"
29
+ }
30
+ }
31
+ pub fun findFirstPrivateType(_ type: Type): Type?
32
+ pub fun getAllPrivate(): [Capability]
33
+ }
34
+
35
+ /// Exposes public Capability retrieval
36
+ ///
37
+ pub resource interface GetterPublic {
38
+ pub fun getPublicCapability(_ type: Type): Capability? {
39
+ post {
40
+ result == nil || type.isSubtype(of: result.getType()): "incorrect returned capability type "
41
+ }
42
+ }
43
+
44
+ pub fun findFirstPublicType(_ type: Type): Type?
45
+ pub fun getAllPublic(): [Capability]
46
+ }
47
+
48
+ /// This Delegator is used to store Capabilities, partitioned by public and private access with corresponding
49
+ /// GetterPublic and GetterPrivate conformances.AccountCapabilityController
50
+ ///
51
+ pub resource Delegator: GetterPublic, GetterPrivate {
52
+ access(self) let privateCapabilities: {Type: Capability}
53
+ access(self) let publicCapabilities: {Type: Capability}
54
+
55
+ // ------ Begin Getter methods
56
+ //
57
+ /// Returns the public Capability of the given Type if it exists
58
+ ///
59
+ pub fun getPublicCapability(_ type: Type): Capability? {
60
+ return self.publicCapabilities[type]
61
+ }
62
+
63
+ /// Returns the private Capability of the given Type if it exists
64
+ ///
65
+ ///
66
+ /// @param type: Type of the Capability to retrieve
67
+ /// @return Capability of the given Type if it exists, nil otherwise
68
+ ///
69
+ pub fun getPrivateCapability(_ type: Type): Capability? {
70
+ return self.privateCapabilities[type]
71
+ }
72
+
73
+ /// Returns all public Capabilities
74
+ ///
75
+ /// @return List of all public Capabilities
76
+ ///
77
+ pub fun getAllPublic(): [Capability] {
78
+ return self.publicCapabilities.values
79
+ }
80
+
81
+ /// Returns all private Capabilities
82
+ ///
83
+ /// @return List of all private Capabilities
84
+ ///
85
+ pub fun getAllPrivate(): [Capability] {
86
+ return self.privateCapabilities.values
87
+ }
88
+
89
+ /// Returns the first public Type that is a subtype of the given Type
90
+ ///
91
+ /// @param type: Type to check for subtypes
92
+ /// @return First public Type that is a subtype of the given Type, nil otherwise
93
+ ///
94
+ pub fun findFirstPublicType(_ type: Type): Type? {
95
+ for t in self.publicCapabilities.keys {
96
+ if t.isSubtype(of: type) {
97
+ return t
98
+ }
99
+ }
100
+
101
+ return nil
102
+ }
103
+
104
+ /// Returns the first private Type that is a subtype of the given Type
105
+ ///
106
+ /// @param type: Type to check for subtypes
107
+ /// @return First private Type that is a subtype of the given Type, nil otherwise
108
+ ///
109
+ pub fun findFirstPrivateType(_ type: Type): Type? {
110
+ for t in self.privateCapabilities.keys {
111
+ if t.isSubtype(of: type) {
112
+ return t
113
+ }
114
+ }
115
+
116
+ return nil
117
+ }
118
+ // ------- End Getter methods
119
+
120
+ /// Adds a Capability to the Delegator
121
+ ///
122
+ /// @param cap: Capability to add
123
+ /// @param isPublic: Whether the Capability should be public or private
124
+ ///
125
+ pub fun addCapability(cap: Capability, isPublic: Bool) {
126
+ pre {
127
+ cap.check<&AnyResource>(): "Invalid Capability provided"
128
+ }
129
+ if isPublic {
130
+ self.publicCapabilities.insert(key: cap.getType(), cap)
131
+ } else {
132
+ self.privateCapabilities.insert(key: cap.getType(), cap)
133
+ }
134
+ emit DelegatorUpdated(id: self.uuid, capabilityType: cap.getType(), isPublic: isPublic, active: true)
135
+ }
136
+
137
+ /// Removes a Capability from the Delegator
138
+ ///
139
+ /// @param cap: Capability to remove
140
+ ///
141
+ pub fun removeCapability(cap: Capability) {
142
+ if let removedPublic = self.publicCapabilities.remove(key: cap.getType()) {
143
+ emit DelegatorUpdated(id: self.uuid, capabilityType: cap.getType(), isPublic: true, active: false)
144
+ }
145
+
146
+ if let removedPrivate = self.privateCapabilities.remove(key: cap.getType()) {
147
+ emit DelegatorUpdated(id: self.uuid, capabilityType: cap.getType(), isPublic: false, active: false)
148
+ }
149
+ }
150
+
151
+ init() {
152
+ self.privateCapabilities = {}
153
+ self.publicCapabilities = {}
154
+ }
155
+ }
156
+
157
+ /// Creates a new Delegator and returns it
158
+ ///
159
+ /// @return Newly created Delegator
160
+ ///
161
+ pub fun createDelegator(): @Delegator {
162
+ let delegator <- create Delegator()
163
+ emit DelegatorCreated(id: delegator.uuid)
164
+ return <- delegator
165
+ }
166
+
167
+ init() {
168
+ let identifier = "CapabilityDelegator_".concat(self.account.address.toString())
169
+ self.StoragePath = StoragePath(identifier: identifier)!
170
+ self.PrivatePath = PrivatePath(identifier: identifier)!
171
+ self.PublicPath = PublicPath(identifier: identifier)!
172
+ }
173
+ }
174
+
@@ -0,0 +1,105 @@
1
+ /// # Capability Factory
2
+ ///
3
+ /// This contract defines a Factory interface and a Manager resource to contain Factory implementations, as well as a
4
+ /// Getter interface for retrieval of contained Factories.
5
+ ///
6
+ /// A Factory is defines a method getCapability() which defines the retrieval pattern of a Capability from a given
7
+ /// account at the specified path. This pattern arose out of a need to retrieve arbitrary & castable Capabilities from
8
+ /// an account under the static typing constraints inherent to Cadence.
9
+ ///
10
+ /// The Manager resource is a container for Factories, and implements the Getter interface.
11
+ ///
12
+ /// **Note:** It's generally an anti-pattern to pass around AuthAccount references; however, the need for castable
13
+ /// Capabilities is critical to the use case of Hybrid Custody. It's advised to use Factories sparingly and only for
14
+ /// cases where Capabilities must be castable by the caller.
15
+ ///
16
+ pub contract CapabilityFactory {
17
+
18
+ pub let StoragePath: StoragePath
19
+ pub let PrivatePath: PrivatePath
20
+ pub let PublicPath: PublicPath
21
+
22
+ /// Factory structures a common interface for Capability retrieval from a given account at a specified path
23
+ ///
24
+ pub struct interface Factory {
25
+ pub fun getCapability(acct: &AuthAccount, path: CapabilityPath): Capability
26
+ }
27
+
28
+ /// Getter defines an interface for retrieval of a Factory if contained within the implementing resource
29
+ ///
30
+ pub resource interface Getter {
31
+ pub fun getSupportedTypes(): [Type]
32
+ pub fun getFactory(_ t: Type): {CapabilityFactory.Factory}?
33
+ }
34
+
35
+ /// Manager is a resource that contains Factories and implements the Getter interface for retrieval of contained
36
+ /// Factories
37
+ ///
38
+ pub resource Manager: Getter {
39
+ /// Mapping of Factories indexed on Type of Capability they retrieve
40
+ pub let factories: {Type: {CapabilityFactory.Factory}}
41
+
42
+ /// Retrieves a list of Types supported by contained Factories
43
+ ///
44
+ /// @return List of Types supported by the Manager
45
+ ///
46
+ pub fun getSupportedTypes(): [Type] {
47
+ return self.factories.keys
48
+ }
49
+
50
+ /// Retrieves a Factory from the Manager, returning it or nil if it doesn't exist
51
+ ///
52
+ /// @param t: Type the Factory is indexed on
53
+ ///
54
+ pub fun getFactory(_ t: Type): {CapabilityFactory.Factory}? {
55
+ return self.factories[t]
56
+ }
57
+
58
+ /// Adds a Factory to the Manager, conditioned on the Factory not already existing
59
+ ///
60
+ /// @param t: Type of Capability the Factory retrieves
61
+ /// @param f: Factory to add
62
+ ///
63
+ pub fun addFactory(_ t: Type, _ f: {CapabilityFactory.Factory}) {
64
+ pre {
65
+ !self.factories.containsKey(t): "Factory of given type already exists"
66
+ }
67
+ self.factories[t] = f
68
+ }
69
+
70
+ /// Updates a Factory in the Manager, adding if it didn't already exist
71
+ ///
72
+ /// @param t: Type of Capability the Factory retrieves
73
+ /// @param f: Factory to replace existing Factory
74
+ ///
75
+ pub fun updateFactory(_ t: Type, _ f: {CapabilityFactory.Factory}) {
76
+ self.factories[t] = f
77
+ }
78
+
79
+ /// Removes a Factory from the Manager, returning it or nil if it didn't exist
80
+ ///
81
+ /// @param t: Type the Factory is indexed on
82
+ ///
83
+ pub fun removeFactory(_ t: Type): {CapabilityFactory.Factory}? {
84
+ return self.factories.remove(key: t)
85
+ }
86
+
87
+ init () {
88
+ self.factories = {}
89
+ }
90
+ }
91
+
92
+ /// Creates a Manager resource
93
+ ///
94
+ /// @return Manager resource
95
+ pub fun createFactoryManager(): @Manager {
96
+ return <- create Manager()
97
+ }
98
+
99
+ init() {
100
+ let identifier = "CapabilityFactory_".concat(self.account.address.toString())
101
+ self.StoragePath = StoragePath(identifier: identifier)!
102
+ self.PrivatePath = PrivatePath(identifier: identifier)!
103
+ self.PublicPath = PublicPath(identifier: identifier)!
104
+ }
105
+ }
@@ -0,0 +1,199 @@
1
+ /// CapabilityFilter defines `Filter`, an interface to sit on top of a ChildAccount's capabilities. Requested
2
+ /// capabilities will only return if the filter's `allowed` method returns true.
3
+ ///
4
+ /// Along with the `Filter` interface are three implementations:
5
+ /// - `DenylistFilter` - A filter which contains a mapping of denied Types
6
+ /// - `AllowlistFilter` - A filter which contains a mapping of allowed Types
7
+ /// - `AllowAllFilter` - A passthrough, all requested capabilities are allowed
8
+ ///
9
+ pub contract CapabilityFilter {
10
+
11
+ /* --- Canonical Paths --- */
12
+ //
13
+ pub let StoragePath: StoragePath
14
+ pub let PublicPath: PublicPath
15
+ pub let PrivatePath: PrivatePath
16
+
17
+ /* --- Events --- */
18
+ //
19
+ pub event FilterUpdated(id: UInt64, filterType: Type, type: Type, active: Bool)
20
+
21
+ /// `Filter` is a simple interface with methods to determine if a Capability is allowed and retrieve details about
22
+ /// the Filter itself
23
+ ///
24
+ pub resource interface Filter {
25
+ pub fun allowed(cap: Capability): Bool
26
+ pub fun getDetails(): AnyStruct
27
+ }
28
+
29
+ /// `DenylistFilter` is a `Filter` which contains a mapping of denied Types
30
+ ///
31
+ pub resource DenylistFilter: Filter {
32
+
33
+ /// Represents the underlying types which should not ever be returned by a RestrictedChildAccount. The filter
34
+ /// will borrow a requested capability, and make sure that the type it gets back is not in the list of denied
35
+ /// types
36
+ access(self) let deniedTypes: {Type: Bool}
37
+
38
+ /// Adds a type to the mapping of denied types with a value of true
39
+ ///
40
+ /// @param type: The type to add to the denied types mapping
41
+ ///
42
+ pub fun addType(_ type: Type) {
43
+ self.deniedTypes.insert(key: type, true)
44
+ emit FilterUpdated(id: self.uuid, filterType: self.getType(), type: type, active: true)
45
+ }
46
+
47
+ /// Removes a type from the mapping of denied types
48
+ ///
49
+ /// @param type: The type to remove from the denied types mapping
50
+ ///
51
+ pub fun removeType(_ type: Type) {
52
+ if let removed = self.deniedTypes.remove(key: type) {
53
+ emit FilterUpdated(id: self.uuid, filterType: self.getType(), type: type, active: false)
54
+ }
55
+ }
56
+
57
+ /// Determines if a requested capability is allowed by this `Filter`
58
+ ///
59
+ /// @param cap: The capability to check
60
+ /// @return: true if the capability is allowed, false otherwise
61
+ ///
62
+ pub fun allowed(cap: Capability): Bool {
63
+ if let item = cap.borrow<&AnyResource>() {
64
+ return !self.deniedTypes.containsKey(item.getType())
65
+ }
66
+
67
+ return false
68
+ }
69
+
70
+ /// Returns details about this filter
71
+ ///
72
+ /// @return A struct containing details about this filter including this Filter's Type indexed on the `type`
73
+ /// key as well as types denied indexed on the `deniedTypes` key
74
+ ///
75
+ pub fun getDetails(): AnyStruct {
76
+ return {
77
+ "type": self.getType(),
78
+ "deniedTypes": self.deniedTypes.keys
79
+ }
80
+ }
81
+
82
+ init() {
83
+ self.deniedTypes = {}
84
+ }
85
+ }
86
+
87
+ /// `AllowlistFilter` is a `Filter` which contains a mapping of allowed Types
88
+ ///
89
+ pub resource AllowlistFilter: Filter {
90
+ // allowedTypes
91
+ // Represents the set of underlying types which are allowed to be
92
+ // returned by a RestrictedChildAccount. The filter will borrow
93
+ // a requested capability, and make sure that the type it gets back is
94
+ // in the list of allowed types
95
+ access(self) let allowedTypes: {Type: Bool}
96
+
97
+ /// Adds a type to the mapping of allowed types with a value of true
98
+ ///
99
+ /// @param type: The type to add to the allowed types mapping
100
+ ///
101
+ pub fun addType(_ type: Type) {
102
+ self.allowedTypes.insert(key: type, true)
103
+ emit FilterUpdated(id: self.uuid, filterType: self.getType(), type: type, active: true)
104
+ }
105
+
106
+ /// Removes a type from the mapping of allowed types
107
+ ///
108
+ /// @param type: The type to remove from the denied types mapping
109
+ ///
110
+ pub fun removeType(_ type: Type) {
111
+ if let removed = self.allowedTypes.remove(key: type) {
112
+ emit FilterUpdated(id: self.uuid, filterType: self.getType(), type: type, active: false)
113
+ }
114
+ }
115
+
116
+ /// Determines if a requested capability is allowed by this `Filter`
117
+ ///
118
+ /// @param cap: The capability to check
119
+ /// @return: true if the capability is allowed, false otherwise
120
+ ///
121
+ pub fun allowed(cap: Capability): Bool {
122
+ if let item = cap.borrow<&AnyResource>() {
123
+ return self.allowedTypes.containsKey(item.getType())
124
+ }
125
+
126
+ return false
127
+ }
128
+
129
+ /// Returns details about this filter
130
+ ///
131
+ /// @return A struct containing details about this filter including this Filter's Type indexed on the `type`
132
+ /// key as well as types allowed indexed on the `allowedTypes` key
133
+ ///
134
+ pub fun getDetails(): AnyStruct {
135
+ return {
136
+ "type": self.getType(),
137
+ "allowedTypes": self.allowedTypes.keys
138
+ }
139
+ }
140
+
141
+ init() {
142
+ self.allowedTypes = {}
143
+ }
144
+ }
145
+
146
+ /// AllowAllFilter is a passthrough, all requested capabilities are allowed
147
+ ///
148
+ pub resource AllowAllFilter: Filter {
149
+ /// Determines if a requested capability is allowed by this `Filter`
150
+ ///
151
+ /// @param cap: The capability to check
152
+ /// @return: true since this filter is a passthrough
153
+ ///
154
+ pub fun allowed(cap: Capability): Bool {
155
+ return true
156
+ }
157
+
158
+ /// Returns details about this filter
159
+ ///
160
+ /// @return A struct containing details about this filter including this Filter's Type indexed on the `type`
161
+ /// key
162
+ ///
163
+ pub fun getDetails(): AnyStruct {
164
+ return {
165
+ "type": self.getType()
166
+ }
167
+ }
168
+ }
169
+
170
+ /// Creates a new `Filter` of the given type
171
+ ///
172
+ /// @param t: The type of `Filter` to create
173
+ /// @return: A new instance of the given `Filter` type
174
+ ///
175
+ pub fun create(_ t: Type): @AnyResource{Filter} {
176
+ post {
177
+ result.getType() == t
178
+ }
179
+
180
+ switch t {
181
+ case Type<@AllowAllFilter>():
182
+ return <- create AllowAllFilter()
183
+ case Type<@AllowlistFilter>():
184
+ return <- create AllowlistFilter()
185
+ case Type<@DenylistFilter>():
186
+ return <- create DenylistFilter()
187
+ }
188
+
189
+ panic("unsupported type requested: ".concat(t.identifier))
190
+ }
191
+
192
+ init() {
193
+ let identifier = "CapabilityFilter_".concat(self.account.address.toString())
194
+
195
+ self.StoragePath = StoragePath(identifier: identifier)!
196
+ self.PublicPath = PublicPath(identifier: identifier)!
197
+ self.PrivatePath = PrivatePath(identifier: identifier)!
198
+ }
199
+ }