diff --git a/kip-0027.md b/kip-0027.md new file mode 100644 index 0000000..2778f77 --- /dev/null +++ b/kip-0027.md @@ -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.