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

Enforce Capability Guard Request #109

Open
EnoF opened this issue Feb 21, 2024 · 1 comment
Open

Enforce Capability Guard Request #109

EnoF opened this issue Feb 21, 2024 · 1 comment

Comments

@EnoF
Copy link

EnoF commented Feb 21, 2024

Enforce Capability Guard Request

I want to be able to verify ownership of an account from within a third party
smart contract. To illustrate the need, I want to create a delivery smart
contract governing the process of ordering a product using a coin account.
In this contract there will be 3 actors:

  1. Buyer
  2. Merchant
  3. Courier

Each of these actors will have their own coin account. From the delivery
account I want a way to assert consent of the 3 actors at various steps
within the process. To give you a few examples:

  1. While Ordering a product I want to have explicit consent of the order details
    Faciliated via hashing to prevent private info to be stored on chain
  2. While Marking a product as ready for delivery
  3. While picking up a delivery
  4. While receiving the package

The coin account already has a guard that proves ownership of an account.
From the delivery contract I would want to reuse that guard to proof consent.
If the guard would be a simple keyset guard, we could write code like:

(defun create-order(order-id:string merchant:string buyer:string)
  (with-capability (CREATE_ORDER order-id)
    (enforce-guard (at 'guard (coin.details merchant)))
    (enforce-guard (at 'guard (coin.details buyer)))
  )
)

Ideally I would want to be able to pass a capability-guard to enforce-guard
and have the above abstract check workout. As capabilities can write to db,
we should only allow capabilities without db writes to pass such guard checks.
Similarly how while enforcing you are not allowed to read from db.

Important to note, the capability being enforced should not be brought into
scope and only tested, as if we are running the defcap as a function within
the body of an enforce. Allowing the guard to have the ability to guard
on multiple contracts without the contract governing the guard to expose
a special function to provide this feature.

@jmcardon
Copy link
Member

jmcardon commented Feb 29, 2024

Just as documentation here, I'm unsure whether to close this issue (We've discussed it internally), but the main problem is with this statement:

Ideally I would want to be able to pass a capability-guard to enforce-guard
and have the above abstract check workout.

Simply checking whether a capability can be acquired does not mean it is correct to assume that a user might want it to be. Many capabilities are useful purely as internally acquired tokens, e.g

(defcap INTERNAL () true)

(defconst MODULE_GUARDED_ACCOUNT "some-string-thats-unique-somehow")

(defun f (account:string ...)  ; assume there's other args
  ..
  ..
  (if (= account MODULE_GUARDED_ACCOUNT) (with-capability (INTERNAL) ..) ; do something here
    )

Does this necessarily mean that you're approved to create an order from MODULE_GUARDED_ACCOUNT simply because you can pass the acquisition code inside of INTERNAL? Of course not, unless the module code provided it, it is most certainly not ok to assume this would be allowed. The entire point of the cap is that it can only be acquired inside of the declaring module's code.

Capability bodies may or may not perform extra checks and enforces, so capability guards aren't simply a check for "does this code pass", but "have I authorized this as the caller module".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants