Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fill in README details #3

Merged
merged 1 commit into from
May 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 108 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,108 @@
# capability-cache
[![codecov](https://codecov.io/gh/Flowtyio/capability-cache/graph/badge.svg?token=8ZuYnUDlQD)](https://codecov.io/gh/Flowtyio/capability-cache)

# Capability Cache

## Overview

CapabilityCache is a contract that allows the storing and retrieval of capabilities.
Private paths are/were removed from Cadence with the launch of Crescendo, which presents
a challenge for platforms that want to keep the number of capabilities they issue
for their users to a minimum.

These platforms could choose to iterate over all controllers on a storage path they want
to have access to and choose one that matches their desired type, but that has two challengnes:

- How do you know the capability you are using isn't slated to be removed by another platform
when they no longer need it?
- What if there are so many capabilities issued to an existing storage path that iteration over it isn't possible?
- How does a platform know which capabilities they issued without having to build complex indexing?

Some of these can be fixed without a contract solution like this one. For instance, a platform could choose to
store a controller id or the issued Capability itself into storage in a way that can be looked up as needed.
This can work, but is overhead that can be offloaded to a contract.

The @CapabilityCache.Cache resource is given a namespace which it should be stored in (though there is no way to guarantee this),
which allows every platform to make their own cache and manage the capabilities that they issue for their users. This also makes it fairly easy
to tell what capabilities belong to what platform. If the cache is used, all a user or ecosystem tool would need to do is look at each
stored @Cache resource and iterate through the types and capabilities that they've stored.

## Usage

### Initialize Cache

In order to make a cache, you need to give it a namespace. This is done to encourage each platform to maintain their
own cache.

**NOTE: There is no way to ensure that someone else won't take a platform's typical cache namespace**

```cadence
import "CapabilityCache"

transaction(namespace: String) {
prepare(acct: auth(Storage) &Account) {
let s = CapabilityCache.getPathForCache(namespace)
if acct.storage.borrow<&CapabilityCache.Cache>(from: s) == nil {
let c <- CapabilityCache.createCache(namespace: namespace)
acct.storage.save(<-c, to: s)
}
}
}
```

### Add Capability to Cache

```cadence
import "CapabilityCache"

transaction(namespace: String, type: Type, path: StoragePath) {
prepare(acct: auth(Storage, Capabilities) &Account) {
let s = CapabilityCache.getPathForCache(namespace)
if acct.storage.borrow<&CapabilityCache.Cache>(from: s) == nil {
let c <- CapabilityCache.createCache(namespace: namespace)
acct.storage.save(<-c, to: s)
}

let cache = acct.storage.borrow<auth(CapabilityCache.Add) &CapabilityCache.Cache>(from: s)
?? panic("capability cache was not found")

let cap = acct.capabilities.storage.issueWithType(path, type: type)
cache.addCapability(cap: cap, type: type)
}
}
```

### Retrieve FT Provider Capability from Cache
```cadence
import "CapabilityCache"
import "FungibleToken"

transaction(namespace: String) {
prepare(acct: auth(BorrowValue) &Account) {
let type = Type<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>()

let s = CapabilityCache.getPathForCache(namespace)
let cache = acct.storage.borrow<auth(CapabilityCache.Get) &CapabilityCache.Cache>(from: s)
?? panic("cache not found in storage")
let cap = cache.getCapabilityByType(type)
?? panic("capability not found with provided type")
let casted = cap as! Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>
casted.borrow() ?? panic("failed to borrow provider capability")
}
}
```

### Remove Capability from Cache

```cadence
import "CapabilityCache"

transaction(namespace: String, type: Type) {
prepare(acct: auth(BorrowValue) &Account) {
let s = CapabilityCache.getPathForCache(namespace)
let cache = acct.storage.borrow<auth(CapabilityCache.Delete) &CapabilityCache.Cache>(from: s)
?? panic("cache not found in storage")

cache.removeCapabilityByType(type)
}
}
```
Loading