Skip to content

Commit

Permalink
Add CapabilityCache contract
Browse files Browse the repository at this point in the history
  • Loading branch information
austinkline committed Aug 24, 2024
1 parent 0c74f7a commit 78a082a
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 2 deletions.
97 changes: 97 additions & 0 deletions contracts/capability-cache/CapabilityCache.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
https://github.com/Flowtyio/capability-cache
CapabilityCache helps manage capabilities which are issued but are not in public paths.
Rather than looping through all capabilities under a storage path and finding one that
matches the Capability type you want, the cache can be used to retrieve them
*/
access(all) contract CapabilityCache {

access(all) let basePathIdentifier: String

access(all) event CapabilityAdded(owner: Address?, cacheUuid: UInt64, namespace: String, resourceType: Type, capabilityType: Type, capabilityID: UInt64)
access(all) event CapabilityRemoved(owner: Address?, cacheUuid: UInt64, namespace: String, resourceType: Type, capabilityType: Type, capabilityID: UInt64)

// Add to a namespace
access(all) entitlement Add

// Remove from a namespace
access(all) entitlement Delete

// Retrieve a cap from the namespace
access(all) entitlement Get

// Resource that manages capabilities for a provided namespace. Only one capability is permitted per type.
access(all) resource Cache {
// A dictionary of resourceType -> CapabilityType -> Capability
// For example, one might store a Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}> for the @TopShot.NFT resource.
// Note that the resource type is not necessarily the type that the borrowed capability is an instance of. This is because some resource definitions
// might be reused.
access(self) let caps: {Type: {Type: Capability}}

// who is this capability cache maintained by? e.g. flowty, dapper, find?
access(all) let namespace: String

// Remove a capability, if it exists,
access(Delete) fun removeCapabilityByType(resourceType: Type, capabilityType: Type): Capability? {
if let ref = &self.caps[resourceType] as auth(Mutate) &{Type: Capability}? {
let cap = ref.remove(key: capabilityType)
if cap != nil {
emit CapabilityRemoved(owner: self.owner?.address, cacheUuid: self.uuid, namespace: self.namespace, resourceType: resourceType, capabilityType: capabilityType, capabilityID: cap!.id)
}
}

return nil
}

// Adds a capability to the cache. If there is already an entry for the given type,
// it will be returned
access(Add) fun addCapability(resourceType: Type, cap: Capability): Capability? {
pre {
cap.id != 0: "cannot add a capability with id 0"
}

let capType = cap.getType()
emit CapabilityAdded(owner: self.owner?.address, cacheUuid: self.uuid, namespace: self.namespace, resourceType: resourceType, capabilityType: capType, capabilityID: cap.id)
if let ref = &self.caps[resourceType] as auth(Mutate) &{Type: Capability}? {
return ref.insert(key: capType, cap)
}

self.caps[resourceType] = {
capType: cap
}

return nil
}

// Retrieve a capability key'd by a given type.
access(Get) fun getCapabilityByType(resourceType: Type, capabilityType: Type): Capability? {
if let tmp = self.caps[resourceType] {
return tmp[capabilityType]
}

return nil
}

init(namespace: String) {
self.caps = {}

self.namespace = namespace
}
}

// There is no uniform storage path for the Capability Cache. Instead, each platform which issues capabilities
// should manage their own cache, and can generate the storage path to store it in with this helper method
access(all) fun getPathForCache(_ namespace: String): StoragePath {
return StoragePath(identifier: self.basePathIdentifier.concat(namespace))
?? panic("invalid namespace value")
}

access(all) fun createCache(namespace: String): @Cache {
return <- create Cache(namespace: namespace)
}

init() {
self.basePathIdentifier = "CapabilityCache_".concat(self.account.address.toString()).concat("_")
}
}
10 changes: 9 additions & 1 deletion flow.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
"aliases": {
"emulator": "0xf8d6e0586b0a20c7",
"testnet": "0x8c5303eaa26202d6",
"mainnet": "0xf919ee77447b7497"
"mainnet": "0xe467b9dd11fa00df"
}
},
"TokenForwarding": {
Expand Down Expand Up @@ -482,6 +482,14 @@
"testnet": "0x3d49bb33997bd91e",
"emulator": "0xf8d6e0586b0a20c7"
}
},
"CapabilityCache": {
"source": "./contracts/capability-cache/CapabilityCache.cdc",
"aliases": {
"testing": "0x0000000000000007",
"emulator": "0xf8d6e0586b0a20c7",
"testnet": "0x83d75469f66d2ee6"
}
}
},
"deployments": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@flowtyio/flow-contracts",
"version": "0.1.0-beta.25",
"version": "0.1.0-beta.26",
"main": "index.json",
"description": "An NPM package for common flow contracts",
"author": "flowtyio",
Expand Down

0 comments on commit 78a082a

Please sign in to comment.