Smart Contract

CapabilityCache

A.acc5081c003e24cf.CapabilityCache

Valid From

85,264,776

Deployed

2d ago
Feb 25, 2026, 10:38:23 PM UTC

Dependents

13 imports
1/*
2https://github.com/Flowtyio/capability-cache
3
4CapabilityCache helps manage capabilities which are issued but are not in public paths.
5Rather than looping through all capabilities under a storage path and finding one that 
6matches the Capability type you want, the cache can be used to retrieve them
7*/
8access(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}