Smart Contract

CapabilityDelegator

A.d8a7e05a7ac670c0.CapabilityDelegator

Deployed

1w ago
Feb 17, 2026, 02:27:56 PM UTC

Dependents

20 imports
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///
10access(all) contract CapabilityDelegator {
11
12    /* --- Canonical Paths --- */
13    //
14    access(all) let StoragePath: StoragePath
15    access(all) let PublicPath: PublicPath
16
17    access(all) entitlement Get
18    access(all) entitlement Add
19    access(all) entitlement Delete
20    
21    /* --- Events --- */
22    //
23    access(all) event DelegatorCreated(id: UInt64)
24    access(all) event DelegatorUpdated(id: UInt64, capabilityType: Type, isPublic: Bool, active: Bool)
25
26    /// Private interface for Capability retrieval
27    ///
28    access(all) resource interface GetterPrivate {
29        access(Get) view fun getPrivateCapability(_ type: Type): Capability? {
30            post {
31                result == nil || type.isSubtype(of: result.getType()): "incorrect returned capability type"
32            }
33        }
34        access(all) view fun findFirstPrivateType(_ type: Type): Type?
35        access(Get) fun getAllPrivate(): [Capability]
36    }
37
38    /// Exposes public Capability retrieval
39    ///
40    access(all) resource interface GetterPublic {
41        access(all) view fun getPublicCapability(_ type: Type): Capability? {
42            post {
43                result == nil || type.isSubtype(of: result.getType()): "incorrect returned capability type"
44            }
45        }
46
47        access(all) view fun findFirstPublicType(_ type: Type): Type?
48        access(all) view fun getAllPublic(): [Capability]
49    }
50
51    /// This Delegator is used to store Capabilities, partitioned by public and private access with corresponding
52    /// GetterPublic and GetterPrivate conformances.AccountCapabilityController
53    ///
54    access(all) resource Delegator: GetterPublic, GetterPrivate {
55        access(self) let privateCapabilities: {Type: Capability}
56        access(self) let publicCapabilities: {Type: Capability}
57
58        // ------ Begin Getter methods
59        //
60        /// Returns the public Capability of the given Type if it exists
61        ///
62        access(all) view fun getPublicCapability(_ type: Type): Capability? {
63            return self.publicCapabilities[type]
64        }
65
66        /// Returns the private Capability of the given Type if it exists
67        ///
68        ///
69        /// @param type: Type of the Capability to retrieve
70        /// @return Capability of the given Type if it exists, nil otherwise
71        ///
72        access(Get) view fun getPrivateCapability(_ type: Type): Capability? {
73            return self.privateCapabilities[type]
74        }
75
76        /// Returns all public Capabilities
77        ///
78        /// @return List of all public Capabilities
79        ///
80        access(all) view fun getAllPublic(): [Capability] {
81            return self.publicCapabilities.values
82        }
83
84        /// Returns all private Capabilities
85        ///
86        /// @return List of all private Capabilities
87        ///
88        access(Get) fun getAllPrivate(): [Capability] {
89            return self.privateCapabilities.values
90        }
91
92        /// Returns the first public Type that is a subtype of the given Type
93        ///
94        /// @param type: Type to check for subtypes
95        /// @return First public Type that is a subtype of the given Type, nil otherwise
96        ///
97        access(all) view fun findFirstPublicType(_ type: Type): Type? {
98            for t in self.publicCapabilities.keys {
99                if t.isSubtype(of: type) {
100                    return t
101                }
102            }
103
104            return nil
105        }
106
107        /// Returns the first private Type that is a subtype of the given Type
108        ///
109        /// @param type: Type to check for subtypes
110        /// @return First private Type that is a subtype of the given Type, nil otherwise
111        ///
112        access(all) view fun findFirstPrivateType(_ type: Type): Type? {
113            for t in self.privateCapabilities.keys {
114                if t.isSubtype(of: type) {
115                    return t
116                }
117            }
118
119            return nil
120        }
121        // ------- End Getter methods
122
123        /// Adds a Capability to the Delegator
124        ///
125        /// @param cap: Capability to add
126        /// @param isPublic: Whether the Capability should be public or private
127        ///
128        access(Add) fun addCapability(cap: Capability, isPublic: Bool) {
129            pre {
130                cap.check<&AnyResource>(): "Invalid Capability provided"
131            }
132            if isPublic {
133                self.publicCapabilities.insert(key: cap.getType(), cap)
134            } else {
135                self.privateCapabilities.insert(key: cap.getType(), cap)
136            }
137            emit DelegatorUpdated(id: self.uuid, capabilityType: cap.getType(), isPublic: isPublic, active: true)
138        }
139
140        /// Removes a Capability from the Delegator
141        ///
142        /// @param cap: Capability to remove
143        ///
144        access(Delete) fun removeCapability(cap: Capability) {
145            if let removedPublic = self.publicCapabilities.remove(key: cap.getType()) {
146                emit DelegatorUpdated(id: self.uuid, capabilityType: cap.getType(), isPublic: true, active: false)
147            }
148            
149            if let removedPrivate = self.privateCapabilities.remove(key: cap.getType()) {
150                emit DelegatorUpdated(id: self.uuid, capabilityType: cap.getType(), isPublic: false, active: false)
151            }
152        }
153
154        init() {
155            self.privateCapabilities = {}
156            self.publicCapabilities = {}
157        }
158    }
159
160    /// Creates a new Delegator and returns it
161    /// 
162    /// @return Newly created Delegator
163    ///
164    access(all) fun createDelegator(): @Delegator {
165        let delegator <- create Delegator()
166        emit DelegatorCreated(id: delegator.uuid)
167        return <- delegator
168    }
169    
170    init() {
171        let identifier = "CapabilityDelegator_".concat(self.account.address.toString())
172        self.StoragePath = StoragePath(identifier: identifier)!
173        self.PublicPath = PublicPath(identifier: identifier)!
174    }
175}
176