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

KIP-0027: Make User Guards SysOnly to ReadOnly #56

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
155 changes: 155 additions & 0 deletions kip-0027.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
KIP: "0027"
Title: ReadOnly User guards
Author: CryptoPascal
Status: Draft
Type: Standard
Category: Pact
Created: 2023/12/09
---

## Abstract

The Proposal is to allow User guards to read User tables.


## Motivation

### Reminder: Purity in Pact.

In Pact, it exists 3 levels of purity environment:
- **Impure** (normal)
- **ReadOnly**: Writing is not allowed, but Reading is allowed
- **SysOnly**: Writing / Reading is not allowed for User tables. Only Sys tables can be read.

Currently (Pact 4.10), User guards called through `(enforce-guard)` must be **SysOnly** pure.

### Rationales and new use cases

Allowing User Guards to be **ReadOnly** pure may allow new use cases, making Pact much more powerful than it actually is.


#### Namespace management by DAO / Complex Multi-sigs schemes

Namespaces are managed by 2 guards (User & Admin).

With a **ReadOnly** (instead of **SysOnly**) pure guards: complex namespaces management would be possible, like:

- Deploy new modules/keyset depending on the number of votes.
- Deploy new modules/keyset depending on the number of signatures.
- Deploy new modules/keyset depending on a dynamically determined date.
- Decentralized namespaces sales.
- ....

With the current behavior, the only (ugly) workaround is to use Modules guards.
But Module guards are deprecated and will be soon removed.


#### Smart wallets, and evolved accounts management.

With a **ReadOnly** (instead of **SysOnly**) pure guards, new features will be available with straightforward implementations.
This allows to create a variety of accounts in coin (or other fungible contracts, or poly-fungible):

- Spending allowed by a number of votes
- Spending allowed by a number of signatures
- Spending allowed by given conditions (*eg:* locking money in another account)
- Spending depending on context (*eg:* Allowed for buying an NFT of a given NFT)
- ....

Currently, it is still possible to find some workarounds by wrapping the account into a specific module.
But this strongly limits the possibilities of interacting with non-cooperative third party contracts.

### Possible drawbacks

As stated by [#489](https://github.com/kadena-io/pact/issues/489), it exists at least 2 drawbacks:

- It would allow user guards to recurse: [#380](https://github.com/kadena-io/pact/issues/380). But it seems that this has already been fixed:
[#417](https://github.com/kadena-io/pact/pull/417) and [#913](https://github.com/kadena-io/pact/pull/913)

- It would complexify FV analysis of user guards.


## Specification


| | Old Behavior | New Behavior |
|------------------------------| ------------- | -------------|
| Read User table in U-Guard | Failure | OK |
| Write User table in U-guard | Failure | Failure |





## Examples

Some basic examples:

### A guard that checks that an account owns more than x KDAs

```pact

(module balance-checker GOV
(defcap GOV ()
(enforce fail "No-Upgrade"))

(defun has-minium-balance:bool (target-account:string min-balance:decimal)
(let ((bal (coin.get-balance target-account)))
(enforce (>= bal min-balance) "No"))
)

(defun get-guard:guard (target-account:string min-balance:decimal)
(create-user-guard (has-minimum-balance target-account min-balance))
)
)

(coin.create-account "alice" (balance-checker.get-guard "alice-savings" 1000.0))

```
Alice's main account will be unlocked only if the savings account has a balance of minimum 1000.0 KDA.

This doesn't work currently (Pact 4.10) => `Failure: Illegal database access attempt (readRow)` but would be possible with this KIP implemented.


### A guard that checks that N approvals have been given

```pact

(module ns-governance GOV
...
...
...

(defconst MIN-APPROVALS 5)

(defun approve (ns:string)
(with-read approvals ns {'count:=cnt}
(insert approvals ns {'count: (+ cnt 1)}))
)

(defun enforce-approvals:bool (ns:string)
(with-read approvals ns {'count:=cnt}
(enforce (>= cnt MIN-APPROVALS) "min approvals condition not met"))
)

(defun not-allowed:bool ()
(enforce false "Not allowed")
)
)

(define-namespace 'my-namespace (create-user-guard (ns-governance.not-allowed))
(create-user-guard (ns-governance.enforce-approvals 'my-namespace)))
```

The namespace can be rotated (and then modules added), when at least 5 people have given their approval.

This doesn't work currently (Pact 4.10) => `Failure: Illegal database access attempt (readRow)` but would be possible with this KIP implemented.




## Backwards Compatibility

Changing the purity requirement of User Guards requires a Hard Fork.

However, already defined User guards (ie: **SysOnly** pure), will still continue to work seamlessly after the hard fork.