Smart Contract
CapabilityFactory
A.d8a7e05a7ac670c0.CapabilityFactory
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///
16access(all) contract CapabilityFactory {
17
18 access(all) let StoragePath: StoragePath
19 access(all) let PublicPath: PublicPath
20
21 access(all) entitlement Add
22 access(all) entitlement Delete
23
24 /// Factory structures a common interface for Capability retrieval from a given account at a specified path
25 ///
26 access(all) struct interface Factory {
27 access(all) view fun getCapability(acct: auth(Capabilities) &Account, controllerID: UInt64): Capability?
28 access(all) view fun getPublicCapability(acct: &Account, path: PublicPath): Capability?
29 }
30
31 /// Getter defines an interface for retrieval of a Factory if contained within the implementing resource
32 ///
33 access(all) resource interface Getter {
34 access(all) view fun getSupportedTypes(): [Type]
35 access(all) view fun getFactory(_ t: Type): {CapabilityFactory.Factory}?
36 }
37
38 /// Manager is a resource that contains Factories and implements the Getter interface for retrieval of contained
39 /// Factories
40 ///
41 access(all) resource Manager: Getter {
42 /// Mapping of Factories indexed on Type of Capability they retrieve
43 access(all) let factories: {Type: {CapabilityFactory.Factory}}
44
45 /// Retrieves a list of Types supported by contained Factories
46 ///
47 /// @return List of Types supported by the Manager
48 ///
49 access(all) view fun getSupportedTypes(): [Type] {
50 return self.factories.keys
51 }
52
53 /// Retrieves a Factory from the Manager, returning it or nil if it doesn't exist
54 ///
55 /// @param t: Type the Factory is indexed on
56 ///
57 access(all) view fun getFactory(_ t: Type): {CapabilityFactory.Factory}? {
58 return self.factories[t]
59 }
60
61 /// Adds a Factory to the Manager, conditioned on the Factory not already existing
62 ///
63 /// @param t: Type of Capability the Factory retrieves
64 /// @param f: Factory to add
65 ///
66 access(Add) fun addFactory(_ t: Type, _ f: {CapabilityFactory.Factory}) {
67 pre {
68 !self.factories.containsKey(t): "Factory of given type already exists"
69 }
70 self.factories[t] = f
71 }
72
73 /// Updates a Factory in the Manager, adding if it didn't already exist
74 ///
75 /// @param t: Type of Capability the Factory retrieves
76 /// @param f: Factory to replace existing Factory
77 ///
78 access(Add) fun updateFactory(_ t: Type, _ f: {CapabilityFactory.Factory}) {
79 self.factories[t] = f
80 }
81
82 /// Removes a Factory from the Manager, returning it or nil if it didn't exist
83 ///
84 /// @param t: Type the Factory is indexed on
85 ///
86 access(Delete) fun removeFactory(_ t: Type): {CapabilityFactory.Factory}? {
87 return self.factories.remove(key: t)
88 }
89
90 init () {
91 self.factories = {}
92 }
93 }
94
95 /// Creates a Manager resource
96 ///
97 /// @return Manager resource
98 access(all) fun createFactoryManager(): @Manager {
99 return <- create Manager()
100 }
101
102 init() {
103 let identifier = "CapabilityFactory_".concat(self.account.address.toString())
104 self.StoragePath = StoragePath(identifier: identifier)!
105 self.PublicPath = PublicPath(identifier: identifier)!
106 }
107}