From 07b4ddaca46ece33a1a494722fdb71bec739ed4d Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Fri, 5 May 2023 10:57:10 -0400 Subject: [PATCH 01/47] add FLIP --- cadence/2023-05-05-remove-priv-and-pub.md | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 cadence/2023-05-05-remove-priv-and-pub.md diff --git a/cadence/2023-05-05-remove-priv-and-pub.md b/cadence/2023-05-05-remove-priv-and-pub.md new file mode 100644 index 00000000..3ced8e24 --- /dev/null +++ b/cadence/2023-05-05-remove-priv-and-pub.md @@ -0,0 +1,56 @@ +--- +status: proposed +flip: NNN (do not set) +authors: Daniel Sainati (daniel.sainati@dapperlabs.com) +sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) +updated: 2023-05-05 +--- + +# Remove `pub` and `priv` aliases for access modifiers + +## Objective + +This FLIP proposes to remove the `pub` alias for `access(all)` and the `priv` +modifier for `access(self)`, requiring all code to use these longer forms instead +of the shortened ones. + +## Motivation + +The proposed entitlements changes in [the entitlements FLIP](https://github.com/onflow/flips/pull/54) +will add a new `access(X)` modifier for entitled access, which will likely be used frequently +in many contracts. It would be more consistent with this new `access(X)` syntax for `pub` +and `priv` to be `access(all)` and `access(self)` respectively. + +## User Benefit + +This will increase the readability and consistency of user code. + +## Design Proposal + +The proposal is simple: just remove the `pub` and `priv` aliases. No other +changes will be necessary. + +### Drawbacks + +This will increase the verbosity of all code, as well as break every single contract +that exists, as it is extremely unlikely that there is any code on Mainnet currently that +does not use at least one `pub` modifier. However, as discussed in the next section, this may be +an benefit rather than a drawback. + +### Compatibility + +This is not backwards compatible, and will indeed break every existing contract. However, +given that the aforementioned entitlements change is also going to require a rewrite of all +code currently deployed to Mainnet, a change such as this that statically breaks all of that code +will alert developers that changes are required, rather than allowing potentially newly unsafe +code to slip through undetected. + +### User Impact + +This is going to require all code to be updated to not use the deprecated modifiers. It would +be possible to write a migration assistant that would automatically replace the `pub` and `priv` +modifiers with their equivalent long forms, but it is unclear if we would want to do this, given +that a stated goal of this change is to make developers manually consider which `pub` methods are +truly `access(all)` and which should be rewritten to use entitlements. + +## Questions and Discussion Topics From 9d9b6546af172ee410be2abbb3b5d533e816f7e1 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 24 May 2023 18:59:29 -0400 Subject: [PATCH 02/47] add language proposing the removal of pub(set) --- cadence/2023-05-05-remove-priv-and-pub.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cadence/2023-05-05-remove-priv-and-pub.md b/cadence/2023-05-05-remove-priv-and-pub.md index 3ced8e24..961ec4f1 100644 --- a/cadence/2023-05-05-remove-priv-and-pub.md +++ b/cadence/2023-05-05-remove-priv-and-pub.md @@ -14,6 +14,11 @@ This FLIP proposes to remove the `pub` alias for `access(all)` and the `priv` modifier for `access(self)`, requiring all code to use these longer forms instead of the shortened ones. +This also proposes to remove the `pub(set)` access keyword, which was previously used to make +variables publicly settable. This is not a common case, and in order to simplify the language, +we also propose to remove it. If users wish to have a field be publicly settable, they should write +a public mutator function for that field. + ## Motivation The proposed entitlements changes in [the entitlements FLIP](https://github.com/onflow/flips/pull/54) From 4172dbfd2378dc936dfde27777934156c065466b Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 25 May 2023 12:06:55 -0400 Subject: [PATCH 03/47] more info about removing pub set --- cadence/2023-05-05-remove-priv-and-pub.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cadence/2023-05-05-remove-priv-and-pub.md b/cadence/2023-05-05-remove-priv-and-pub.md index 961ec4f1..3cbfb4e9 100644 --- a/cadence/2023-05-05-remove-priv-and-pub.md +++ b/cadence/2023-05-05-remove-priv-and-pub.md @@ -32,8 +32,8 @@ This will increase the readability and consistency of user code. ## Design Proposal -The proposal is simple: just remove the `pub` and `priv` aliases. No other -changes will be necessary. +The proposal is simple: just remove the `pub` and `priv` aliases. `pub(set)` will +also be removed. ### Drawbacks From 52d0ad9bb5d5bf3fa08e18674d76ce797b5beca0 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 25 May 2023 14:43:58 -0400 Subject: [PATCH 04/47] Update cadence/2023-05-05-remove-priv-and-pub.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- cadence/2023-05-05-remove-priv-and-pub.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cadence/2023-05-05-remove-priv-and-pub.md b/cadence/2023-05-05-remove-priv-and-pub.md index 3cbfb4e9..23651c8f 100644 --- a/cadence/2023-05-05-remove-priv-and-pub.md +++ b/cadence/2023-05-05-remove-priv-and-pub.md @@ -1,12 +1,12 @@ --- status: proposed -flip: NNN (do not set) +flip: 84 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) updated: 2023-05-05 --- -# Remove `pub` and `priv` aliases for access modifiers +# FLIP 84: Remove `pub` and `priv` aliases for access modifiers ## Objective From d80cb4312b783d2050a047a14fefebaa86d961b0 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 25 May 2023 14:45:25 -0400 Subject: [PATCH 05/47] rename --- ...-05-remove-priv-and-pub.md => 20230505-remove-priv-and-pub.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cadence/{2023-05-05-remove-priv-and-pub.md => 20230505-remove-priv-and-pub.md} (100%) diff --git a/cadence/2023-05-05-remove-priv-and-pub.md b/cadence/20230505-remove-priv-and-pub.md similarity index 100% rename from cadence/2023-05-05-remove-priv-and-pub.md rename to cadence/20230505-remove-priv-and-pub.md From 00a745b26314424211f70ec78909fac76768bb6f Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Mon, 5 Jun 2023 15:46:12 -0400 Subject: [PATCH 06/47] Mark FLIPs as implemented (#98) mark flips as implemented --- cadence/20211129-cadence-mutability-restrictions.md | 2 +- cadence/20211208-cadence-remove-optional-reference.md | 2 +- cadence/20211208-cadence-storage-api-changes.md | 2 +- cadence/20211210-cadence-numeric-supertypes.md | 2 +- cadence/20220203-capability-controllers.md | 2 +- cadence/20220516-reference-creation-semantics.md | 2 +- cadence/20220715-cadence-purity-analysis.md | 2 +- cadence/20220921-attachments.md | 2 +- cadence/20221011-for-loop-semantics.md | 2 +- cadence/20221018-change-fun-type-syntax.md | 2 +- cadence/20221024-interface-inheritance.md | 2 +- cadence/20221207-authaccount-capabilities.md | 2 +- cadence/20221214-auth-remodel.md | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cadence/20211129-cadence-mutability-restrictions.md b/cadence/20211129-cadence-mutability-restrictions.md index ce45bf6d..dcba1968 100644 --- a/cadence/20211129-cadence-mutability-restrictions.md +++ b/cadence/20211129-cadence-mutability-restrictions.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 703 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) diff --git a/cadence/20211208-cadence-remove-optional-reference.md b/cadence/20211208-cadence-remove-optional-reference.md index 2ebed627..a060afcb 100644 --- a/cadence/20211208-cadence-remove-optional-reference.md +++ b/cadence/20211208-cadence-remove-optional-reference.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 722 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) diff --git a/cadence/20211208-cadence-storage-api-changes.md b/cadence/20211208-cadence-storage-api-changes.md index 59e9089a..45310cd3 100644 --- a/cadence/20211208-cadence-storage-api-changes.md +++ b/cadence/20211208-cadence-storage-api-changes.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 718 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) diff --git a/cadence/20211210-cadence-numeric-supertypes.md b/cadence/20211210-cadence-numeric-supertypes.md index a1883bfe..f740afce 100644 --- a/cadence/20211210-cadence-numeric-supertypes.md +++ b/cadence/20211210-cadence-numeric-supertypes.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 729 authors: Supun Setunga (supun.setunga@dapperlabs.com) sponsor: Supun Setunga (supun.setunga@dapperlabs.com) diff --git a/cadence/20220203-capability-controllers.md b/cadence/20220203-capability-controllers.md index ea17c239..153f8ae8 100644 --- a/cadence/20220203-capability-controllers.md +++ b/cadence/20220203-capability-controllers.md @@ -1,5 +1,5 @@ --- -status: Accepted +status: implemented flip: 798 authors: Janez Podhostnik (janez.podhostnik@dapperlabs.com), Bastian Müller (bastian@dapperlabs.com) updated: 2023-05-12 diff --git a/cadence/20220516-reference-creation-semantics.md b/cadence/20220516-reference-creation-semantics.md index 0a5242cc..7829ed0a 100644 --- a/cadence/20220516-reference-creation-semantics.md +++ b/cadence/20220516-reference-creation-semantics.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 941 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) diff --git a/cadence/20220715-cadence-purity-analysis.md b/cadence/20220715-cadence-purity-analysis.md index cd74b111..1562e703 100644 --- a/cadence/20220715-cadence-purity-analysis.md +++ b/cadence/20220715-cadence-purity-analysis.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 1056 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) diff --git a/cadence/20220921-attachments.md b/cadence/20220921-attachments.md index 5b8a9650..0b6daa0a 100644 --- a/cadence/20220921-attachments.md +++ b/cadence/20220921-attachments.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 11 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) diff --git a/cadence/20221011-for-loop-semantics.md b/cadence/20221011-for-loop-semantics.md index eae92eda..a76ed4a7 100644 --- a/cadence/20221011-for-loop-semantics.md +++ b/cadence/20221011-for-loop-semantics.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 13 authors: Bastian Müller (bastian@dapperlabs.com) sponsor: Bastian Müller (bastian@dapperlabs.com) diff --git a/cadence/20221018-change-fun-type-syntax.md b/cadence/20221018-change-fun-type-syntax.md index 302d28fd..d3292415 100644 --- a/cadence/20221018-change-fun-type-syntax.md +++ b/cadence/20221018-change-fun-type-syntax.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 43 authors: Naomi Liu (naomi.liu@dapperlabs.com) sponsor: Naomi Liu (naomi.liu@dapperlabs.com) diff --git a/cadence/20221024-interface-inheritance.md b/cadence/20221024-interface-inheritance.md index 89994bb6..ce406800 100644 --- a/cadence/20221024-interface-inheritance.md +++ b/cadence/20221024-interface-inheritance.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 40 authors: Supun Setunga (supun.setunga@dapperlabs.com) sponsor: Supun Setunga (supun.setunga@dapperlabs.com) diff --git a/cadence/20221207-authaccount-capabilities.md b/cadence/20221207-authaccount-capabilities.md index 2e0e21d7..c9dec6b1 100644 --- a/cadence/20221207-authaccount-capabilities.md +++ b/cadence/20221207-authaccount-capabilities.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 53 authors: Bastian Müller (bastian@dapperlabs.com) sponsor: Dieter Shirley (dete@dapperlabs.com) diff --git a/cadence/20221214-auth-remodel.md b/cadence/20221214-auth-remodel.md index 19f4c261..0a6cbf0b 100644 --- a/cadence/20221214-auth-remodel.md +++ b/cadence/20221214-auth-remodel.md @@ -1,5 +1,5 @@ --- -status: draft +status: accepted flip: 54 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) From 09f281dc1fd8c15c1a6240f032559c8106f4cc17 Mon Sep 17 00:00:00 2001 From: Jeff Doyle Date: Mon, 5 Jun 2023 13:20:35 -0700 Subject: [PATCH 07/47] Mark FLIP-200 and FLIP-934 as implemented (#99) --- application/20201125-bip-44-multi-account.md | 32 +++++++++---------- application/20220503-interaction-templates.md | 14 ++++---- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/application/20201125-bip-44-multi-account.md b/application/20201125-bip-44-multi-account.md index fa466032..ad8dd924 100644 --- a/application/20201125-bip-44-multi-account.md +++ b/application/20201125-bip-44-multi-account.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 200 authors: Peter Siemens (peter@dapperlabs.com), Jeffery Doyle (jeffrey.doyle@dapperlabs.com) sponsor: Peter Siemens (peter@dapperlabs.com) @@ -164,20 +164,20 @@ The prescribed account discovery procedure is as follows: elliptic curve used to generate it. If the gap limit has been reached for both key index and account index, stop discovery. - - 3.1. If no addresses are found in the registry - - 3.1.1 If the key index gap limit has been reached without finding any - addressed in the registry, then go to step 2, incrementing the account index - by one and starting with key index = 0 again. - - 3.1.2 If the key index gap limit has not been reached, go to step 2 and - increment the key index by one. - - 3.2. If one or more addresses are found, query the Flow network to fetch each - account's details. - - 3.2.1. If no accounts are found1, go to step 2, incrementing - the account index by one. - - 3.2.2. For each account found1, remember the relationship between the path - used to generate this key, the curve used to generate this key, - and the hash algorithm corresponding to this key and the account's details. - Then go to step 2, incrementing the key index by one. + - 3.1. If no addresses are found in the registry + - 3.1.1 If the key index gap limit has been reached without finding any + addressed in the registry, then go to step 2, incrementing the account index + by one and starting with key index = 0 again. + - 3.1.2 If the key index gap limit has not been reached, go to step 2 and + increment the key index by one. + - 3.2. If one or more addresses are found, query the Flow network to fetch each + account's details. + - 3.2.1. If no accounts are found1, go to step 2, incrementing + the account index by one. + - 3.2.2. For each account found1, remember the relationship between the path + used to generate this key, the curve used to generate this key, + and the hash algorithm corresponding to this key and the account's details. + Then go to step 2, incrementing the key index by one. 1Flow supports account deletion, meaning that an address found in the registry may refer to a nonexistent account. In this case the address should be @@ -283,7 +283,7 @@ to the Flow account model. ### Dependencies -* Dependent projects: Flow Ledger application, Flow Port, FCL-Ledger-Web +- Dependent projects: Flow Ledger application, Flow Port, FCL-Ledger-Web ### Tutorials and Examples diff --git a/application/20220503-interaction-templates.md b/application/20220503-interaction-templates.md index 97bee50b..af8b39b0 100644 --- a/application/20220503-interaction-templates.md +++ b/application/20220503-interaction-templates.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 934 forum: https://forum.onflow.org/t/flip-934-interaction-templates/3080 authors: Jeffrey Doyle (jeffrey.doyle@dapperlabs.com) @@ -403,23 +403,23 @@ FCL `mutate` and `query` could be modified to accept an Interaction Template, an EXAMPLE: ```javascript -import transferFLOWTemplate from "./transfer-flow-template.json"; +import transferFLOWTemplate from "./transfer-flow-template.json" await fcl.mutate({ template: transferFLOWTemplate, args: (arg, t) => [arg("1.0", t.UFix64), arg("0xABC123DEF456", t.Address)], -}); +}) ``` EXAMPLE: ```javascript -import { getFLOWBalanceTemplate } from "@onflow/flow-templates"; +import { getFLOWBalanceTemplate } from "@onflow/flow-templates" await fcl.query({ template: getFLOWBalanceTemplate, args: (arg, t) => [arg("0xABC123DEF456", t.Address)], -}); +}) ``` Instead, if templates are made available at an external location, developers may chose to request them when needed by querying for them from their location: @@ -430,7 +430,7 @@ EXAMPLE: await fcl.mutate({ template: "https://transfer-flow.interactions.onflow.org", args: (arg, t) => [arg("1.0", t.UFix64), arg("0xABC123DEF456", t.Address)], -}); +}) ``` EXAMPLE: @@ -440,7 +440,7 @@ await fcl.query({ template: "ipfs://64EC88CA00B268E5BA1A35678A1B5316D212F4F366B2477232534A8AECA37F3C", args: (arg, t) => [arg("0xABC123DEF456", t.Address)], -}); +}) ``` Since a URL can remain static, while the Interaction Template it corresponds to dynamic and able to change, this allows developers to always request the most up to date implementation of an interaction - enabling a mechanic for contract developers to modify their contracts and interactions while helping to prevent any downstream breaking changes. From e843cc33eccb3d55fa64847d4531714bedf77a08 Mon Sep 17 00:00:00 2001 From: Janez Podhostnik <67895329+janezpodhostnik@users.noreply.github.com> Date: Tue, 6 Jun 2023 16:28:14 +0100 Subject: [PATCH 08/47] Flips 99 and 753 are implemented (#102) Set fee flips as implemented --- protocol/20201310-storage-fees.md | 2 +- protocol/20220111-execution-effort.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/20201310-storage-fees.md b/protocol/20201310-storage-fees.md index a0a1b841..d077ad73 100644 --- a/protocol/20201310-storage-fees.md +++ b/protocol/20201310-storage-fees.md @@ -1,5 +1,5 @@ --- -status: finalized +status: implemented flip: 99 authors: Janez Podhostnik (janez.podhostnik@dapperlabs.com) sponsor: Janez Podhostnik (janez.podhostnik@dapperlabs.com) diff --git a/protocol/20220111-execution-effort.md b/protocol/20220111-execution-effort.md index 9de0874a..354ee549 100644 --- a/protocol/20220111-execution-effort.md +++ b/protocol/20220111-execution-effort.md @@ -1,5 +1,5 @@ --- -status: proposed +status: implemented flip: 753 authors: Janez Podhostnik (janez.podhostnik@dapperlabs.com) sponsor: Janez Podhostnik (janez.podhostnik@dapperlabs.com) From 76d2f6865eb43fb121ec44abeb64b3c6b13efda0 Mon Sep 17 00:00:00 2001 From: Jeff Doyle Date: Tue, 6 Jun 2023 09:22:26 -0700 Subject: [PATCH 09/47] Updates FLIP-45 to implemented (#101) --- application/20221108-fcl-specification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/20221108-fcl-specification.md b/application/20221108-fcl-specification.md index 68f7a021..03f1f535 100644 --- a/application/20221108-fcl-specification.md +++ b/application/20221108-fcl-specification.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 45 authors: Greg Santos (greg.santos@dapperlabs.com) sponsor: Justin Barry (justin.barry@dapperlabs.com) From b02758b99f580f713c82c41d33c8269bcb3cb77b Mon Sep 17 00:00:00 2001 From: Peter Argue <89119817+peterargue@users.noreply.github.com> Date: Tue, 6 Jun 2023 12:13:46 -0700 Subject: [PATCH 10/47] Mark Even Streaming FLIP as accpted (#103) --- protocol/20230309-accessnode-event-streaming-api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/20230309-accessnode-event-streaming-api.md b/protocol/20230309-accessnode-event-streaming-api.md index 90cf5ce2..b20174d0 100644 --- a/protocol/20230309-accessnode-event-streaming-api.md +++ b/protocol/20230309-accessnode-event-streaming-api.md @@ -1,9 +1,9 @@ --- -status: proposed +status: accepted flip: 73 authors: Peter Argue (peter.argue@dapperlabs.com) sponsor: Jerome Pimmel (jerome.pimmel@dapperlabs.com) -updated: 2023-03-09 +updated: 2023-06-06 --- # FLIP 73: Event Streaming API (alpha version) From fd55c5a257bb71506b49b205bca3fef5f6ae6b2e Mon Sep 17 00:00:00 2001 From: Kshitij Chaudhary <78124453+KshitijChaudhary666@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:42:25 -0400 Subject: [PATCH 11/47] Update 20210201-consuming-messages-from-network-layer.md (#105) Changing status to "Implemented". The FLIP has already been implemented for most of the liveness-critical components within the nodes --- protocol/20210201-consuming-messages-from-network-layer.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/20210201-consuming-messages-from-network-layer.md b/protocol/20210201-consuming-messages-from-network-layer.md index 505a735f..82625231 100644 --- a/protocol/20210201-consuming-messages-from-network-layer.md +++ b/protocol/20210201-consuming-messages-from-network-layer.md @@ -1,9 +1,9 @@ --- -status: accepted +status: Implemented flip: 343 authors: Alex Hentschel (alex.hentschel@dapperlabs.com) sponsor: Alex Hentschel (alex.hentschel@dapperlabs.com) -updated: 2021-09-20 +updated: 2023-06-06 --- # FLIP 343: Handing Messages from Networking Layer to Engines (Core Protocol) From 59ffa8604724f49db99dc04e7873eec1a87dce48 Mon Sep 17 00:00:00 2001 From: Kshitij Chaudhary <78124453+KshitijChaudhary666@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:43:01 -0400 Subject: [PATCH 12/47] Update 20210118-self-ejection.md (#104) Changing status to Accepted --- protocol/20210118-self-ejection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/20210118-self-ejection.md b/protocol/20210118-self-ejection.md index 6ee4d311..9e8d0f6a 100644 --- a/protocol/20210118-self-ejection.md +++ b/protocol/20210118-self-ejection.md @@ -1,5 +1,5 @@ --- -status: proposed +status: Accepted flip: 324 authors: Alex Hentschel (alex.hentschel@dapperlabs.com), Jordan Schalm (jordan@dapperlabs.com) sponsor: Alex Hentschel (alex.hentschel@dapperlabs.com) From 575cd78844fa12c547ed43792b90f65fa1be8603 Mon Sep 17 00:00:00 2001 From: Kshitij Chaudhary <78124453+KshitijChaudhary666@users.noreply.github.com> Date: Tue, 6 Jun 2023 16:30:14 -0400 Subject: [PATCH 13/47] Update 20220629-staking-rewards.md (#106) The staking rewards have not altered, and have been "maintained" for now, as proposed by this FLIP. Therefore changing the status of this FLIP to "Implemented" --- governance/20220629-staking-rewards.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/governance/20220629-staking-rewards.md b/governance/20220629-staking-rewards.md index d1eb0f5d..9f8020a4 100644 --- a/governance/20220629-staking-rewards.md +++ b/governance/20220629-staking-rewards.md @@ -1,5 +1,5 @@ --- -status: accepted +status: Implemented flip: GOV-1 forum: https://forum.onflow.org/t/flip-gov-1-maintain-staking-rewards/3340 authors: Kristin Smith (kristin@flowfoundation.com) From a92cb231e8464ae7bd87031e68ec08da5a4086e5 Mon Sep 17 00:00:00 2001 From: Kshitij Chaudhary <78124453+KshitijChaudhary666@users.noreply.github.com> Date: Tue, 6 Jun 2023 16:30:23 -0400 Subject: [PATCH 14/47] Update 20220718-enable-automatic-rewards.md (#107) This has been implemented (on 5/3). See the following PRs - https://github.com/onflow/service-account/pull/238/ https://github.com/onflow/flow-core-contracts/pull/352 https://github.com/onflow/flow-core-contracts/pull/365 --- governance/20220718-enable-automatic-rewards.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/governance/20220718-enable-automatic-rewards.md b/governance/20220718-enable-automatic-rewards.md index 075dded9..381f1531 100644 --- a/governance/20220718-enable-automatic-rewards.md +++ b/governance/20220718-enable-automatic-rewards.md @@ -1,5 +1,5 @@ --- -status: proposed +status: Implemented flip: GOV-2 forum: https://forum.onflow.org/t/flip-gov-2-enable-automatic-staking-rewards/3438 authors: Paul Gebheim (paul.gebheim@dapperlabs.com) From 70b433bdfd9f14e7c7b9eb97635af94dd60c73f2 Mon Sep 17 00:00:00 2001 From: Kshitij Chaudhary <78124453+KshitijChaudhary666@users.noreply.github.com> Date: Tue, 6 Jun 2023 16:30:33 -0400 Subject: [PATCH 15/47] Update 20230105-identify-errant-node.md (#108) No issues raised by the community - changing status to Accepted. --- governance/20230105-identify-errant-node.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/governance/20230105-identify-errant-node.md b/governance/20230105-identify-errant-node.md index 82a270b6..31e9746e 100644 --- a/governance/20230105-identify-errant-node.md +++ b/governance/20230105-identify-errant-node.md @@ -1,5 +1,5 @@ --- -status: proposed +status: Accepted flip: GOV-4 authors: James Lofgren (76029851+TheUnseen12@users.noreply.github.com) sponsors: Kshitij Chaudhary (kshitij.chaudhary@dapperlabs.com), Vishal Changrani (vishal.changrani@dapperlabs.com) From 2b9b2d086498d8af37033af7e83a5e089651e19e Mon Sep 17 00:00:00 2001 From: Kshitij Chaudhary <78124453+KshitijChaudhary666@users.noreply.github.com> Date: Tue, 6 Jun 2023 16:52:21 -0400 Subject: [PATCH 16/47] Create 20230323-transaction-fee.md (#74) * Create 20230323-transaction-fee.md * Add files via upload * Update 20230323-transaction-fee.md Adding image * Update 20230323-transaction-fee.md --------- Co-authored-by: KshitijChaudharyHBS <78124453+KshitijChaudharyHBS@users.noreply.github.com> --- governance/20230323-transaction-fee.md | 143 +++++++++++++++++++++++++ governance/TPS-vs-Inflation.png | Bin 0 -> 67178 bytes 2 files changed, 143 insertions(+) create mode 100644 governance/20230323-transaction-fee.md create mode 100644 governance/TPS-vs-Inflation.png diff --git a/governance/20230323-transaction-fee.md b/governance/20230323-transaction-fee.md new file mode 100644 index 00000000..23bd183d --- /dev/null +++ b/governance/20230323-transaction-fee.md @@ -0,0 +1,143 @@ +# FLIP: Revisiting Flow Transaction fee + +| Status | Proposed | +:-------------- |:---------------------------------------------------- | +| **FLIP #** | [74](https://github.com/onflow/flow/pull/74) +| **Author(s)** | Kshitij Chaudhary (kshitij.chaudhary@dapperlabs.com) | +| **Sponsor** | Kshitij Chaudhary (kshitij.chaudhary@dapperlabs.com) | +| **Updated** | 2023-03-23 | + +## **Introduction** + +In October 2021, with [FLIP-660](https://github.com/onflow/flow/blob/c05d847adf2f6fb509e42c17020484d7dd3e89bd/flips/20211007-transaction-fees.md) it was determined that the transaction fees on Flow should be proportional to the cost of effort to the network imposed by deployment of resources such as CPU and bandwidth. Fees were broken down into [three components](https://developers.flow.com/learn/concepts/variable-transaction-fees) - ‘*Inclusion Fee*’ that accounts for the resources required to process a transaction due to the transaction’s core properties (byte size, number of signatures); ‘Execution Fee’ that accounts for the operational cost of running the transaction script, processing the results, sending results for verification, generating verification receipt, etc; and a *Surge* factor as a multiplicative factor to dynamically account for network pressure and market conditions. + +Despite the trifurcation however, transaction fees on Flow continue to remain incredibly low, posing threats of network attack, and potentially dis-balancing demand for transaction processing against network-capacity in future. This FLIP proposes an increase in transaction fee and seeks community feedback on the proposed changes. + +## **Problem Statement** + +**Low transaction fee poses threats of attack, necessitates continued token-issuance by the protocol (inflation), and makes FLOW use-cases seem peripheral vis-a-vis other networks.** + +In early days of the Flow network, when the number of transactions were fewer, transaction fees were intentionally kept low to encourage network usage. Today however, with Flow’s purpose-built compute platform and web3 utility for the masses driving a growing user-base (18M+ accounts) on the network consistently sending 6M+ transactions in an epoch (week), there is a need to revisit the fees. + +Today, the cost of attacking Flow with an inordinate number of transactions is incredibly low, making the network susceptible to attack by malicious actors. Additionally, as exhibited in the table below, despite ~900K daily transactions (sometimes exceeding 1M), total weekly fee collection (~50 FLOW) accounts for merely 0.004% of epoch rewards ([1.3M+ FLOW tokens](https://flowscan.org/staking/history)) paid out to node operators and delegators. During rewards pay-out, the protocol first draws from the transaction fee pool, thereafter issuing new tokens to achieve the target reward rate for each epoch ([explained here](https://developers.flow.com/nodes/staking/schedule)). Low fee collection thus remains a key factor behind Flow’s 5% annual inflation. *Note that a detailed discussion on Flow inflation is out-of-scope for this FLIP and will be comprehensively addressed in a separate proposal.* + +Finally, Flow’s low transaction fee unfortunately makes FLOW use-cases less perceptible to many users. Competing networks such as Solana, NEAR and Avalanche for instance have 300x, 450x, and 1,300x average fee per transaction respectively vis-à-vis Flow, while on ETH, the average fee is ~480,000x (see table below). Given FLOW’s multiple use-cases including staking, delegating, paying transaction fees, paying storage fees, trading assets and participating in experiences built on Flow, it is crucial that FLOW token’s utility is priced appropriately to reflect and surface its value-proposition to users. + +| Network | Daily total txns (est.) | Daily total fee (~$) | Avg fee/ txn (~$) | V/s Flow txn fee | +| --- | --- | --- | --- | --- | +| Avalanche | 2,000,000 | $ 22,375 | $ 1.12E-02 | 1,324 times | +| Bitcoin | 305,700 | $ 296,060 | $ 9.68E-01 | 114,612 times | +| BNB | 2,800,000 | $ 551,696 | $ 1.97E-01 | 23,318 times | +| Cardano | 77,300 | $ 9,599 | $ 1.24E-01 | 14,696 times | +| ETH | 1,000,000 | $ 4,063,415 | $ 4.06E+00 | 480,882 times | +| NEAR Protocol | 420,000 | $ 1,594 | $ 3.80E-03 | 449 times | +| Solana | 17,690,000 | $ 44,206 | $ 2.50E-03 | 296 times | +| Flow | 947,558 | $ 8.01 | $ 8.45E-06 | N/A | +1. *Market prices used are Year-to-date (YTD) moving averages* +2. *Average fee per transaction is calculated by daily total fee/ daily total transactions* +3. *The last column simply divides average transaction fee for a network to the average transaction fee on Flow* + +## **Proposal** + +Today, the functional specification of transaction fee on Flow looks as follows. + +**Transaction fee = {inclusion fee + (execution effort * unit cost)} x surge** + +- *Inclusion fee = 1E-6 FLOW (currently constant, but [dynamic inclusion fee FLIP](https://forum.onflow.org/t/flip-dynamic-inclusion-fees/3700) was proposed last year);* +- *Execution Effort Unit Cost = 4.99E-08 FLOW (currently constant);* +- *Surge = 1.0 (currently constant);* +- *Execution Effort is variable based on transaction type, as [shown here](https://github.com/onflow/flow/blob/c05d847adf2f6fb509e42c17020484d7dd3e89bd/flips/20220111-execution-effort.md).* + +**It is proposed that** + +1. *Inclusion fee is maintained as a constant, but increased 100x, from 1E-6 FLOW to 1E-4 FLOW for all transaction types* +2. *Unit Cost of Execution Effort is increased 100x, from 4.99E-8 FLOW to 4.99E-06 FLOW* + +| Transaction type | Effort | Current fee (FLOW) | Proposed fee (FLOW) | Proposed increase | +| --- | --- | --- | --- | --- | +| Empty Transaction (inclusion fee only) | 0 | 1.00E-06 | 1.00E-04 | 100 times | +| Create 1 account | 43 | 3.15E-06 | 3.15E-04 | 100 times | +| Create 10 accounts | 433 | 2.26E-05 | 2.26E-03 | 100 times | +| Add key to account | 0 | 1.00E-06 | 1.00E-04 | 100 times | +| FT transfer | 17 | 1.85E-06 | 1.85E-04 | 100 times | +| Deploying a 50kB contract | 574 | 2.96E-05 | 2.96E-03 | 100 times | +| Mint a small NFT | 18 | 1.90E-06 | 1.90E-04 | 100 times | + +## Impact + +First, if the proposal is accepted and implemented, users would pay a 100x transaction fee vis-à-vis today. Simply put, minting 1 million small NFTs on Flow costs ~1.9 FLOW today; with increased fee however, users would have to pay ~190 FLOW for such volume. By generally increasing the cost of mass attack by 100x, the proposal is aimed at disincentivizing malicious actors and enhancing network’s security and resilience against attacks. + +Second, while this proposal by itself will only marginally reduce inflation (from ~5% to ~4.98%), it is a crucial step in the direction of addressing inflation on Flow in the long-term. As an example, the graph below exhibits the inflation rate with status-quo vis-a-vis with proposed fee increase, demonstrating a meaningful reduction in inflation if number of transactions grow multifold (ceteris paribus). Besides increased TPS however, a pragmatic approach that revisits other factors such as minimum staking requirements and annual yields would help guide lower inflation on Flow, to be explained and addressed in a separate FLIP soon. + +![TPS-vs-Inflation](TPS-vs-Inflation.png) + +Third, this change would make FLOW’s use-cases more perceptible and established, further accentuating its stature as a token of value. The table below shows the average transaction fees of various networks vis-a-vis Flow in the current and proposed scenarios. Simply put, for every dollar that users would pay to transact on the Flow network, they currently pay $450 on NEAR, $300 on Solana, and $480,000 on ETH - for the same transaction(s). This differential would reduce 100x with the approval and implementation of this proposal, yet even with the implementation of the new fee structure, Flow would continue to remain an economically attractive network to transact on. Note that given FLOW market price’s high correlation with the listed tokens’ prices (”R” averaging 0.8+), even a change in FLOW token price or stochastic market volatility would not substantially alter the competitiveness of the proposed Flow fees compared to other networks, as can be seen in the last two columns of the table below. + +| Network | Current Avg txn fee | Current Multiple v/s Flow | Proposed avg txn fee | Proposed Multiple v/s Flow | Expected Multiple if FLOW/$ changes | +| --- | --- | --- | --- | --- | --- | +| ETH | $ 4.06E+00 | 480,882 times | $ 4.06E+00 | 4,808 times | 4,040 times | +| BSC | $ 1.97E-01 | 23,318 times | $ 1.97E-01 | 233 times | 182 times | +| Bitcoin | $ 9.68E-01 | 114,612 times | $ 9.68E-01 | 115 times | 940 times | +| Solana | $ 2.50E-03 | 296 times | $ 2.50E-03 | 3 times | 2.4 times | +| Avalanche | $ 1.12E-02 | 1,324 times | $ 1.12E-02 | 13 times | 10.6 times | +| Cardano | $ 1.24E-01 | 14,696 times | $ 1.24E-01 | 147 times | 120.5 times | +| NEAR | $ 3.80E-03 | 449 times | $ 3.80E-03 | 4.5 times | 3.4 times | +| FLOW | $ 1.21E-05 | N/A | $ 1.21E-03 | N/A | N/A | + +## **Final Word** + +Transaction fees offer many benefits in Flow network’s economic design, including compensating the node operators for the resources deployed to process transactions and secure the network, protecting the network against spamming attacks, and generating long-term stability in the Flow economy via reduced inflation. In a mature state, transaction fees should allow the Flow blockchain to self-regulate transaction throughput in a way where it would always approach optimal throughput. This proposal however is meant to be a starting point for community discussions on how an increase in inclusion fees and unit cost of execution effort could lead to network-wide benefits including economically deterring network attacks and strengthening the overall FLOW economy. The community is invited to share feedback on this post and help shape the economics of FLOW. + +## **Appendix 1** + +**Comparison** **of** **Flow v/s Solana transaction fees (current scenario) for specific transaction types** + +The table below demonstrates how Solana fees associated with different transaction types fare against Flow today, ranging from ~100x for empty transactions to 3x for an average contract deployment. + +| | Flow txn fee (US$) | Solana txn fee (US$) | SOL : Flow fee ratio | +| --- | --- | --- | --- | +| Empty Transaction | 1.11E-06 | 1.09E-04 | 98 X | +| Create 1 account | 3.49E-06 | 1.09E-04 | 31 X | +| Create 10 accounts | 2.51E-05 | 1.09E-03 | 44 X | +| Add key to account | 1.11E-06 | 1.09E-04 | 98 X | +| FT transfer | 2.05E-06 | 1.09E-04 | 53 X | +| Deploying a 50kB contract | 3.29E-05 | 1.09E-04 | 3 X | +| Mint a small NFT | 2.11E-06 | 1.09E-04 | 52 X | +1. *Note that Solana also has a [prioritization fees](https://docs.solana.com/terminology#prioritization-fee) which is not considered in the analysis below but is paid by ~48% of non-voting transactions.* +2. *Assumed 1 signature per transaction & Solana’s fee of 5000 Lamports per signature, where 1 Lamport = 1E-9 SOL; and 1SOL = US$ 21.07 (YTD moving average of SOL/US$ market price)* +3. *To create 10 accounts, 10 signatures for creation of 10 accounts were assumed* +4. *Solana-Flow multiple is calculated by dividing Solana txn fee for a transaction type by Flow txn fee for the same type* + +## Appendix 2 + +**Resources** + +[https://developers.flow.com/learn/concepts/variable-transaction-fees](https://developers.flow.com/learn/concepts/variable-transaction-fees) + +[https://developers.flow.com/nodes/staking/schedule#rewards-distribution](https://developers.flow.com/nodes/staking/schedule#rewards-distribution) + +[https://docs.solana.com/transaction_fees#basic-economic-design](https://docs.solana.com/transaction_fees#basic-economic-design) + +[https://docs.solana.com/terminology#prioritization-fee](https://docs.solana.com/terminology#prioritization-fee) + +[https://forum.onflow.org/t/flip-dynamic-inclusion-fees/3700](https://forum.onflow.org/t/flip-dynamic-inclusion-fees/3700) + +[https://github.com/onflow/flow/blob/c05d847adf2f6fb509e42c17020484d7dd3e89bd/flips/20220111-execution-effort.md](https://github.com/onflow/flow/blob/c05d847adf2f6fb509e42c17020484d7dd3e89bd/flips/20220111-execution-effort.md) + +[https://cryptofees.info/](https://cryptofees.info/) + +[https://www.theblock.co/data/scaling-solutions/evm-chains-stats/transaction-count-for-evm-chains](https://www.theblock.co/data/scaling-solutions/evm-chains-stats/transaction-count-for-evm-chains) + +[https://app.artemis.xyz/dashboard](https://app.artemis.xyz/dashboard) + +[http://www.coinmarketcap.com](http://www.coinmarketcap.com/) + +[https://ycharts.com/indicators/bitcoin_average_transaction_fee](https://ycharts.com/indicators/bitcoin_average_transaction_fee) + +[https://docs.bnbchain.org/docs/overview](https://docs.bnbchain.org/docs/overview) + +[https://solanacompass.com/statistics/fees](https://solanacompass.com/statistics/fees) + +[https://beta-analysis.solscan.io/public/dashboard/06d689e1-dcd7-4175-a16a-efc074ad5ce2](https://beta-analysis.solscan.io/public/dashboard/06d689e1-dcd7-4175-a16a-efc074ad5ce2)  + +[https://solscan.io/](https://solscan.io/) diff --git a/governance/TPS-vs-Inflation.png b/governance/TPS-vs-Inflation.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed197accb62474fd1ce7624b43d68c85d953ece GIT binary patch literal 67178 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

I`* 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 literal 0 HcmV?d00001 From 8055c20b30d41c5f3e3f5df3a34667f28a47131b Mon Sep 17 00:00:00 2001 From: "Bjarte S. Karlsen" Date: Tue, 6 Jun 2023 23:23:40 +0200 Subject: [PATCH 17/47] Update 20210916-nft-metadata.md (#100) --- application/20210916-nft-metadata.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/20210916-nft-metadata.md b/application/20210916-nft-metadata.md index e530ba60..353ce701 100644 --- a/application/20210916-nft-metadata.md +++ b/application/20210916-nft-metadata.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 636 authors: Bjarte Karslen (bjartek@find.xyz), Deniz Mert Edincik (Deniz@edincik.com), Brian Dilley (briandilley@briandilley.com) sponsor: Peter Siemens (peter@dapperlabs.com) From d663183d233f7e5aa48c6033ab4f7a943200589c Mon Sep 17 00:00:00 2001 From: Kshitij Chaudhary <78124453+KshitijChaudhary666@users.noreply.github.com> Date: Tue, 6 Jun 2023 18:29:19 -0400 Subject: [PATCH 18/47] Update 20220811-fungible-tokens-metadata.md (#109) Changing status from accepted > implemented Changes are deployed. See - https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenMetadataViews.cdc https://contractbrowser.com/A.f233dcee88fe0abe.FungibleTokenMetadataViews https://testnet.contractbrowser.com/A.9a0766d93b6608b7.FungibleTokenMetadataViews --- application/20220811-fungible-tokens-metadata.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/20220811-fungible-tokens-metadata.md b/application/20220811-fungible-tokens-metadata.md index 3388aa1d..f96c000e 100644 --- a/application/20220811-fungible-tokens-metadata.md +++ b/application/20220811-fungible-tokens-metadata.md @@ -1,5 +1,5 @@ --- -status: accepted +status: Implemented flip: 1087 authors: Álvaro Lillo Igualada (alvaro.lillo@dapperlabs.com) sponsor: Josh Hannan (joshua.hannan@dapperlabs.com) From ca626dd5bb7dfd8b837ab886660d6f5375b66209 Mon Sep 17 00:00:00 2001 From: Satyam Agrawal Date: Sun, 11 Jun 2023 11:55:53 +0530 Subject: [PATCH 19/47] Change status of FLIP-69 (#110) change status --- application/20230206-fungible-token-vault-type-discovery.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/20230206-fungible-token-vault-type-discovery.md b/application/20230206-fungible-token-vault-type-discovery.md index 66f14d7d..248ce9d7 100644 --- a/application/20230206-fungible-token-vault-type-discovery.md +++ b/application/20230206-fungible-token-vault-type-discovery.md @@ -1,5 +1,5 @@ --- -status: accepted +status: implemented flip: 69 authors: Satyam Agrawal (satyam.agrawal@dapperlabs.com) updated: 2023-02-06 From 62f193d554127d367e88393b8588f41ca814aebb Mon Sep 17 00:00:00 2001 From: Janez Podhostnik <67895329+janezpodhostnik@users.noreply.github.com> Date: Tue, 13 Jun 2023 17:25:08 +0100 Subject: [PATCH 20/47] Reject GOV-3 (#113) --- governance/20221005-dynamic-inclusion-fee.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/governance/20221005-dynamic-inclusion-fee.md b/governance/20221005-dynamic-inclusion-fee.md index 61cc873c..e8f42c8b 100644 --- a/governance/20221005-dynamic-inclusion-fee.md +++ b/governance/20221005-dynamic-inclusion-fee.md @@ -1,5 +1,5 @@ --- -status: proposed +status: rejected flip: GOV-3 forum: https://forum.onflow.org/t/flip-dynamic-inclusion-fees/3700 authors: Tony Zhang (tony.zhang@dapperlabs.com) From bfba41a8dc1d8dfd5b140e83390b60c34e25382b Mon Sep 17 00:00:00 2001 From: Supun Setunga Date: Mon, 19 Jun 2023 09:02:45 -0700 Subject: [PATCH 21/47] FLIP: Improve interface conformance (#83) * Add FLIP for improving interface conformance * Update to the new styling * Update status to 'accepted' --- cadence/20230503-improve-conformance.md | 100 ++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 cadence/20230503-improve-conformance.md diff --git a/cadence/20230503-improve-conformance.md b/cadence/20230503-improve-conformance.md new file mode 100644 index 00000000..7fbf55e2 --- /dev/null +++ b/cadence/20230503-improve-conformance.md @@ -0,0 +1,100 @@ +--- +status: accepted +flip: 83 +authors: Supun Setunga (supun.setunga@dapperlabs.com) +sponsor: Supun Setunga (supun.setunga@dapperlabs.com) +updated: 2023-06-19 +--- + +# FLIP 83: Improve interface conformance + +## Objective + +This FLIP proposes to relax a restriction associated with interface conformance, +by allowing conditions defined in other interfaces to coexist with a default function implementation coming from a +different interface. + +## Motivation + +Assume there are two interfaces, one (i.e: `Vault`) provides a default implementation to the `withdraw` function, +and the other (i.e: `ThrottledVault`) provides restrictions on how much can be withdrawn at a time. + +Now suppose an implementation need to conform to both of these interfaces. + +```cadence +pub resource interface Vault { + pub fun withdraw(_ amount: Int): @NFT { + // some default implementation + } +} + +pub resource interface ThrottledVault { + pub fun withdraw(_ amount: Int): @NFT { + pre { amount < 50 } + } +} + +pub resource MyVault: Vault, ThrottledVault { // Reports an error +} +``` + +Currently, this reports an error saying ``resource `MyVault` has conflicting requirements for function `withdraw` ``. + +## User Benefit + +It can be useful to have interfaces that only define restrictions, in the form of pre/post conditions. +Relaxing the current restriction allows user to use this pattern along with default functions. + +When interface inheritance is supported, the chance of running into similar situations would be more frequent. + +## Design Proposal + +Here it is proposed to relax the current restriction and allow conditions defined in other interfaces to coexist +with a default function implementation coming from other interfaces. + +```cadence +pub resource MyVault: Vault, ThrottledVault { // This would be valid + // `MyVault` would get the default implementation from `Vault` and the conditions from `ThrottledVault` +} +``` + +### Drawbacks + +None + +### Alternatives Considered + +None + +### Performance Implications + +None + +### Dependencies + +None + +### Engineering Impact + +This change is trivial in the implementation. + +### Compatibility + +This proposal suggests a relaxation of an existing restriction. Hence, no existing codes would break. + +### User Impact + +None + +## Related Issues + +None + +## Prior Art + +None + +## Questions and Discussion Topics + +None + From 067a19f70eb7dca21aa7194e69b93d8b0025d9db Mon Sep 17 00:00:00 2001 From: Supun Setunga Date: Mon, 19 Jun 2023 14:33:52 -0700 Subject: [PATCH 22/47] Add mutability restrictions vision (#97) Add mutability improvements vision --- cadence/vision/mutability-restrictions.md | 219 ++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 cadence/vision/mutability-restrictions.md diff --git a/cadence/vision/mutability-restrictions.md b/cadence/vision/mutability-restrictions.md new file mode 100644 index 00000000..a49875cb --- /dev/null +++ b/cadence/vision/mutability-restrictions.md @@ -0,0 +1,219 @@ +# Mutability Restrictions + +## Motivation + +A previous version of Cadence ("Secure Cadence") restricted the potential foot-gun of mutating container-typed +`let` fields/variables via the +[Cadence mutability restrictions FLIP](https://github.com/onflow/flips/blob/main/cadence/20211129-cadence-mutability-restrictions.md). + +However, there are still ways to mutate such fields by: +- Directly mutating a nested composite typed field. +- Mutating a field by calling a mutating function on the field. +- Mutating the field via a reference. + +More details on this problem is described in the [FLIP for improving mutability restrictions](https://github.com/onflow/flips/pull/58). + +## Problem in a nutshell + +Consider the below example: + +```cadence +pub resource MasterCollection { + pub let kittyCollection: @Collection + pub let topshotCollection: @Collection +} + +pub resource Collection { + pub(set) var id: String + pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + + pub fun deposit(token: @NonFungibleToken.NFT) { ... } +} +``` + +For owned values, despite the inner resources are declared with `let`: + +1) Can directly mutate `id` field of the nested resource. + + ```cadence + var masterCollection: MasterCollection <- ... + + masterCollection.kittyCollection.id = "NewID" + ``` + +2) Can call a mutating function on the nested field. + + ```cadence + var masterCollection: MasterCollection <- ... + + masterCollection.kittyCollection.deposit(<-nft) + ``` + +3) Can take a reference to the inner `ownedNFTs`, and update it. + + ```cadence + var masterCollection: MasterCollection <- ... + + let ownedNFTsRef = &masterCollection.kittyCollection.ownedNFTs as &{UInt64: NonFungibleToken.NFT} + destroy ownedNFTsRef.insert(key: 1234, <-nft) + ``` + +Similarly, for values that are not owned, i.e. when only a reference to the master collection is available, +the same set of problems exists. + +```cadence +var masterCollectionRef: &MasterCollection = ... + +// Directly updating the field +masterCollectionRef.kittyCollection.id = "NewID" + +// Calling a mutating function +masterCollectionRef.kittyCollection.deposit(<-nft) + +// Updating via the reference +let ownedNFTsRef = &masterCollectionRef.kittyCollection.ownedNFTs as &{UInt64: NonFungibleToken.NFT} +destroy ownedNFTsRef.insert(key: 1234, <-nft) +``` + +## Solution + +In order to solve these existing problems, three FLIPs have been proposed, that tackles the problem in tandem: +- [Change member-access semantics](https://github.com/onflow/flips/pull/89) +- [Introducing built-in entitlements](https://github.com/onflow/flips/pull/86) +- [Improve entitlement mappings](https://github.com/onflow/flips/pull/94) + +More details on each of these changes can be found in their respective FLIPs. +Here we are more interested in how they all work together to solve the aforementioned problems. + +Let's take a look at the same example, this time utilizing all three proposed changes. + +```cadence +pub resource MasterCollection { + access(KittyCollectorMapping) let kittyCollection: @Collection + access(TopshotCollectorMapping) let topshotCollection: @Collection +} + +pub resource Collection { + pub(set) var id: String + access(Identity) var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + + access(Insertable) fun deposit(token: @NonFungibleToken.NFT) { ... } +} + + +// Entitlements and mappings for `kittyCollection` + +entitlement KittyCollector + +entitlement mapping KittyCollectorMapping { + KittyCollector -> Insertable + KittyCollector -> Removable +} + +// Entitlements and mapings for `topshotCollection` + +entitlement TopshotCollector + +entitlement mapping TopshotCollectorMapping { + TopshotCollector -> Insertable + TopshotCollector -> Removable +} +``` + +#### Owned values + +All mutations are possible for owned values. + +```cadence +var masterCollection: MasterCollection <- ... + +// Directly updating the field +masterCollection.kittyCollection.id = "NewID" + +// Directly updating the dictionary. +// Note that this wasn't possible before. +destroy masterCollection.kittyCollection.ownedNFTs.insert(key: 1234, <-nft) +destroy masterCollection.kittyCollection.ownedNFTs.remove(key: 1234) + +// Calling a mutating function +masterCollection.kittyCollection.deposit(<-nft) + +// Updating via the reference +let ownedNFTsRef = &masterCollectionRef.kittyCollection.ownedNFTs as &{UInt64: NonFungibleToken.NFT} +destroy ownedNFTsRef.insert(key: 1234, <-nft) +``` + +It is true that this still allows mutating nested fields, even the parent is declared with `let`. +But on contrary, `let` fields by-definition states that no new value can be assigned, but isn't designed to prevent +inner mutations. +This is the same behavior for most existing languages including, but not limited to, Java, Swift, etc. + +Also, if someone owns the outer value, they can create a reference to an inner field with any desired entitlement, +which then allows mutations as defined in the entitlement-access. +Thus, it doesn't make much sense to prevent mutations to the owned values, since it'll be anyway possible by taking +a reference with required entitlements. + +#### Reference values + +On the other hand, when a reference is created, entitlements are used to control what can be accessed and what +can be modified, via the reference. +Therefore, the end goal is to streamline the use of entitlements to control mutations for nested fields as well, +when accessed through a reference. + +#### Reference values, with no entitlements + +Without entitlements, all fields return non-auth references. i.e. All fields are read only. + +```cadence +var masterCollectionRef: &MasterCollection <- ... + +// Error: Cannot update the field. Doesn't have sufficient entitlements. +masterCollectionRef.kittyCollection.id = "NewID" + +// Error: Cannot directly update the dictionary. Doesn't have sufficient entitlements. +destroy masterCollectionRef.kittyCollection.ownedNFTs.insert(key: 1234, <-nft) +destroy masterCollectionRef.ownedNFTs.remove(key: 1234) + +// Error: Cannot call mutating function. Doesn't have sufficient entitlements. +masterCollectionRef.kittyCollection.deposit(<-nft) + +// Error: `masterCollectionRef.kittyCollection.ownedNFTs` is already a non-auth reference. +// Thus cannot update the dictionary. Doesn't have sufficient entitlements. +let ownedNFTsRef = &masterCollectionRef.kittyCollection.ownedNFTs as &{UInt64: NonFungibleToken.NFT} +destroy ownedNFTsRef.insert(key: 1234, <-nft) +``` + +#### Reference values, with entitlements + +Entitlement states what mutations can be done on which fields. +Here, if an `auth{KittyCollector}` reference is available for `&MasterCollection`, then the returned `kittyCollection` +reference is entitled to `Insertable` and `Removable` operations. +Given `ownedNFT` field has `access(Identity)`, any entitlement available for `kittyCollection` field will be available +to the nested `ownedNFT` field as well. + +Thus, all the following operations are valid. + +```cadence +var masterCollectionRef: auth{KittyCollector} &MasterCollection <- ... + +// Directly updating the field +masterCollectionRef.kittyCollection.id = "NewID" + +// Updating the dictionary +destroy masterCollectionRef.kittyCollection.ownedNFTs.insert(key: 1234, <-nft) +destroy masterCollectionRef.kittyCollection.ownedNFTs.remove(key: 1234) + +// Calling a mutating function +masterCollectionRef.kittyCollection.deposit(<-nft) +``` + +Note that, given the reference has entitlements only for `KittyCollector`, and because `TopshotCollectorMapping` has +no entries to that maps `KittyCollector` to anything, the accessing the field `topshotCollection` would return a +non-auth reference. +This doing any updates to the `topshotCollection` would be restricted. + +```cadence +var masterCollectionRef: auth{KittyCollector} &MasterCollection <- ... + +masterCollectionRef.topshotCollection.ownedNFTs.insert(key: 1234, <-nft) +``` From c14ad7fff2ec7ecf6d14e412f7267b8eeb4bf915 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 20 Jun 2023 13:07:29 -0400 Subject: [PATCH 23/47] accept flip --- cadence/20230505-remove-priv-and-pub.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cadence/20230505-remove-priv-and-pub.md b/cadence/20230505-remove-priv-and-pub.md index 23651c8f..d020508e 100644 --- a/cadence/20230505-remove-priv-and-pub.md +++ b/cadence/20230505-remove-priv-and-pub.md @@ -1,5 +1,5 @@ --- -status: proposed +status: accepted flip: 84 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) @@ -42,6 +42,9 @@ that exists, as it is extremely unlikely that there is any code on Mainnet curre does not use at least one `pub` modifier. However, as discussed in the next section, this may be an benefit rather than a drawback. +Additionally, any existing `pub(set)` fields will need to be replaced with `access(all)` fields, and be given +a setter function explicitly in order to regain their previous functionality. + ### Compatibility This is not backwards compatible, and will indeed break every existing contract. However, From 65b475ac70b8ecc015556976c6b8dc31d456a4b2 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 20 Jun 2023 13:07:45 -0400 Subject: [PATCH 24/47] FLIP for removing `pub`, `pub(set)` and `priv` (#84) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add FLIP * add language proposing the removal of pub(set) * more info about removing pub set * Update cadence/2023-05-05-remove-priv-and-pub.md Co-authored-by: Bastian Müller * rename * accept flip --------- Co-authored-by: Bastian Müller --- cadence/20230505-remove-priv-and-pub.md | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 cadence/20230505-remove-priv-and-pub.md diff --git a/cadence/20230505-remove-priv-and-pub.md b/cadence/20230505-remove-priv-and-pub.md new file mode 100644 index 00000000..d020508e --- /dev/null +++ b/cadence/20230505-remove-priv-and-pub.md @@ -0,0 +1,64 @@ +--- +status: accepted +flip: 84 +authors: Daniel Sainati (daniel.sainati@dapperlabs.com) +sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) +updated: 2023-05-05 +--- + +# FLIP 84: Remove `pub` and `priv` aliases for access modifiers + +## Objective + +This FLIP proposes to remove the `pub` alias for `access(all)` and the `priv` +modifier for `access(self)`, requiring all code to use these longer forms instead +of the shortened ones. + +This also proposes to remove the `pub(set)` access keyword, which was previously used to make +variables publicly settable. This is not a common case, and in order to simplify the language, +we also propose to remove it. If users wish to have a field be publicly settable, they should write +a public mutator function for that field. + +## Motivation + +The proposed entitlements changes in [the entitlements FLIP](https://github.com/onflow/flips/pull/54) +will add a new `access(X)` modifier for entitled access, which will likely be used frequently +in many contracts. It would be more consistent with this new `access(X)` syntax for `pub` +and `priv` to be `access(all)` and `access(self)` respectively. + +## User Benefit + +This will increase the readability and consistency of user code. + +## Design Proposal + +The proposal is simple: just remove the `pub` and `priv` aliases. `pub(set)` will +also be removed. + +### Drawbacks + +This will increase the verbosity of all code, as well as break every single contract +that exists, as it is extremely unlikely that there is any code on Mainnet currently that +does not use at least one `pub` modifier. However, as discussed in the next section, this may be +an benefit rather than a drawback. + +Additionally, any existing `pub(set)` fields will need to be replaced with `access(all)` fields, and be given +a setter function explicitly in order to regain their previous functionality. + +### Compatibility + +This is not backwards compatible, and will indeed break every existing contract. However, +given that the aforementioned entitlements change is also going to require a rewrite of all +code currently deployed to Mainnet, a change such as this that statically breaks all of that code +will alert developers that changes are required, rather than allowing potentially newly unsafe +code to slip through undetected. + +### User Impact + +This is going to require all code to be updated to not use the deprecated modifiers. It would +be possible to write a migration assistant that would automatically replace the `pub` and `priv` +modifiers with their equivalent long forms, but it is unclear if we would want to do this, given +that a stated goal of this change is to make developers manually consider which `pub` methods are +truly `access(all)` and which should be rewritten to use entitlements. + +## Questions and Discussion Topics From 395a1120524e362c815803fc8edff81c804a6a98 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 21 Jun 2023 09:50:43 -0400 Subject: [PATCH 25/47] FLIP for removing restricted types (#85) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add flip * Update cadence/2023-05-05-remove-restricted-types.md Co-authored-by: Bastian Müller * add info about migration of entitled references * Update cadence/2023-05-05-remove-restricted-types.md Co-authored-by: Bastian Müller * rename * respond to review * Update cadence/20230505-remove-restricted-types.md --------- Co-authored-by: Bastian Müller --- cadence/20230505-remove-restricted-types.md | 69 +++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 cadence/20230505-remove-restricted-types.md diff --git a/cadence/20230505-remove-restricted-types.md b/cadence/20230505-remove-restricted-types.md new file mode 100644 index 00000000..a1f2aef1 --- /dev/null +++ b/cadence/20230505-remove-restricted-types.md @@ -0,0 +1,69 @@ +--- +status: accepted +flip: 85 +authors: Daniel Sainati (daniel.sainati@dapperlabs.com) +sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) +updated: 2023-05-05 +--- + +# FLIP 85: Replace Restricted Types with Interface Set Types + +## Objective + +Currently in Cadence, a restricted type consists of a type (often confusingly also called +the restricted type) and a set of interface types that serve as its restrictions. Written `T{I1, I2, ...}`, +this type indicates a value of type `T`, but restricted such that only members present on one of the `I`s +can be accessed. This FLIP proposes to remove the `T` portion of the type, changing this type to simply +indicate some value of a type that conforms to each of the `I`s. + +## Motivation + +The proposed entitlements changes in [the entitlements FLIP](https://github.com/onflow/flips/pull/54) make +restricted types mostly useless in their current form. Previously they existed as a form of access control for references, +as a restricted reference type could not be downcast, so a restriction set functioned for references like access control, +limiting what functionality was available to a reference. + +The entitlements changes will move this functionality to entitlements, and allow downcasting references, making +this behavior unnecessary. However, it will still be valuable to allow the specification of "interface set" types, +for the purposes of polymorphism, so by removing the outer `T` component of the restricted type `T{I1, I2, ...}`, we +can replace this obseleted type form with a simpler interface set type that handles the polymorphism use case. + +## User Benefit + +This will simplify the language by removing a redundant and poorly understood feature. + +## Design Proposal + +This would remove the "restricted type" portion of the restricted type. Users will no longer be able to write types with a `T` in +the `T{I}` position of an old restricted type. + +For the new semantics of the interface set type, we can use the existing semantics of the `AnyStruct{X}` and `AnyResource{Y}` restricted types, +as these contain no information about the type being restricted, and thus function only as restrictions on a generic type. + +The semantics of upcasting and downcasting restricted types will remain the same; they will be covariant in their interface sets. + +Existing references and capabilities could be migrated by replacing the restricted type with the outer type, i.e. converting `T{I}` to `T`. +In combination with the incoming entitlement changes, where the old "restricted" behavior would be recaptured with entitlements, this would +be able to preserve existing behavior. In particular, in the case of references, the entitlements present on the interfaces would be granted to the +reference type. + +For example, an existing `&Vault{Withdraw}` value would be migrated to a `auth(Withdrawable) &Vault` reference + +### Drawbacks + +This is not backwards compatible, and will break existing restricted types that have non-trivial values for their outer type. + +### Alternatives Considered + +We could simply leave restricted types as-is, which would break nothing, but would leave restricted types in the language +as a vestigial feature without much of a use case. + +### Compatibility + +This is not backwards compatible. + +### User Impact + +As users are already going to be needing to rethink their restricted types as they migrate their contracts to use +entitlements, this is unlikely to significantly increase the engineering burden of upgrading their contracts to Stable +Cadence. From e244a20a7c35d7d105a377f36264d6e868474416 Mon Sep 17 00:00:00 2001 From: Supun Setunga Date: Wed, 21 Jun 2023 09:28:37 -0700 Subject: [PATCH 26/47] Emit events from function conditions (#111) * Events emitted from interfaces * flip reference * status update * Update flips/20230417-events-emitted-from-interfaces.md Co-authored-by: Joshua Hannan * Update flips/20230417-events-emitted-from-interfaces.md Co-authored-by: Joshua Hannan * Update flips/20230417-events-emitted-from-interfaces.md Co-authored-by: Joshua Hannan * Update proposal to stress on allowing event emission from conditions * Add section on emitting events in view functions * Update note on view functions * Update status --------- Co-authored-by: Deniz Mert Edincik Co-authored-by: Joshua Hannan --- ...20230417-events-emitted-from-interfaces.md | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 cadence/20230417-events-emitted-from-interfaces.md diff --git a/cadence/20230417-events-emitted-from-interfaces.md b/cadence/20230417-events-emitted-from-interfaces.md new file mode 100644 index 00000000..65e44a04 --- /dev/null +++ b/cadence/20230417-events-emitted-from-interfaces.md @@ -0,0 +1,117 @@ +--- +status: accepted +flip: 111 +authors: Deniz Mert Edincik (deniz@edincik.com) / Supun Setunga (supun.setunga@dapperlabs.com) +sponsor: Deniz Mert Edincik (deniz@edincik.com) / Supun Setunga (supun.setunga@dapperlabs.com) +updated: 2023-06-21 +--- + +# FLIP 111: Emit events from function conditions + +## Objective + +The objective of this proposal is to allow emitting events from function pre/post conditions. + +## Motivation + +Currently, though interfaces can declare events, they act as a type-requirement for the implementations, +and cannot be used to emit events using `emit` statement. +Also, there is no way for the interfaces to guarantee the emission of an event. +Instead, the implementation of the interface needs to re-declare the same event, and then emit events as needed. + +The current approach not only put the burden on the implementor to emit the event, +but also can lead to potential issues with events, such as: +- Emission of incorrect events +- Events with improper parameters +- Multiple emissions of the same event +- Omission of necessary events + +## User Benefit + +Interfaces can ensure the emission of proper events, and can take that burden off the implementation. + +## Design Proposal + +As per the objectives, the solution proposed in this FLIP is to allow emitting events inside pre/post conditions. +This allows interfaces to guarantee the emission of events, when a function (defined in the interface) is called. + +### Example: + +Suppose the `FungibleToken` is a contract, and has a `TokenWithdrawal` event declared in it. + +With function pre/post conditions being able to emit events, the `withdraw` function would look like below. + +```cadence +pub contract FungibleToken { + + pub event TokenWithdrawal(type: Type, amount: UFix64, from: Address?) + + pub resource interface Provider{ + pub fun withdraw(amount: UFix64): @{FungibleToken.Vault} { + post { + result.balance == amount: "Withdrawal amount must be the same as the balance of the withdrawn Vault" + emit TokenWithdrawal(type:type, amount:amount, from:from) + } + } + } +} +``` + +Here, everytime the `withdraw` is invoked, an `TokenWithdrawal` event will be emitted. +Thus, the interface can ensure the proper event is emitted, and can take that burden off the implementation. + +### Caveats + +In the [FLIP for 'view' functions](https://github.com/onflow/flips/blob/main/cadence/20220715-cadence-purity-analysis.md), +function conditions were considered to be `view`, which restricts the modification of the state inside a condition. +While the emission of events has been categorized as an operation with side effects, it also notes that emitting events +is permitted in the proposed design, as they are not observable. + +### Drawbacks + +The proposed solution doesn't possess any known drawbacks. + +### Alternatives Considered + +N/A + +### Performance Implications + +There will be no impact on performance since this simply move the emission of events from one location to another. + +### Dependencies + +None + +### Engineering Impact + +This feature would be relatively simple to implement. + +### Best Practices + +This introduces a new best practice, allowing interface owners the option to emit their own events. +Additionally, contracts can define their own events that complement the existing ones. + +### Compatibility + +This solution is backwards compatible. + +Existing contracts would still emit their old events in addition to these new events, so any event listeners would not +be affected by these changes except for if they wanted to listen to new contracts that did not emit their own events. + +### User Impact + +None + +## Related Issues + +https://github.com/onflow/cadence/issues/2069 + +## Prior Art + +N/A + +## Questions and Discussion Topics + +- Is it still a requirement to allow interfaces to declare concrete events (not just type requirements), +and being able to use those events in `emit` statements? From 1b0c04ec85267482131d34a5d613774976e8a3fd Mon Sep 17 00:00:00 2001 From: Joshua Hannan Date: Thu, 22 Jun 2023 13:19:23 -0500 Subject: [PATCH 27/47] FLIP78- Delegator Staking Minimum (#78) * delegator minimum FLIP * change minimum to 50 and make it staking minimum, not rewards * update status and date --- protocol/20230403-delegator-minimum.md | 123 +++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 protocol/20230403-delegator-minimum.md diff --git a/protocol/20230403-delegator-minimum.md b/protocol/20230403-delegator-minimum.md new file mode 100644 index 00000000..4d3bfa4b --- /dev/null +++ b/protocol/20230403-delegator-minimum.md @@ -0,0 +1,123 @@ +--- +status: Implemented +flip: FLIP-78 +authors: Joshua Hannan (joshua.hannan@dapperlabs.com) +sponsor: Joshua Hannan (joshua.hannan@dapperlabs.com) +updated: 2023-06-22 +--- + +# Delegator Staking Minimum + +## Objective + +Introduce a minimum required stake (50 FLOW) +for staking delegators in the Flow protocol and staking smart contracts. + +## Motivation + +Delegators were proposed as an easy way to participate +in the security of the network and earn staking rewards +without having to run a node or commit much capital for extended periods of time. + +While delegators aren't directly critical to the core functioning +of the network, as a group, they provide a signaling function of trusted nodes +and trust in the network generally. Delegators have been staked +in the identity table and choose a specific node to delegate to. +They can delegate any amount of FLOW and will receive rewards proportional to the +amount of FLOW they delegate. + +Unfortunately, the low barriers to entry take a toll on the network. +Since there are so many delegators in the identity table, epoch transition operations +such as moving tokens between buckets and paying rewards are costly +and time-consuming. The network also has to pay for storage +for each delegator regardless of how much they stake. + +Currently, there are over 16k delegators in the network, which means that nearly +50k events are emitted for each delegator when their rewards are paid because each delegator +gets a `FlowToken.TokensWithdrawn`, `FlowToken.TokensDeposited`, and `FlowIDTableStaking.DelegatorRewardsPaid` +event. Over 28k of those are for amounts less than 0.1 FLOW, which is very wasteful for such a small amount. + +You can find these amount by using this command on the command line: + +``` +curl -s https://rest-mainnet.onflow.org/v1/transaction_results/84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 \ +| jq '.events | map(select( .type == "A.1654653399040a61.FlowToken.TokensDeposited" )) | map(.payload | @base64d | fromjson) | map(select((.value.fields[0].value.value | tonumber) > 0.1)) | length' +``` + +You'll need to multiply the result by three to get the total number of events for each +delegator above the specified rewards amount. + +This FLIP proposes increasing the delegator staking minimum to 50 FLOW +to avoid more unnecessary storage usage +and iterations and events for small staking and reward amounts. + +The number of staked FLOW proposed for minimum rewards was chosen because it is +a reasonable value to prevent DOS attacks and is less than the minimum stake for access nodes. +It makes creating thousands of empty delegations prohibitively expensive. + +It currently will cut down the number of rewards events emitted by almost two-thirds. +It is also still affordable at current FLOW prices. +With current rewards calculations, this means that the minimum amount of rewards +that a delegator can receive in an epoch is 0.1 FLOW. + +This value can definitely change in the future if network and economic changes require it. + +## User Benefit + +This change would benefit everyone using the network because the rewards transaction will +no longer take multiple seconds to execute. + +It will also benefit applications who are monitoring the network for events because it will drastically +reduce the number of events in this transaction, making it easier to parse and store. + +## Design Proposal + +In `FlowIDTableStaking.moveTokens()`, for each delegator, check that their committed balance +is above the minimum. If not, unstake their tokens. + +In `FlowIDTableStaking.calculateRewards()`, add a conditional that only +calculates rewards for a delegator if their `tokensStaked` is greater than 50 FLOW. + +The service account committee runs a transaction, +[`set_minimums.cdc`](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/admin/change_minimums.cdc) +to set the delegator minimum to the desired value. +The key for delegators in the minimums dictionary will be `0`. + +### Drawbacks + +This makes staking as a delegator slightly more expensive. + +### Alternatives Considered + +This doesn't fully address the issue of too many iterations and events in the staking +contract, but is an important short term solution +while other more complex changes can be designed and implemented. + +These include: +* Reducing the size of events in the protocol (will be live later in 2023) +* removing the unnecessary `FlowToken` events from these transactions completely + with a cadence flag only usable by the service account to not emit events. (FLIP in progress) +* Breaking up reward payments into batches to reduce event amount per transaction. (currently being explored) + +### Performance Implications + +This will significantly improve the performance of the epoch rewards payment transaction. + +### Dependencies + +This change will not affect any standard transactions, scripts, or events. + +### Engineering Impact + +This is a small change that can be easily tested and maintained. + +### User Impact + +* This will be rolled out with an upgrade to the staking contract +and a transaction to set the staking minimum for delegators. + +## Related Issues + +## Questions and Discussion Topics + +Is the staking minimum reasonable for delegators? From 81ae4a44ab6d2e2f01448147b729cce46d6cfd33 Mon Sep 17 00:00:00 2001 From: Supun Setunga Date: Fri, 23 Jun 2023 08:37:01 -0700 Subject: [PATCH 28/47] Improve entitlement mappings (#94) * Add proposal to improve entitlements * Extract identity mapping to a separate section. Improve FLIP in general * Add reference to the 'vision' * Update status --- cadence/20211129-entitlement-improvements.md | 233 +++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 cadence/20211129-entitlement-improvements.md diff --git a/cadence/20211129-entitlement-improvements.md b/cadence/20211129-entitlement-improvements.md new file mode 100644 index 00000000..9fa55a62 --- /dev/null +++ b/cadence/20211129-entitlement-improvements.md @@ -0,0 +1,233 @@ +--- +status: accepted +flip: 94 +authors: Supun Setunga (supun.setunga@dapperlabs.com) +sponsor: Supun Setunga (supun.setunga@dapperlabs.com) +updated: 2023-06-23 +--- + +# FLIP 94: Entitlements Improvements + +## Objective + +The main objective of this proposal is to improve entitlement mappings and their use-cases by: +- Allowing use of [entitlement mappings](https://github.com/onflow/flips/blob/main/cadence/20221214-auth-remodel.md#entitlement-mapping-and-nested-values) + for composite fields. +- Introducing an "Identity mapping", which is a shorthand syntax for mapping a given entitlement to the same entitlement. + +## Motivation + +### Motivation I: Cannot use entitlement mappings for non-reference fields + +With the [FLIP for changing member access semantics](https://github.com/onflow/flips/pull/89), +fields of a composite value would return a non-auth reference when accessed via a reference to the composite value. +However, currently, entitlement mappings can only be used for functions, and reference typed field, +but not to non-reference typed fields. + +```cadence +access(M) let refField: auth(M) &T // OK + +access(M) let field: T // Not allowed +``` + +As such, there's no way to specify to return an auth-reference for fields through member-access syntax, +if the field is a non-reference. +Users would have to write delegator functions to achieve the same, which adds unnecessary boilerplate code. + +### Motivation II: Mapping entitlements to themselves is cumbersome + +There can be use-cases where entitlements are needed to be delegated down to nested objects. +In other words, entitlement mapping may need to map an arbitrary entitlement `E` to the same entitlement `E`. +e.g: + +```cadence +entitlement mapping M { + Mutable -> Mutable + Insertable -> Insertable + Removable -> Removable +} +``` + +However, currently it is a bit cumbersome to write such a mapping, and also, it would require knowing all possible +entitlements beforehand. + +### Bigger Picture + +These two changes are also intended on improving the user experience of existing mutability restrictions. +The [Mutability Restrictions Vision](https://github.com/onflow/flips/pull/97) explains how this proposed change +contributes to improving the solution to the existing issue with mutability restrictions, +and how the final solution looks like, with examples. + +## User Benefit + +Provides a simple and shorthand syntax to achieve above-mentioned use-cases and thus, prevents developers from writing +a lot of boilerplate code. + +## Design Proposal + +### Allow entitlement mappings on fields + +The proposal is to allow entitlement mappings on composite fields. +For example, below code would now be valid. + +```cadence +entitlement mapping M { + Mutable -> Insertable +} + +pub resource Collection { + access(M) var ownedNFTs: @{UInt64: NFT} +} +``` + +#### Case I: Code only has a reference to the container value + +Assume an `auth{Mutable}` reference to the collection `mutableCollectionRef` is available. +Because `ownedNFTs` has an entitlement mapping access (i.e. `access(M)`), `mutableCollectionRef.ownedNFTs` would now +return a reference of type `auth{Insertable} &{UInt64: NFT}`. i.e: + +```cadence +var mutableCollectionRef: auth{Mutable} &Collection = ... + +var ownedNFTsRef: auth{Insertable} &{UInt64: NFT} = mutableCollectionRef.ownedNFTs +``` + +This will allow inserting values to the `ownedNFTs` fields, via `mutableCollectionRef.ownedNFTs`. + +```cadence +mutableCollectionRef.ownedNFTs.append(<-nft) // OK +``` + +This massively reduces the boilerplate could a developer would have to if they are to achieve the same by writing +a function. + +#### Case II: Code owns the container value + +Assume `collection` is of type `Collection`. i.e. the code owns the value. +Then, there is no change to the current behavior. + +```cadence +var collection: @Collection <- ... + +// `collection.ownedNFTs` would return the concrete value, which is of type `@{UInt64: NFT}`. +// This is same as existing semantics. +// Also note that, this is an error because it is not possible to move nested resource. +var ownedNFTs: @{UInt64: NFT} <- collection.ownedNFTs +``` + +### Syntax for identity mapping + +The idea of this change is to introduce a syntax to represent "identity mapping", which denotes mapping of an arbitrary +entitlement `E` to the same entitlement `E`, without having to explicitly specify what the source (domain) and the +target (range) of the mapping are. +This saves the trouble of developers having to map each and every such entitlement explicitly. + +The proposed solution consist of two parts. + +#### Part I: Built-in 'Identity' entitlement mapping + +A built-in entitlement mapping `Identity` is introduced, which maps any arbitrary entitlement to itself. +For example, inplace of using a custom mapping like below, developers can use the `Identity` entitlement mapping. + +```cadence +entitlement mapping M { + Mutable -> Mutable + Insertable -> Insertable + E1 -> E1 + E2 -> E2 +} + +pub resource Foo { + access(M) fun someFunction() +} +``` + +Can be also written as: + +```cadence +pub resource Foo { + access(Identity) fun someFunction() +} +``` + +An added benefit of the proposed syntax is, developers wouldn't need to know or explicitly specify all the possible +entitlements that needs to be included in the mapping, beforehand. + +#### Part II: Entitlement composition + +There can be situations where a developer wants to re-use existing entitlement mappings, but also, rather than just +using them as-is, it might be needed to combine them with some new mapping entries. + +The `include` keyword lets developers include all entries from another mapping, to their own mapping. + +For an example: + +```cadence +entitlement mapping M { + include Identity + + Insertable -> Mutable + Removable -> Mutable +} +``` + +The above mapping states that, any entitlement will map to itself, but also the two additional mapping entries would +also be in effect. + +Entitlement composition is not limited to the `Identity` entitlement. +The `include` keyword can be used to combine any arbitrary set of entitlement mappings. + + +```cadence +entitlement mapping M1 { + Removable -> Mutable +} + +entitlement mapping M2 { + Insertable -> Mutable +} + +entitlement mapping M3 { + include M1 + include M2 +} +``` + + +### Drawbacks + +This is an improvement to the existing feature. +There aren't any known drawbacks at this point of time. + +### Alternatives Considered + +N/A + +### Performance Implications + +N/A + +### Best Practices + +N/A + + +### Compatibility + +This is a feature addition to the existing entitlements feature. + +### User Impact + +This is a feature addition to the existing entitlements feature. + +## Related Issues + +N/A + +## Prior Art + +N/A + +## Questions and Discussion Topics + +N/A From 1b7d29637c427ed3d157e452fdff2b9300536f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 26 Jun 2023 12:30:13 -0700 Subject: [PATCH 29/47] Rename 20211129-entitlement-improvements.md to 20230623-entitlement-improvements.md --- ...ement-improvements.md => 20230623-entitlement-improvements.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cadence/{20211129-entitlement-improvements.md => 20230623-entitlement-improvements.md} (100%) diff --git a/cadence/20211129-entitlement-improvements.md b/cadence/20230623-entitlement-improvements.md similarity index 100% rename from cadence/20211129-entitlement-improvements.md rename to cadence/20230623-entitlement-improvements.md From 374b46d5322769dd8fa4251e4e834ccf6948a441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 26 Jun 2023 12:47:14 -0700 Subject: [PATCH 30/47] Port FLIP 1043 (#115) * Add files via upload * adjust frontmatter --- ...0220708-resource-reference-invalidation.md | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 cadence/20220708-resource-reference-invalidation.md diff --git a/cadence/20220708-resource-reference-invalidation.md b/cadence/20220708-resource-reference-invalidation.md new file mode 100644 index 00000000..b1eb3cca --- /dev/null +++ b/cadence/20220708-resource-reference-invalidation.md @@ -0,0 +1,181 @@ +--- +status: implemented +flip: 1043 +authors: Supun Setunga (supun.setunga@dapperlabs.com) +sponsor: Supun Setunga (supun.setunga@dapperlabs.com) +updated: 2022-10-03 +--- + +# FLIP 1043: Invalidate References to Transferred Resources + +## Objective + +This proposal is to introduce an invalidation for ephemeral reference values in Cadence, if the referred-to resource is +"transferred" after the reference was created. +Transferring is the act of moving a resource from outside account storage (stack) into account storage, moving from +the storage of one account to the storage of another account, or moving out of account storage (to the stack). + +The objective is to avoid a potential foot-gun of accidentally gaining/retaining access to a resource that a user +does not own. + +## Motivation + +When a reference is taken to a resource, that reference remains valid even if the resource was transferred. +In other words, references stay alive forever. + +For example, consider the following resource. + +```cadence +resource R { + pub(set) var id: Int + + init() { + self.id = 1 + } +} +``` + +Now, create an instance from the above resource, then take a reference to it, and finally transfer it to an account. +The transferred resource can still be accessed via the reference taken prior to the transfer. + +```cadence +// Create a resource. +let r <-create R() + +// And take a reference. +let ref = &r as &R + +// Then transfer the resource into an account. +account.save(<-r, to: /storage/r) + +// Update the reference. +// This will also update the referring resource in the account. +ref.id = 2 +``` + +In the above example, resource `r` was initially created on the stack and was not owned by anyone. +But similarly, it is also possible for someone to take a reference to a resource in their account, and transfer the +resource to someone, and keep accessing the transferred resource through the reference. +```cadence +// Create a resource collection in 'foo' account +fooAccount.save(<-[<-create R()], to: /storage/a) + +// Take a ephemeral reference to the resource at index '0' in the collection. +// Resource is in the 'foo' account at the time of taking the reference. +let collectionRef = fooAccount.borrow<&[R]>(from: /storage/a)! +let ref = &collectionRef[0] as &R + +// Transfer the entire collection to the 'bar' account. +let collection <- fooAccount.load<@[R]>(from: /storage/a)! +barAccount.save(<- collection, to: /storage/b) + +// Can still access the transferred resource through the reference. +ref.id = 2 +``` + +## User Benefit +This proposal would avoid a potential foot-gun of gaining/giving/retaining unintended access to resources through +references. + +## Implementation Benefit +The current implementation of Cadence resource reference tracking requires a lot of bookkeeping in order to ensure +that the references to resources point to the correct resource, when the referred-to resource value is moved around. +With this proposal, such bookkeeping would no longer be required and the implementation complexity could be eliminated. + +## Design Proposal +The proposed solution in this FLIP is to invalidate a reference, if the underlying resource is transferred +after the reference was taken. +The reference is invalidated upon the first transfer, regardless of the origin and the destination. + +There can be different types of transfers, depending on the origin (where the reference was obtained), and the +destination. + +| Origin | Destination | +|:--------|:------------------| +| Stack | Stack | +| Stack | Account | +| Account | Stack | +| Account | Same Account | +| Account | Different Account | + +All of the above type of transfers of a resource will cause any reference taken against that particular resource to be invalid. + +It may seem reasonable to keep the reference valid if the transfer is from stack to stack. +However, it can also possess a potential foot-gun for certain cases. +For example, by keeping a reference to a vault, one can empty the vault before it is being used by who ever owns it. +Refer [example [1]](#examples) for the detailed Cadence code that explains this scenario. + +With this change, trying to use variable `ref` in the above two examples will produce a run-time error, +causing the program to terminate. +```cadence +ref.id = 2 // Will produce a run-time error +``` + +### Drawbacks +- This is a breaking change, and developers will have to update their codes. Many existing contracts may be affected. + +### User Impact + +Developers will have to update their code to remove the use of references to moved resources. +If they still want a reference to the resource after move, they will have to obtain a new reference. + +### Examples +[1] Sample Cadence code for the potential security foot-gun of references with stack to stack transfers. +```cadence +access(all) contract Buyer { + + pub fun buy() { + let receiver: &Receiver ... + let vault: @Vault ... + + // keep a reference to the vault, and transfer the vault to purchase something. + receiver!.vaultRef = &vault as &Vault + + Seller.purchaseNFT(receiver, <-vault) + } + + pub resource Receiver { + priv let vaultRef: &Vault? + priv let secretVault: @Vault + + pub fun deposit(_ something: @AnyResource) { + self.steal() + destroy something + } + + pub fun steal() { + let stolen <- self.vaultRef!.withdraw(50) + self.secretVault.deposit(<- stolen) + } + } + + pub resource Vault { + pub var balance: Int + + pub fun withdraw(_ amount: Int): @Vault { + self.balance = self.balance - amount + return <- create Vault(amount) + } + + pub fun deposit(_ from: @Vault) { + self.balance = self.balance + from.balance + destroy from + } + } +} +``` + +```cadence +access(all) contract Seller { + + pub fun purchaseNFT(_ receiver: &Receiver, _ vault: @Vault) { + pre { + vault.balance >= sellingPrice + } + + receiver.deposit(<- create NFT()) // receiver will drain money from vault via the vault-reference + + self.vault.deposit(<-vault) + } +} +``` From 5725606efbbfae9f72b9ca5c490c3e9ef9b956e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 26 Jun 2023 13:17:37 -0700 Subject: [PATCH 31/47] port Cadence FLIPs --- cadence/20220725-cadence-borrowContract.md | 77 ++++ cadence/20220817-extensibility.md | 439 +++++++++++++++++++ cadence/20220908-publish-claim-capability.md | 149 +++++++ 3 files changed, 665 insertions(+) create mode 100644 cadence/20220725-cadence-borrowContract.md create mode 100644 cadence/20220817-extensibility.md create mode 100644 cadence/20220908-publish-claim-capability.md diff --git a/cadence/20220725-cadence-borrowContract.md b/cadence/20220725-cadence-borrowContract.md new file mode 100644 index 00000000..51415fde --- /dev/null +++ b/cadence/20220725-cadence-borrowContract.md @@ -0,0 +1,77 @@ +--- +status: implemented +flip: 1071 +authors: Deniz Mert Edincik (deniz@edincik.com) +sponsor: Austin Kline (austin@flowty.io) +updated: 2022-10-11 +--- + +# FLIP 1071: borrowContract function for PublicAccount + +## Objective + +This proposal will allow Cadence programs to import contracts dynamically from an address. + +## Motivation + +There is a popular request, especially from people coming from EVM space, to have a way to import contracts from an address by name ( dynamic import functionality ) + +Cadence lacks dynamic imports, which leads to mass imports in some contracts ( e.g., alchemy, find ) which also causes many contracts to fail if one of the crucial contracts ceases to exist. + +## User Benefit + +- It makes it possible to use patterns common to Solidity developers in Flow. ( Such as creating an empty `Vault` or empty `Collection` for the FT/NFT type without prior knowledge of the contract except if it implements the relevant standard. +- It allows importing and using contracts with a name collision. See https://github.com/onflow/cadence/issues/1171 +- It will prevent a single contract from breaking the ecosystem + +## Design Proposal + + +We suggest adding a new method `borrow` to both `AuthAccount.Contracts` and `PublicAccount.Contracts`. + +Borrowing a Contract will return a reference to the contract, avoiding move/copy problems. + +Implemented a proof of concept in https://github.com/onflow/cadence/pull/1934 + +```cadence +fun borrow(name: String): &T? +``` + +```cadence +if let contract = getAccount(0x1).contracts.borrow<&FungibleToken>("ExampleFT") { + let emptyVault <- contract.createEmptyVault() +} +``` + + +## Alternative + +Adding a method named `borrowContract` to both `PublicAccount` and `AuthAccount`. + +```cadence +fun borrowContract(name: String): &T? +``` + +Example usage will be: + +```cadence +if let contract = getAccount(0x1).borrowContract<&FungibleToken>("ExampleFT") { + let emptyVault <- contract.createEmptyVault() +} +``` + + +## Compatibility + +This change should be backward compatible. + +## User Impact + +The proposed change can affect how users write their smart contracts, which can cause some minor issues with reading contract code due to the nature of dynamic imports. But eventually, we don't see any negative security impact. + +## Prior Art & Related Features + +- Dynamically resolving import addresses https://github.com/onflow/cadence/issues/550 +- Solidity has a way to import and call contracts from an address. + + diff --git a/cadence/20220817-extensibility.md b/cadence/20220817-extensibility.md new file mode 100644 index 00000000..24b874aa --- /dev/null +++ b/cadence/20220817-extensibility.md @@ -0,0 +1,439 @@ +--- +status: rejected +flip: 1101 +authors: Daniel Sainati (daniel.sainati@dapperlabs.com) +sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) +updated: 2022-09-02 +--- + +# FLIP 1101: Extensibility (rejected) + +## Objective + +This FLIP proposes to add a new `extension` feature to Cadence, allowing users to extend existing +composite types (structs and resources) with additional fields and methods, without modifying the +original declaration. This feature is purely additive, i.e. no existing functionality is changed or removed. + +## Motivation + +It is currently not possible to extend existing types unless the original author explicitly made provisions for future extensions. + +For example, to make a resource declaration extensible, its author may add a field that allows any other code to store an extension. However, this requires a lot of boilerplate and is brittle. The original type must be prepared to store additional data with potentially additional functionality. + +Instead, this would allow users to extend existing types whether or not the original author planned for that use case. + +## User Benefit + +This enables a number of uses cases that were previously difficult or impossible, including [adding autographs to TopShot moments](https://github.com/onflow/cadence/issues/357#issuecomment-683387179)(or generally adding signature/edition info to existing NFTs), or [adding apparel to CryptoKitties](https://kittyhats.co/#/). + +## Design Proposal + +### Extension Declarations + +The new extension feature would be used with a new `extension` keyword, which would be declared using a new form of composite declaration: +` extension for : { ... }`, where the extension methods and fields are declared in the body. As such, +the following would be examples of legal declarations of extensions: + +```cadence +pub extension Foo for MyStruct: MyInterface { + ... +} + +priv extension Bar for MyResource { + ... +} + +priv extension Baz for MyResource: MyOtherInterface, MyThirdInterface { + ... +} +``` + +Specifying the kind (struct or resource) of an extension is not necessary, as its kind will necessarily be the same as the type it is extending. At this time, +extensions can only be defined for a resource or struct composite type. + +The access modifier defines the scope in which the extension can be used: a `pub` extension can extend its original type anywhere that imports it, +while an `access(contract)` extension can only be used within the contract that defines it. Note that this access is different than the access +of the fields or methods within the extension itself; a `pub` extension can declare a `priv` field, for example. + +Within the extension, fields and methods can be defined the same way they would be in a struct or resource declaration, with an access modifier and +a declaration kind. Any fields and methods on the original type would be accessible to the extension on the `self` value. +Note, however, that extensions only have access to the same fields and functions as other code declared in the same place would have; +i.e. an extension defined in the same contract as its original type would have access to `pub` and `access(contract)` fields and methods, but not `priv` fields +or methods, while an extension defined in a different contract and account to its original type would only be able to reference `pub` fields and methods on its +original type. Extensions may also not override or overload fields or methods on the original type, even if the original fields are not accessible to the extension. +Hence, if the original type `T` declared a `priv` field named `foo`, an extension `E` of `T` would not be able to declare any fields or methods named `foo`, even +though `foo` is not accessible to `E`. This is to avoid any confusion or ambiguity when reading code. + +Interface conformances are checked against the combination of the original type with the extension applied. In particular, this means that it is possible to declare +an extension with an interface annotation if neither the extension nor the original type conform to that interface, as long as the resultant extended type would conform. +For example: + +```cadence +pub struct interface I { + pub fun foo(): Int + pub fun bar(): String +} + +pub struct S { + pub fun foo(): Int { ... } +} + +pub extension E for S: I { + pub fun bar(): String { ... } +} +``` + +In this case, S does not conform to `I`, but `E`'s declaration does conform to `I` because type of `S` with the extension `E` applied produces a type that conforms to `I`. + +Any additional fields that are declared in an extension must be initialized, just as any fields declared in a composite must be. An extension +that declares fields must declare an additional (partial) initializer, which is run when the extension is created. For this reason, the `init` +method in an extension cannot make reference to any fields or methods of the base type, as it will be run before extension is attached to that type. It is +recommended that users simply initialize any fields as simply as possible here, and save any complex set-up for the extension's `attach` method (explained +later in this section). + +The same checks on normal initializers apply to extension initializers; namely that all the fields declared in the extensions must receive a value in the +extension's initializer. So, the following would be a legal extension: + +```cadence +pub struct S {} + +pub extension E for S { + pub let x: String + init(_ x: String) { + self.x = x + } +} +``` + +while these would not: + +```cadence +pub struct S {} + +pub extension E for S { + pub let x: String + pub let y: String + init(_ x: String) { + self.x = x + } +} +``` + +```cadence +pub struct S { + pub let y: String + init(_ y: String) { + self.y = y + } +} + +pub extension E for S { + init(_ y: String) { + self.y = y // E cannot reference S's fields in the initializer + } +} +``` + +Any resource fields (which are only legal when extending resources) must also be explicitly handled in a `destroy` method, which is run when +the extension is destroyed. Like `init`, because `destroy` may be run when the extension is not attached to a base type, it may not reference +any fields or methods of its base type, and should simply destroy any resources declared on the extension itself. + +Extensions may also declare two special methods: `attach() { ... }` and `remove() { ... }` that are not considered conflicting when attaching +multiple extensions to a single value. The `attach` method is automatically run after the extension is attached to a type, while the `remove` method +is run automatically when the extension is removed from a value (before the removal occurs). These functions exist to perform any necessary setup +and teardown for the extended type that requires using values from the base type, and thus cannot be performed in `init` or `destroy`. It is also recommended that +users check any pre-conditions or post-conditions they would like to hold before or after the extended type is created in these functions. + +If a resource type with attached extensions is `destroy`ed, the extensions will be implicitly `remove`d and then `destroy`ed. For reasons that will be further +detailed in the Extended Types section below, there are no guarantees made about the order in which the `remove` and `destroy` methods will be run in the case +of destroying a resource type with multiple extensions attached, other than that a) `destroy` on the base type will always be the last method run, and b) the +`remove` method for an extension will always be run before the `destroy` method of that same extension. If developers wish to enforce that `remove`s and `destroy`s +run in a specific order, it is recommended that they explicitly `remove` extensions from a resource and `destroy` them, rather than `destroy`ing the entire extended +resource type all at once. + +Some may wonder why `init` and `attach` are separate functions (and have a similar question about `destroy` and `remove`). The primary reason for this +is to allow extensions to be re-used across multiple instances of the same base type. By separating `init` and `attach` (and `destroy` and `remove`), +we can have separate code that runs once when the extension is created (destroyed), and then multiple times each time the extension is attached to (removed from) +a base type. A motivating example for this would be a hat for a CryptoKitty: by separating the code to initialize the hat and the code to "equip" a Kitty with the +hat, the hat can be added and removed from various Kitties, as well as sold and traded independently of the Kitties themselves. + +### Extended Types + +The `with` type operator can be used to describe the type of an extended composite. Hence, given some resource `R` and an extension `E` defined as such: + +```cadence +resource R {} +extension E for R {} +``` + +The type `@R with @E` describes the type of `R` extended with `E`. An extension can only appear on the right side of the `with` type operator +when it is a valid extension for the type on the left. + +The extension type itself also can be referenced with just `E`, but no operations can be performed on a value of type `E` other than to +move it around or to attach it to a value using `extend` syntax (see below). That is to say, a method or field defined in the declaration of `E` +exists on values of type `@R with @E`, not on values of type `E`. + +If the extension has any interface conformances, then the extended `with` type conforms to those interfaces. Hence, given these declarations: + +```cadence +resource R {} +extension E for R: I {} +``` + +`@R with @E` conforms to `I`. + +The original type is always a supertype of any extended versions of itself; i.e. `T` is a supertype of `T with E`. + +Because `T with E` is itself a type, `T with E1 with E2` would also be an acceptable type to describe the type of `T` extended with both `E1` +and `E2`. However, because this syntax has the potential for unneccessary verbosity and confusion, we also allow the use of comma separated +lists in these types: `T with E1, E2` is equivalent to `T with E1 with E2`. With the subtyping rules described above, `T with E1, E2`, is a +subtype of `T`, `T with E1` and `T with E2`. + +The order of the extensions in the type are interchangeable: `T with E1, E2` is the same type as `T with E2, E1`, and both are +subtypes of `T`, `T with E1` and `T with E2`. + +### Creating Extensions + +Extensions are created using similar syntax to creating composites: for an extension `E`, `E()` creates a struct-kinded extension, +and `create E()` creates a resource-kinded extension. The values created by these expressions have type `E`, and any types or +methods defined in the extension cannot be used on those values; the extension must be attached before its methods can be used. + +### Adding Extensions to a Type + +An extension can be attached to a base type using the `extend e1 with e2` expression. This expression requires that `e1` have a struct +or resource type, and that `e2` be a valid extension of that type. It will fail to typecheck otherwise. If `e1` has type `@R` and `e2` +has type `@E`, then a successfully checking expression of this form will have type `@R with @E`, and then `E`'s `attach` method will be run. +So, given resource definition: + +```cadence +resource R {} +extension E for R {} +``` + +The following would be valid ways to create `@R with @E`: + +```cadence +let r <- create R() +let e <- create E() +let r2 <- extend <-r with <-e +``` + +or + +```cadence +let r2 <- extend <-create R() with <-create E() +``` + +Note that extending `r` in the first example moves both the resource and the extension; `r` cannot be referenced after the creation of `r2`, +nor can `e` be attached to any other types. Compare with the same example using structs: + +```cadence +struct S {} +extension E for S {} +``` + +and + +```cadence +let s = S() +let e = E() +let s2 = extend s with e +``` + +or + +```cadence +let s2 = extend S() with E() +``` + +Here, in the first example, `s` is copied when it is extended, so when `s2` is created it has a copy of all of `s`'s fields and data. If +the data in `s2` is modified, those modifications would not be reflected in `s`. `e` can be attached to other values as well, and writes to +its data in `s2` are similarly not reflected in other values created with that extension. + +If the extension has an initializer, the arguments to that initializer are provided in the creation of the extension like so: + +```cadence +struct S { + pub let x: String + init(x: String) { + self.x = x + } +} + +extension E for S { + pub let y: Int + init(y: Int) { + self.y = y + } +} + +let se = extend S(x: "foo") with E(y: 3) +``` + +Values can be extended more than once; given resource `R` and extensions `E1` and `E2` of `R`, `extend <-r with <-create E2()` is +valid whether `r` has type `@R` or `@R with @E1`, since both are subtypes of `@R` which `@E2` extends. +In the latter case, the type of that expression would be `@R with @E1, @E2`, or equivalently `@R with @E1 with @E2`. Note, however, +that if `E1` and `E2` declare any fields or methods with the same name, this extension will fail statically, as this would result +in conflicts between the two extended types. + +At runtime, fields and methods are namespaced, so if `E1` and `E2` both declare a field named `foo`, so while a type `S with E1 and E2` +cannot be created, `E1` and `E2` can still both be attached to `S` at the same time at runtime: + +```cadence +let s = S() +let s2 = extend s with E1(foo: 3) +let s3 = s2 as S +let s4 = extend s3 with E2(foo: 3) +``` + +Because `s3` has type `S` statically, the extra data added by extending it with `E1` is "hidden" from view and not accessible, and +then extending that value with `E2` to create `s4` will create a value of type `S with E2`. The two `foo` fields are namespaced, +and do not interact. Referencing `s4.foo` will access the `foo` defined in `E2`, while referencing `s2.foo` will access the `foo` +defined in `E1`. Attempting to downcast `s4` to `S with E1 and E2` would fail at runtime, as despite how it may otherwise appear, +that type is not a subtype of `S with E2` because it is not a valid type. + +If people wish to extend a resource with multiple extensions at once, in order to avoid necessitating expressions like +`extend extend <-r with <-e1 with <-e2` or similar, we allow the use of the `and` keyword to declare multiple extensions at once: +`extend <-r with <-e1 and <-e2`. This latter expression is syntactic sugar for the former. + +### Removing Extensions from a Type + +Extensions can be removed with a new statement: `let x, y <- remove t from e` (or `let x, y = remove t from e` for structs). +The `t` value here is a type name, rather than a value, as the extension being removed cannot be referenced as a value. +In order to typecheck, if `t` is the name of some type `T2`, `e` must have type `T1 with T2`. Before the expression executes, +`T2`'s `remove` method will be executed. After the expression executes, `x` will contain a value of type `T1`, while `y` will +contain an extension with type `T2`. If these are resource-kinded, these values will have been moved out of `e`, so any alias +to the resource with type `T1 with T2` will be invalidated. + +Extensions may be removed from a multiply extended type in any order, as multiple extensions on the same base type cannot interact. +Users should still take care however not to design any extensions that rely on specific behaviors of other extensions, as there is no +way in this proposal to require that an extension depend on another or to require that a type has a given extension when another extension +is present. + +### References to Extended Resources + +When a reference is taken to a resource that has been extended, in addition to all the other circumstances in which that reference +might get invalidated, the reference will also be invalidated when any extensions are removed from that resource. This is to +prevent users from attempting to access fields or calling methods that only exist on the extension after the extension has been removed. +Consider: + +```cadence +resource R { + fun foo() {} +} +extension E1 for R { + fun bar() {} +} +extension E2 for R { + fun baz() {} +} + +let r <- create R() +let e1 <- create E1() +let e2 <- create E2() +let refBase: &@R = &r +let r1 <- extend <-r with <-e1 +let ref1: &@R with E1 = &r1 +let r3 <- extend <-r with <-e2 +let ref2: &@R with E1 = &r3 +let ref3: &@R with E1, E2 = &r3 +// at this point, refBase, ref1, ref2 and ref3 all refer to the same underlying value, +// but permit different sets of method calls on each +let r2, e3 <- remove E1 from r3 +// ref1, ref2 and ref3 are now invalid, as an extension has been removed from the resource they reference +let r0, e4 <- remove E2 from r2 +// refBase remains valid however, because the reference was not taken while the resource was extended +destroy r0 +destroy e3 +destroy e4 +``` + +### Drawbacks + +Adding a new language feature has the downside of complexity: users have to learn yet another +concept, and it also complicates the language implementation. + +However, this language feature can be disclosed progressively, users can discover and use it when needed, +it is not necessary to be understood for core use-cases of the language, i.e. the target audience is mostly “power-users”. + +### Tutorials and Examples + +* TODO: fill in later once the details of the design are decided + +### Compatibility + +This is backwards compatible, as it does not invalidate any existing Cadence code. + +## Related Issues + +In the interest of keeping this proposal tractable, we are keeping the scope deliberately limited, and a number +of useful features beyond the basic ones for extension are deliberately out of scope for this FLIP. + +Adding extensions for structs and resources implies the ability to extend contracts, transactions, interfaces or enumerations as well, +but these extensions are out of scope for this proposal. + +Some types may wish to require that they be extended; i.e. users may wish to define a set of methods on a type +that define a base functionality, but in order for the type to be used it should be extended with additional features. The +ability to require an extension on a type may be added in a future proposal, but is out of scope for this one. + +Similarly, some types may wish to prevent themselves from being extended; users may wish to prevent derivative works of an NFT, for +example. Such a restriction might be added in a future proposal with an `inextensible` or `final` keyword, for example. + +A future proposal may wish to add the ability to dynamically get a list of all the current extensions on a type. + +Having user-defineable type aliases would be very helpful for types that are multiply-extended. If we could write something like +`type T = X with Y`, then we could also write a type like `T with Z` instead of `X with Y, Z` or `X with Y with Z`, which is much +easier to read and understand. It also enables abstractions where users can use an (aliased) type without even having to know that +it was created using an extension. We should propose this in a future FLIP to complement this one. + +Currently, users can only declare extensions for a base resource or struct type, and extensions for the same type cannot interact with +or depend on each other. The benefit of this is that the order that extensions were added to the base type does not matter, and they +can be removed in any order interchangeably. However, allowing users to build extensions on top of each other to create dependency chains, +e.g. to declare an extension `E2 for R with E1`, where `E2` is able to rely both on the fields/methods of `R` and those of `E1` would enable +powerful new use cases. A future proposal that adds this ability would need to contend with the order of these extensions and how they would be added +and removed. + +## Alternatives + +In the comments of the PR where this FLIP was added, @turbolent proposed an alternative wherein every resource or struct has an implicit +`extensions` field that contains all of the extensions that are added to that composite. The extensions on a resource or struct would be +accessible, addable and removeable without changing the static type of that composite, and accessing the fields on an extension would require +accessing the specific extension from the base type and then accessing the field from that extension specifically. This has the nice property +that there would be no potential for naming conflicts between the base type and the extensions, as every method or field access on an +extension is always fully qualified. + +The downside of this alternative is that it does not provide any static typing guarantees. The proposal in the FLIP has the nice property +that the extensions present on a value are expressed in the type of that value; this makes it possible for a contract developer to write an +application that is designed to work with, say, CryptoKitties with Hats, and statically require its inputs to be of that extended type. If +extensions are stored on the base type like in the alternative though, expressing the type of a CryptoKitty with a Hat statically is no +longer possible, and the author of such an application would only be able to statically require its inputs be CryptoKitties, and then would +need to dynamically validate that the Hat extension is present on each of them. + +Simply requiring fields to be fully qualified on an extended type, even when the extensions are also reflected in the static type, also breaks +a nice property that the current proposal upholds, which is that the resulting type of extending `R with E` is equivalent to a composite type `RE` +that contains the fields and methods of both `R` and `E` on it. This makes extended values "first-class" similar to resources and structs, and +makes them more user-friendly to work with. + +## Prior Art + +Extensions exist in [C#](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods) +where they are static methods defined in an "Extension Class" that function like additional instance methods on the extended type. +This syntax is fairly unintuitive since the actual functionality of the new methods is very different than it appears based on +the syntax. Extensions are named and brought into scope explicitly. + +[Scala](http://dotty.epfl.ch/docs/reference/contextual/extension-methods.html) allows `extension` structures to be defined on +a type after it is created, defining computed fields or methods on that type within the `extension`. Extensions are not named. + +[Kotlin](https://kotlinlang.org/docs/extensions.html) allows extending a type by prefixing a function name with the receiver type +that is being extended. Extensions are not named, and are resolved statically (are not subject to dynamic dispatch). + +[Swift](https://docs.swift.org/swift-book/LanguageGuide/Extensions.html) allows defining an `extension` structure that adds functionality +to an existing type, and allows for the extension to be annotated with any interfaces to which it conforms. Extensions can define +additional methods, computed properties and initializers. + +## Questions and Discussion Topics + +* If Cadence had support for tuples or multiple return values, we would be able to make removing extensions more +ergonomic by simply making the return of the `remove from` expression a tuple, or to make the expression return multiple values. +We would then not need to special cast the bindings created from this expression. + diff --git a/cadence/20220908-publish-claim-capability.md b/cadence/20220908-publish-claim-capability.md new file mode 100644 index 00000000..eda2650d --- /dev/null +++ b/cadence/20220908-publish-claim-capability.md @@ -0,0 +1,149 @@ +--- +status: implemented +flip: 1122 +authors: Daniel Sainati (daniel.sainati@dapperlabs.com) +sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) +updated: 2022-09-16 +--- + +# FLIP 1122: Publish/Claim Capability + +## Objective + +This adds two new functions that allow users to publish values for specific other +users to claim, while ensuring that other users cannot claim these values. In particular, +this dramatically simplifies the use case for bootstrapping capabilities. + +## Motivation + +https://github.com/onflow/flow/pull/945 proposed to add an `identity` resource-typed field +on `AuthAccount` objects, to allow users to verify the identity of an account. In particular, +this was intended to enable sharing values to specific users, and to simplify the capability bootstrapping +usecase. In this use case, the owner of a resource, which we can call the Provider, +wants to share a capability to that resource with another account, which we can call the Recipient. + +Currently the best way to do this in Cadence is for the Provider and the Recipient to co-sign a transaction +in which the Provider creates the capability and then stores it in the Recipient's account. However, +this is awkward because it requires the Provider and the Recipient to both sign the transaction within a specific +time window, which can be difficult in highly asynchronous environments, e.g. collaboration between distant time-zones. + +This FLIP is designed to enable an alternative solution, in which the Provider can create the capability and place it somewhere +where the Recipient can securely claim it at their leisure, without any pressure to do so within a specific time window and with +no worry that someone else may come along and interfere. + +## User Benefit + +This will dramatically simplify the capability bootstrapping use case, as well as generally making it easier for users +to share specific values directly with another account. + +## Design Proposal + +This adds a new field `inbox` to `AuthAccount`, that has a new `Inbox` struct type +defined as a nested composite on `AuthAccount`: + +```cadence +struct Inbox { + fun publish(_ value: Capability, name: String, recipient: Address) + + fun unpublish(_ name: String): Capability? + + fun claim(_ name: String, provider: Address): Capability? +} +``` + +The `publish` function takes a `value` argument, a `name` string that identifies it, +and a `recipient` address that specifies which account should be allowed to `claim` the +published `value` later. When `publish` is called, `value` and its intended `recipient` are stored +in a publishing dictionary on the calling account (not accessible to users), with the `name` as its key. +Note that this means any values that have been `publish`ed but have yet to be `claim`ed will count towards +the `publish`ing account's storage usage. + +The `claim` function takes the `name` of the value to be claimed and an `provider` address that +specifies which account is providing the value, as well as a type argument `T` that specifies +the type with which the value should be claimed. When called, `claim` will search the `provider`s +publishing dictionary for the `name` key. If the key does not exist on the map, `claim` returns `nil`. + +If the key does exist, then `claim` compares the stored `recipient` (from the original call to `publish`) +to see if it matches the address of the account calling `claim`. If it does not, then `claim` returns `nil`. +If it does match, then the runtime type of the published `value` compared against the type argument `T`. If +it does not match, then `claim` will produce an error. If it does match, `value` is removed from the `provider`'s dictionary and +returned to the `claim` calling account. In effect, this means that a `publish`ed value can only be `claim`ed once. + +An example of how this might look, when bootstrapping a capability to a resource owned by 0x1: + +```cadence +// transaction 1 (from the original resource owner 0x1) +import MyIntf from 0x1 + +transaction() { + prepare(acct: AuthAccount) { + // create a capability to a resource stored at /storage/myResource. + // With the changes proposed in https://github.com/onflow/flow/pull/798, this may + // not involve linking to a concrete path, but at the moment the only way to create + // a capability is via `link` + let cap = acct.link<&MyIntf>(/private/myCapability, target: /storage/myResource) + acct.inbox.publish(cap, name: "yourCapability", recipient: 0x2) + } +} +``` + +```cadence +// transaction 2 (from the reciever of the capability 0x2) +import MyIntf from 0x1 + +transaction() { + prepare(acct: AuthAccount) { + let cap = acct.inbox.claim>("yourCapability", provider: 0x1) + // if we successfully obtain the capability, store it on our account + if cap != nil { + acct.save(cap, to: /storage/myCapability) + } + } +} +``` + +The `unpublish` function exists so that a provider can remove a published value from their storage, so that it +stops taking up space if it goes un`claim`ed by its intended recipient. The calling account (the original provider +of the value) calls `unpublish` with the same `name` that the value was originally stored with. If a value with that +`name` is present in the account's publishing dictionary, and the provided type argument to `unpublish` is a supertype +of that value's runtime type, then the function will return that value and remove it from the dictionary. Otherwise, +the function returns `nil`. The type comparison is a force-cast like `load` and `claim`, so if the types do not match +the program will fail. + +This FLIP also adds two new events to Cadence: + +```cadence +event InboxValuePublished(provider: Address, recipient: Address, name: String, type: Type) + +event InboxValueRemoved(provider: Address, remover: Address, name: String) +``` + +These events are emitted whenever a value is added or removed from an inbox's publishing dictionary. When `publish` is called, +`InboxValuePublished` is emitted containing the address of the `provider` and the `recipient`, the `name` the value was published with, and the runtime +`type` it was published with. When a value is `claim`ed or `unpublish`ed, `InboxValueRemoved` is emitted, including the address the value was +originally published from (`provider`), the address of the `remover` (in the case of `claim`, this is the recipient's address, in the case of +`unpublish` it is the same as the `provider`), and the `name` of the removed event. + +### Alternatives Considered + +* The original proposal for this flip generalized `publish` and `claim` to work with resources, as well as Capabilities. +While the generalized version was strictly more powerful, we felt that it was too likely to encourage users +to write code in the `msg.sender` pattern instead of using it for the capability bootstrapping usecase. We have decided to +restrict the API to capabilities for now, with the understanding that it is possible in the future to expand the API without breaking anything. + +### Best Practices + +* This will change the best practices for bootstrapping capabilities, which was previously only +possible by cosigning a transaction. Instead, users should be encouraged to use the `publish`/`claim` pattern +in order to handle any cases where they would like to pass a value directly from their account to a specific +other. + +### Compatibility + +This will be backwards-compatible from the Cadence perspective, but will add a new field to +every account (the dictionary of published objects). To support this we would need a storage migration +to add empty dictionaries to all accounts during the spork that adds support for this feature. + +### User Impact + +* This should have no direct impact on users; it will not break any existing contracts. From 40483abb4333aff062ea67225bf462ad2ddc9dc2 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Sat, 3 Jun 2023 02:43:46 +0530 Subject: [PATCH 32/47] Flip for Range & Progression in Cadence --- cadence/20230602-cadence-range-progression.md | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 cadence/20230602-cadence-range-progression.md diff --git a/cadence/20230602-cadence-range-progression.md b/cadence/20230602-cadence-range-progression.md new file mode 100644 index 00000000..c31787d8 --- /dev/null +++ b/cadence/20230602-cadence-range-progression.md @@ -0,0 +1,179 @@ +--- +status: draft +flip: 96 +authors: darkdrag00n (darkdrag00n@proton.me) +sponsor: Bastian Müller (bastian@dapperlabs.com) +updated: 2023-06-02 +--- + +# FLIP 96: Range & Progression Type + +## Objective + +This FLIP proposes adding the `Range` & `Progression` types to Cadence. +Both of these types can then used inside a `for-in` loop. + +## Motivation + +Modern langauges often provide a concise way for highly repetitive use cases. One of them is looping between a start & end integer possibly with a step. + +Presently, to loop over a start & end integer value, users have to either create an `Array` or use an imperative style `while` loop. A concise syntax for e.g. `1 .. 10` would enhance the readability of the language. + +## User Benefit + +Users will benefit from the concise syntax leading to a cleaner & readable code. + +## Design Proposal + +This proposal suggest adding two new types to Cadence: +1. `Range` + +### Range + +A `Range` will be defined as follows: + +```go +struct Range { + let start: T + let endInclusive: T +} +``` + +It can be instantiated using the `..` & `downTo` binary operators & can be used in a `for-in` loop as follows: + +```cadence +// i will be start, start + 1, .. endInclusive +for i in start .. endInclusive { + // do something with i +} + +// i will be start, start - 1, .. endInclusive +for i in start downTo endInclusive { + // do something with i +} +``` + +When `..` is used, we must have `start <= endInclusive` while if `downTo` is used, then we must have `start >= endInclusive`. + +`Range` will also provide the following public member variables and functions: + +1. `length`: Returns the count of integers included in the `Range`. +2. `contains(value: T): Bool`: Returns if the `Range` includes the provided `value`. + +#### Examples + +Example usage of a `Range` type: + +```cadence +let rangeValue = 11 .. 45 + +let len1 = rangeValue.length // 35 +let isPresent1 = rangeValue.contains(24) // True + +for i in rangeValue { + // logic using i +} + +let rangeValueBackwards = 132 .. 33 + +let len2 = rangeValueBackwards.length // 100 +let isPresent2 = rangeValueBackwards.contains(1) // False +``` + +### Progression + +A `Progression` type will essentially be a `Range` with an additional `step` which determines the step of the progression. In other words, `Range` will be a `Progression` with `step` set to 1 or -1. + +It will be defined as follows: + +```go +struct Progression { + let start: T + let endInclusive: T + let step: T +} +``` + +It can be instantiated with the usage of `..` & `downTo` along with a `step` operator & can be used in a `for-in` loop as follows: + +```cadence +// i will be start, start + 2, step + 4, .. endInclusive +for i in start .. endInclusive step 2 { + // do something with i +} + +// i will be start, start - 3, start - 6, .. endInclusive +for i in start downTo endInclusive step 3 { + // do something with i +} +``` + +When `..` is used, we must have `start <= endInclusive` while if `downTo` is used, then we must have `start >= endInclusive`. + +`Progression` will also provide the following public member variables and functions: + +1. `length`: Returns the count of integers included in the `Progression`. +2. `step`: Returns the step size of the `Progression`. +3. `contains(value: T): Bool`: Returns if the `Progression` includes the provided `value`. + +#### Examples + +Example usage of a `Progression` type: + +```cadence +let progressionValue = 11 .. 45 step 2 + +let len1 = progressionValue.length // 18 +let isPresent1 = progressionValue.contains(24) // False + +for i in progressionValue { + // logic using i +} + +let progressionValueBackwards = 132 .. 33 step 2 + +let len2 = progressionValueBackwards.length // 50 +let isPresent2 = progressionValueBackwards.contains(34) // True +``` + +### Drawbacks + +None + +### Alternatives Considered + +No. Relatively straightforward. Other modern languages such as Kotlin, Swift & Rust have similar syntax & API for `Range`. + +### Performance Implications + +None + +### Dependencies + +None + +### Engineering Impact + +No engineering impact is expected. + +### Compatibility + +This change has no impact on compatibility between systems (e.g. SDKs). + +### User Impact + +The proposed feature is a purely additive. +There is no impact on existing contracts and new transactions. + +## Related Issues + +None + +## Questions and Discussion Topics + +None + +## Implementation +Will be done as part of https://github.com/onflow/cadence/issues/2482. + From dca8310ccdf77bd434099b4fde5b3ff9bfd2f9a3 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Sat, 3 Jun 2023 02:50:00 +0530 Subject: [PATCH 33/47] Fix grammatical mistake --- cadence/20230602-cadence-range-progression.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/20230602-cadence-range-progression.md b/cadence/20230602-cadence-range-progression.md index c31787d8..74b9955c 100644 --- a/cadence/20230602-cadence-range-progression.md +++ b/cadence/20230602-cadence-range-progression.md @@ -11,7 +11,7 @@ updated: 2023-06-02 ## Objective This FLIP proposes adding the `Range` & `Progression` types to Cadence. -Both of these types can then used inside a `for-in` loop. +Both of these types can then be used inside a `for-in` loop. ## Motivation From a00e19ccc45a73ccc0d6f55991939de598abc00c Mon Sep 17 00:00:00 2001 From: darkdrag00nv2 <122124396+darkdrag00nv2@users.noreply.github.com> Date: Sat, 3 Jun 2023 22:47:23 +0530 Subject: [PATCH 34/47] Add missing `>` in header Co-authored-by: Daniel Sainati --- cadence/20230602-cadence-range-progression.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/20230602-cadence-range-progression.md b/cadence/20230602-cadence-range-progression.md index 74b9955c..0afd77fc 100644 --- a/cadence/20230602-cadence-range-progression.md +++ b/cadence/20230602-cadence-range-progression.md @@ -26,7 +26,7 @@ Users will benefit from the concise syntax leading to a cleaner & readable code. ## Design Proposal This proposal suggest adding two new types to Cadence: -1. `Range` 2. `Progression` ### Range From edca98ae5604e07c61569dbc3ebdd2b3b3da4b45 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Wed, 7 Jun 2023 01:49:22 +0530 Subject: [PATCH 35/47] Update proposal to use constructor functions instead of operators --- cadence/20230602-cadence-range-progression.md | 179 ---------------- cadence/20230602-cadence-range.md | 197 ++++++++++++++++++ 2 files changed, 197 insertions(+), 179 deletions(-) delete mode 100644 cadence/20230602-cadence-range-progression.md create mode 100644 cadence/20230602-cadence-range.md diff --git a/cadence/20230602-cadence-range-progression.md b/cadence/20230602-cadence-range-progression.md deleted file mode 100644 index 0afd77fc..00000000 --- a/cadence/20230602-cadence-range-progression.md +++ /dev/null @@ -1,179 +0,0 @@ ---- -status: draft -flip: 96 -authors: darkdrag00n (darkdrag00n@proton.me) -sponsor: Bastian Müller (bastian@dapperlabs.com) -updated: 2023-06-02 ---- - -# FLIP 96: Range & Progression Type - -## Objective - -This FLIP proposes adding the `Range` & `Progression` types to Cadence. -Both of these types can then be used inside a `for-in` loop. - -## Motivation - -Modern langauges often provide a concise way for highly repetitive use cases. One of them is looping between a start & end integer possibly with a step. - -Presently, to loop over a start & end integer value, users have to either create an `Array` or use an imperative style `while` loop. A concise syntax for e.g. `1 .. 10` would enhance the readability of the language. - -## User Benefit - -Users will benefit from the concise syntax leading to a cleaner & readable code. - -## Design Proposal - -This proposal suggest adding two new types to Cadence: -1. `Range` -2. `Progression` - -### Range - -A `Range` will be defined as follows: - -```go -struct Range { - let start: T - let endInclusive: T -} -``` - -It can be instantiated using the `..` & `downTo` binary operators & can be used in a `for-in` loop as follows: - -```cadence -// i will be start, start + 1, .. endInclusive -for i in start .. endInclusive { - // do something with i -} - -// i will be start, start - 1, .. endInclusive -for i in start downTo endInclusive { - // do something with i -} -``` - -When `..` is used, we must have `start <= endInclusive` while if `downTo` is used, then we must have `start >= endInclusive`. - -`Range` will also provide the following public member variables and functions: - -1. `length`: Returns the count of integers included in the `Range`. -2. `contains(value: T): Bool`: Returns if the `Range` includes the provided `value`. - -#### Examples - -Example usage of a `Range` type: - -```cadence -let rangeValue = 11 .. 45 - -let len1 = rangeValue.length // 35 -let isPresent1 = rangeValue.contains(24) // True - -for i in rangeValue { - // logic using i -} - -let rangeValueBackwards = 132 .. 33 - -let len2 = rangeValueBackwards.length // 100 -let isPresent2 = rangeValueBackwards.contains(1) // False -``` - -### Progression - -A `Progression` type will essentially be a `Range` with an additional `step` which determines the step of the progression. In other words, `Range` will be a `Progression` with `step` set to 1 or -1. - -It will be defined as follows: - -```go -struct Progression { - let start: T - let endInclusive: T - let step: T -} -``` - -It can be instantiated with the usage of `..` & `downTo` along with a `step` operator & can be used in a `for-in` loop as follows: - -```cadence -// i will be start, start + 2, step + 4, .. endInclusive -for i in start .. endInclusive step 2 { - // do something with i -} - -// i will be start, start - 3, start - 6, .. endInclusive -for i in start downTo endInclusive step 3 { - // do something with i -} -``` - -When `..` is used, we must have `start <= endInclusive` while if `downTo` is used, then we must have `start >= endInclusive`. - -`Progression` will also provide the following public member variables and functions: - -1. `length`: Returns the count of integers included in the `Progression`. -2. `step`: Returns the step size of the `Progression`. -3. `contains(value: T): Bool`: Returns if the `Progression` includes the provided `value`. - -#### Examples - -Example usage of a `Progression` type: - -```cadence -let progressionValue = 11 .. 45 step 2 - -let len1 = progressionValue.length // 18 -let isPresent1 = progressionValue.contains(24) // False - -for i in progressionValue { - // logic using i -} - -let progressionValueBackwards = 132 .. 33 step 2 - -let len2 = progressionValueBackwards.length // 50 -let isPresent2 = progressionValueBackwards.contains(34) // True -``` - -### Drawbacks - -None - -### Alternatives Considered - -No. Relatively straightforward. Other modern languages such as Kotlin, Swift & Rust have similar syntax & API for `Range`. - -### Performance Implications - -None - -### Dependencies - -None - -### Engineering Impact - -No engineering impact is expected. - -### Compatibility - -This change has no impact on compatibility between systems (e.g. SDKs). - -### User Impact - -The proposed feature is a purely additive. -There is no impact on existing contracts and new transactions. - -## Related Issues - -None - -## Questions and Discussion Topics - -None - -## Implementation -Will be done as part of https://github.com/onflow/cadence/issues/2482. - diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md new file mode 100644 index 00000000..1e40303b --- /dev/null +++ b/cadence/20230602-cadence-range.md @@ -0,0 +1,197 @@ +--- +status: draft +flip: 96 +authors: darkdrag00n (darkdrag00n@proton.me) +sponsor: Bastian Müller (bastian@dapperlabs.com) +updated: 2023-06-02 +--- + +# FLIP 96: Range Type + +## Objective + +This FLIP proposes adding the concept of a `Range` to Cadence. It proposes two new types, `InclusiveRange` and `ExclusiveRange` along with constructor functions to create them. It also proposes their usage inside a `for-in` loop. + +## Motivation + +Modern langauges often provide a concise way for highly repetitive use cases. One of them is looping between a start & end integer possibly with a step. + +Presently, to loop over a start & end integer value, users have to either create an `Array` or use an imperative style `while` loop. A concise syntax would enhance the readability of the language. + +## User Benefit + +The two `Range` types improves over the usage of arrays. Hence, users will benefit from the concise syntax leading to a cleaner & readable code. + +## Design Proposal + +New types `InclusiveRange` & `ExclusiveRange` will be added to Cadence and defined as follows: + +```go +struct InclusiveRange { + let start: T + let endInclusive: T + let step: T +} + +struct ExclusiveRange { + let start: T + let endExclusive: T + let step: T +} +``` + +Please note the following points: +1. In `InclusiveRange`, `endInclusive` is an element of the resulting sequence if and only if it can be produced from `start` using steps of size `step`. + +2. In `ExclusiveRange`, `endExclusive` is guaranteed to not be part of the generated sequence. As a result, if `start == endExclusive`, the resulting sequence is empty. + +Both the `Range` types will be usable in a `for-in` loop. + +### Constructor Functions +Constructor functions will be defined to instantiate variables of type `InclusiveRange` & `ExclusiveRange`. They are defined below. + +- `InclusiveRange(start: T, endInclusive: T)`: Creates an `InclusiveRange` with the provided start and end with a default value of step as 1 if `start <= endInclusive` or -1 if `start > endInclusive`. + +- `InclusiveRangeWithStep(start: T, endInclusive: T, step: T)`: Creates an `InclusiveRange` with the provided start, end and step. + +- `ExclusiveRange(start: T, endExclusive: T)`: Creates an `ExclusiveRange` with the provided start and end with a default value of step as 1 if `start <= endInclusive` or -1 if `start > endInclusive`. + +- `ExclusiveRangeWithStep(start: T, endExclusive: T, step: T)`: Creates an `ExclusiveRange` with the provided start, end and step. + +The following constraints are applicable in all the four constructor functions: + +1. `step` must be non-zero i.e. `abs(step) > 0`. + +2. The value of `step` must lead to the sequence moving towards the end. + +Violation of the above constraints will lead to runtime errors during instantiation. + +### Public Members +`Range` will also provide the following public member variables and functions: + +1. `length`: Returns the count of integers included in the `Range`. +2. `contains(value: T): Bool`: Returns if the `Range` includes the provided `value`. + +### Examples + +Example usage of `InclusiveRange` and `ExclusiveRange` types: + +```cadence +//////////////////// +// InclusiveRange // +//////////////////// + +let inclusiveRangeValue = InclusiveRange(11, 21) +inclusiveRangeValue.length // 11 +inclusiveRangeValue.contains(20) // True +for i in inclusiveRangeValue { + // i will be 11, 12, 13, ... 20, 21 +} + +let inclusiveRangeValueWithStep = InclusiveRangeWithStep(11, 20, 2) +inclusiveRangeValueWithStep.length // 5 +inclusiveRangeValueWithStep.contains(20) // False since 20 cannot be produced from 11 using step of 2. +for i in inclusiveRangeValueWithStep { + // i will be 11, 13, 15, 17, 19 +} + +let inclusiveRangeValueBackwards = InclusiveRange(132, 33) +inclusiveRangeValueBackwards.length // 100 +inclusiveRangeValueBackwards.contains(1) // False +for i in inclusiveRangeValue { + // i will be 132, 131, 130, ... 34, 33 +} + +let inclusiveRangeValueBackwards = InclusiveRangeWithStep(132, 33, -3) +inclusiveRangeValueBackwards.length // 15 +inclusiveRangeValueBackwards.contains(34) // True +for i in inclusiveRangeValue { + // i will be 132, 125, 118, ... 41, 34 +} + +let invalidStep = InclusiveRangeWithStep(10, 32, 0) // Runtime Error +let invalidDirection = InclusiveRangeWithStep(132, 33, 3) // Runtime Error since the sequence moves in increasing direction. + +//////////////////// +// ExclusiveRange // +//////////////////// + +let exclusiveRangeValue = ExclusiveRange(11, 21) +exclusiveRangeValue.length // 10 +exclusiveRangeValue.contains(20) // True +exclusiveRangeValue.contains(21) // False +for i in exclusiveRangeValue { + // i will be 11, 12, 13, ... 19, 20 +} + +let exclusiveRangeValueWithStep = ExclusiveRangeWithStep(11, 19, 2) +exclusiveRangeValueWithStep.length // 4 +exclusiveRangeValueWithStep.contains(19) // False +for i in exclusiveRangeValueWithStep { + // i will be 11, 13, 15, 17 +} + +let exclusiveRangeValueBackwards = ExclusiveRange(132, 33) +exclusiveRangeValueBackwards.length // 99 +exclusiveRangeValueBackwards.contains(1) // False +for i in exclusiveRangeValue { + // i will be 132, 131, 130, ... 35, 34 +} + +let exclusiveRangeValueBackwards = ExclusiveRangeWithStep(132, 33, -3) +exclusiveRangeValueBackwards.length // 15 +exclusiveRangeValueBackwards.contains(34) // True +for i in exclusiveRangeValue { + // i will be 132, 125, 118, ... 41, 34 +} + +let exclusiveRangeValueEmpty = ExclusiveRangeWithStep(10, 10, 2) // Empty since start == endExclusive + +let invalidStep = ExclusiveRangeWithStep(10, 32, 0) // Runtime Error +let invalidDirection = ExclusiveRangeWithStep(132, 33, 3) // Runtime Error + +``` + +### Drawbacks + +None + +### Alternatives Considered +Initial proposal considered defining operators such as `..` or `downTo` for defining `Range`. It also proposed adding another type named `Progression` for allowing non-default values of `step`. + +Due to the readability concerns associated with the inclusive vs exclusive behavior of the operators, it was considered better to have types and constructor functions with self-explanatory names to avoid ambiguity. + +It was also proposed that since `Progression` is essentially a `Range` with non-default value of `step`, the two types can be merged into one. + +### Performance Implications + +None + +### Dependencies + +None + +### Engineering Impact + +No engineering impact is expected. + +### Compatibility + +This change has no impact on compatibility between systems (e.g. SDKs). + +### User Impact + +The proposed feature is a purely additive. +There is no impact on existing contracts and new transactions. + +## Related Issues + +None + +## Questions and Discussion Topics + +None + +## Implementation +Will be done as part of https://github.com/onflow/cadence/issues/2482. + From 31c0a4be0d7f4764f40e1dbdff93232016562b35 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Wed, 7 Jun 2023 01:53:37 +0530 Subject: [PATCH 36/47] nit: remove extra line --- cadence/20230602-cadence-range.md | 1 - 1 file changed, 1 deletion(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index 1e40303b..c394fd14 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -149,7 +149,6 @@ let exclusiveRangeValueEmpty = ExclusiveRangeWithStep(10, 10, 2) // Empty since let invalidStep = ExclusiveRangeWithStep(10, 32, 0) // Runtime Error let invalidDirection = ExclusiveRangeWithStep(132, 33, 3) // Runtime Error - ``` ### Drawbacks From 19a7aaa6b53b97751881027e6a3ab34d38e61d62 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Mon, 19 Jun 2023 22:57:52 +0530 Subject: [PATCH 37/47] Update FLIP based on review suggestions --- cadence/20230602-cadence-range.md | 63 ++++++++++++++----------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index c394fd14..43506e9b 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -3,7 +3,7 @@ status: draft flip: 96 authors: darkdrag00n (darkdrag00n@proton.me) sponsor: Bastian Müller (bastian@dapperlabs.com) -updated: 2023-06-02 +updated: 2023-06-19 --- # FLIP 96: Range Type @@ -29,36 +29,32 @@ New types `InclusiveRange` & `ExclusiveRange` will be ad ```go struct InclusiveRange { let start: T - let endInclusive: T + let end: T let step: T } struct ExclusiveRange { let start: T - let endExclusive: T + let end: T let step: T } ``` Please note the following points: -1. In `InclusiveRange`, `endInclusive` is an element of the resulting sequence if and only if it can be produced from `start` using steps of size `step`. +1. In `InclusiveRange`, `end` is an element of the resulting sequence if and only if it can be produced from `start` using steps of size `step`. -2. In `ExclusiveRange`, `endExclusive` is guaranteed to not be part of the generated sequence. As a result, if `start == endExclusive`, the resulting sequence is empty. +2. In `ExclusiveRange`, `end` is guaranteed to not be part of the generated sequence. As a result, if `start == end`, the resulting sequence is invalid & we disallow creation of such `ExclusiveRange`. Both the `Range` types will be usable in a `for-in` loop. ### Constructor Functions Constructor functions will be defined to instantiate variables of type `InclusiveRange` & `ExclusiveRange`. They are defined below. -- `InclusiveRange(start: T, endInclusive: T)`: Creates an `InclusiveRange` with the provided start and end with a default value of step as 1 if `start <= endInclusive` or -1 if `start > endInclusive`. +- `InclusiveRange(start: T, end: T, step: T)`: Creates an `InclusiveRange` with the provided start, end and step. `step` will be an optional argument with a default value of step as 1 if `start <= end` or -1 if `start > end`. -- `InclusiveRangeWithStep(start: T, endInclusive: T, step: T)`: Creates an `InclusiveRange` with the provided start, end and step. +- `ExclusiveRange(start: T, end: T, step: T)`: Creates an `ExclusiveRange` with the provided start, end and step. `step` will be an optional argument with a default value of step as 1 if `start < end` or -1 if `start > end`. -- `ExclusiveRange(start: T, endExclusive: T)`: Creates an `ExclusiveRange` with the provided start and end with a default value of step as 1 if `start <= endInclusive` or -1 if `start > endInclusive`. - -- `ExclusiveRangeWithStep(start: T, endExclusive: T, step: T)`: Creates an `ExclusiveRange` with the provided start, end and step. - -The following constraints are applicable in all the four constructor functions: +The following constraints are applicable in both the constructor functions: 1. `step` must be non-zero i.e. `abs(step) > 0`. @@ -67,10 +63,10 @@ The following constraints are applicable in all the four constructor functions: Violation of the above constraints will lead to runtime errors during instantiation. ### Public Members -`Range` will also provide the following public member variables and functions: +Both `InclusiveRange` & `ExclusiveRange` will also provide the following public member variables and functions: -1. `length`: Returns the count of integers included in the `Range`. -2. `contains(value: T): Bool`: Returns if the `Range` includes the provided `value`. +1. `count`: Returns the count of integers included in the Range. +2. `contains(value: T): Bool`: Returns if the Range includes the provided `value`. ### Examples @@ -82,73 +78,72 @@ Example usage of `InclusiveRange` and `ExclusiveRange` types: //////////////////// let inclusiveRangeValue = InclusiveRange(11, 21) -inclusiveRangeValue.length // 11 +inclusiveRangeValue.count // 11 inclusiveRangeValue.contains(20) // True for i in inclusiveRangeValue { // i will be 11, 12, 13, ... 20, 21 } -let inclusiveRangeValueWithStep = InclusiveRangeWithStep(11, 20, 2) -inclusiveRangeValueWithStep.length // 5 +let inclusiveRangeValueWithStep = InclusiveRange(11, 20, 2) +inclusiveRangeValueWithStep.count // 5 inclusiveRangeValueWithStep.contains(20) // False since 20 cannot be produced from 11 using step of 2. for i in inclusiveRangeValueWithStep { // i will be 11, 13, 15, 17, 19 } let inclusiveRangeValueBackwards = InclusiveRange(132, 33) -inclusiveRangeValueBackwards.length // 100 +inclusiveRangeValueBackwards.count // 100 inclusiveRangeValueBackwards.contains(1) // False for i in inclusiveRangeValue { // i will be 132, 131, 130, ... 34, 33 } -let inclusiveRangeValueBackwards = InclusiveRangeWithStep(132, 33, -3) -inclusiveRangeValueBackwards.length // 15 +let inclusiveRangeValueBackwards = InclusiveRange(132, 33, -3) +inclusiveRangeValueBackwards.count // 15 inclusiveRangeValueBackwards.contains(34) // True for i in inclusiveRangeValue { // i will be 132, 125, 118, ... 41, 34 } -let invalidStep = InclusiveRangeWithStep(10, 32, 0) // Runtime Error -let invalidDirection = InclusiveRangeWithStep(132, 33, 3) // Runtime Error since the sequence moves in increasing direction. +let invalidStep = InclusiveRange(10, 32, 0) // Runtime Error +let invalidDirection = InclusiveRange(132, 33, 3) // Runtime Error since the sequence moves in increasing direction. //////////////////// // ExclusiveRange // //////////////////// let exclusiveRangeValue = ExclusiveRange(11, 21) -exclusiveRangeValue.length // 10 +exclusiveRangeValue.count // 10 exclusiveRangeValue.contains(20) // True exclusiveRangeValue.contains(21) // False for i in exclusiveRangeValue { // i will be 11, 12, 13, ... 19, 20 } -let exclusiveRangeValueWithStep = ExclusiveRangeWithStep(11, 19, 2) -exclusiveRangeValueWithStep.length // 4 +let exclusiveRangeValueWithStep = ExclusiveRange(11, 19, 2) +exclusiveRangeValueWithStep.count // 4 exclusiveRangeValueWithStep.contains(19) // False for i in exclusiveRangeValueWithStep { // i will be 11, 13, 15, 17 } let exclusiveRangeValueBackwards = ExclusiveRange(132, 33) -exclusiveRangeValueBackwards.length // 99 +exclusiveRangeValueBackwards.count // 99 exclusiveRangeValueBackwards.contains(1) // False for i in exclusiveRangeValue { // i will be 132, 131, 130, ... 35, 34 } -let exclusiveRangeValueBackwards = ExclusiveRangeWithStep(132, 33, -3) -exclusiveRangeValueBackwards.length // 15 +let exclusiveRangeValueBackwards = ExclusiveRange(132, 33, -3) +exclusiveRangeValueBackwards.count // 15 exclusiveRangeValueBackwards.contains(34) // True for i in exclusiveRangeValue { // i will be 132, 125, 118, ... 41, 34 } -let exclusiveRangeValueEmpty = ExclusiveRangeWithStep(10, 10, 2) // Empty since start == endExclusive - -let invalidStep = ExclusiveRangeWithStep(10, 32, 0) // Runtime Error -let invalidDirection = ExclusiveRangeWithStep(132, 33, 3) // Runtime Error +let exclusiveRangeValueEmpty = ExclusiveRange(10, 10, 2) // Runtime Error +let invalidStep = ExclusiveRange(10, 32, 0) // Runtime Error +let invalidDirection = ExclusiveRange(132, 33, 3) // Runtime Error ``` ### Drawbacks @@ -172,7 +167,7 @@ None ### Engineering Impact -No engineering impact is expected. +It would require 2-3 weeks of engineering effort to implement, review & test the feature. ### Compatibility From 3292a180b9a0e0f4c3c290e62d2005a6dc6f492d Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Mon, 19 Jun 2023 23:03:25 +0530 Subject: [PATCH 38/47] Correct language in the code snippet --- cadence/20230602-cadence-range.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index 43506e9b..1fa9c069 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -26,7 +26,7 @@ The two `Range` types improves over the usage of arrays. Hence, users will benef New types `InclusiveRange` & `ExclusiveRange` will be added to Cadence and defined as follows: -```go +```cadence struct InclusiveRange { let start: T let end: T From 41126e7c58e41693aab1e6164624b29e6bb6d5e6 Mon Sep 17 00:00:00 2001 From: darkdrag00nv2 <122124396+darkdrag00nv2@users.noreply.github.com> Date: Tue, 20 Jun 2023 22:56:22 +0530 Subject: [PATCH 39/47] Indicate that start and end do not require argument labels. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- cadence/20230602-cadence-range.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index 1fa9c069..3c0dece8 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -50,9 +50,9 @@ Both the `Range` types will be usable in a `for-in` loop. ### Constructor Functions Constructor functions will be defined to instantiate variables of type `InclusiveRange` & `ExclusiveRange`. They are defined below. -- `InclusiveRange(start: T, end: T, step: T)`: Creates an `InclusiveRange` with the provided start, end and step. `step` will be an optional argument with a default value of step as 1 if `start <= end` or -1 if `start > end`. +- `InclusiveRange(_ start: T, _ end: T, step: T)`: Creates an `InclusiveRange` with the provided start, end and step. `step` will be an optional argument with a default value of step as 1 if `start <= end` or -1 if `start > end`. -- `ExclusiveRange(start: T, end: T, step: T)`: Creates an `ExclusiveRange` with the provided start, end and step. `step` will be an optional argument with a default value of step as 1 if `start < end` or -1 if `start > end`. +- `ExclusiveRange(_ start: T, _ end: T, step: T)`: Creates an `ExclusiveRange` with the provided start, end and step. `step` will be an optional argument with a default value of step as 1 if `start < end` or -1 if `start > end`. The following constraints are applicable in both the constructor functions: From 7a7986be71a84bb4ac239e3d367fe252bd3f4905 Mon Sep 17 00:00:00 2001 From: darkdrag00nv2 <122124396+darkdrag00nv2@users.noreply.github.com> Date: Tue, 20 Jun 2023 22:56:49 +0530 Subject: [PATCH 40/47] nit: multiple types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- cadence/20230602-cadence-range.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index 3c0dece8..f18a439d 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -6,11 +6,11 @@ sponsor: Bastian Müller (bastian@dapperlabs.com) updated: 2023-06-19 --- -# FLIP 96: Range Type +# FLIP 96: Range Types ## Objective -This FLIP proposes adding the concept of a `Range` to Cadence. It proposes two new types, `InclusiveRange` and `ExclusiveRange` along with constructor functions to create them. It also proposes their usage inside a `for-in` loop. +This FLIP proposes adding the concept of a range to Cadence. It proposes two new types, `InclusiveRange` and `ExclusiveRange` along with constructor functions to create them. It also proposes their usage inside a `for-in` loop. ## Motivation From 828142a6d8253c799ed899bfe1d4d091915d1e71 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Tue, 20 Jun 2023 23:20:42 +0530 Subject: [PATCH 41/47] Address review comments --- cadence/20230602-cadence-range.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index f18a439d..91146161 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -63,10 +63,9 @@ The following constraints are applicable in both the constructor functions: Violation of the above constraints will lead to runtime errors during instantiation. ### Public Members -Both `InclusiveRange` & `ExclusiveRange` will also provide the following public member variables and functions: +Both `InclusiveRange` & `ExclusiveRange` will also provide the following public members: -1. `count`: Returns the count of integers included in the Range. -2. `contains(value: T): Bool`: Returns if the Range includes the provided `value`. +1. `contains(value: T): Bool`: Returns if the Range includes the provided `value`. ### Examples @@ -84,7 +83,7 @@ for i in inclusiveRangeValue { // i will be 11, 12, 13, ... 20, 21 } -let inclusiveRangeValueWithStep = InclusiveRange(11, 20, 2) +let inclusiveRangeValueWithStep = InclusiveRange(11, 20, step: 2) inclusiveRangeValueWithStep.count // 5 inclusiveRangeValueWithStep.contains(20) // False since 20 cannot be produced from 11 using step of 2. for i in inclusiveRangeValueWithStep { @@ -98,15 +97,15 @@ for i in inclusiveRangeValue { // i will be 132, 131, 130, ... 34, 33 } -let inclusiveRangeValueBackwards = InclusiveRange(132, 33, -3) +let inclusiveRangeValueBackwards = InclusiveRange(132, 33, step: -3) inclusiveRangeValueBackwards.count // 15 inclusiveRangeValueBackwards.contains(34) // True for i in inclusiveRangeValue { // i will be 132, 125, 118, ... 41, 34 } -let invalidStep = InclusiveRange(10, 32, 0) // Runtime Error -let invalidDirection = InclusiveRange(132, 33, 3) // Runtime Error since the sequence moves in increasing direction. +let invalidStep = InclusiveRange(10, 32, step: 0) // Runtime Error +let invalidDirection = InclusiveRange(132, 33, step: 3) // Runtime Error since the sequence moves in increasing direction. //////////////////// // ExclusiveRange // @@ -120,7 +119,7 @@ for i in exclusiveRangeValue { // i will be 11, 12, 13, ... 19, 20 } -let exclusiveRangeValueWithStep = ExclusiveRange(11, 19, 2) +let exclusiveRangeValueWithStep = ExclusiveRange(11, 19, step: 2) exclusiveRangeValueWithStep.count // 4 exclusiveRangeValueWithStep.contains(19) // False for i in exclusiveRangeValueWithStep { @@ -134,16 +133,17 @@ for i in exclusiveRangeValue { // i will be 132, 131, 130, ... 35, 34 } -let exclusiveRangeValueBackwards = ExclusiveRange(132, 33, -3) +let exclusiveRangeValueBackwards = ExclusiveRange(132, 33, step: -3) exclusiveRangeValueBackwards.count // 15 +exclusiveRangeValueBackwards.contains(35) // False exclusiveRangeValueBackwards.contains(34) // True for i in exclusiveRangeValue { // i will be 132, 125, 118, ... 41, 34 } -let exclusiveRangeValueEmpty = ExclusiveRange(10, 10, 2) // Runtime Error -let invalidStep = ExclusiveRange(10, 32, 0) // Runtime Error -let invalidDirection = ExclusiveRange(132, 33, 3) // Runtime Error +let exclusiveRangeValueEmpty = ExclusiveRange(10, 10, step: 2) // Runtime Error +let invalidStep = ExclusiveRange(10, 32, step: 0) // Runtime Error +let invalidDirection = ExclusiveRange(132, 33, step: 3) // Runtime Error ``` ### Drawbacks From d3723078650a60f8ba48ca57a6695b2c613403d2 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Tue, 27 Jun 2023 22:29:54 +0530 Subject: [PATCH 42/47] Remove examples of count --- cadence/20230602-cadence-range.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index 91146161..ed12ab94 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -77,28 +77,24 @@ Example usage of `InclusiveRange` and `ExclusiveRange` types: //////////////////// let inclusiveRangeValue = InclusiveRange(11, 21) -inclusiveRangeValue.count // 11 inclusiveRangeValue.contains(20) // True for i in inclusiveRangeValue { // i will be 11, 12, 13, ... 20, 21 } let inclusiveRangeValueWithStep = InclusiveRange(11, 20, step: 2) -inclusiveRangeValueWithStep.count // 5 inclusiveRangeValueWithStep.contains(20) // False since 20 cannot be produced from 11 using step of 2. for i in inclusiveRangeValueWithStep { // i will be 11, 13, 15, 17, 19 } let inclusiveRangeValueBackwards = InclusiveRange(132, 33) -inclusiveRangeValueBackwards.count // 100 inclusiveRangeValueBackwards.contains(1) // False for i in inclusiveRangeValue { // i will be 132, 131, 130, ... 34, 33 } let inclusiveRangeValueBackwards = InclusiveRange(132, 33, step: -3) -inclusiveRangeValueBackwards.count // 15 inclusiveRangeValueBackwards.contains(34) // True for i in inclusiveRangeValue { // i will be 132, 125, 118, ... 41, 34 @@ -112,7 +108,6 @@ let invalidDirection = InclusiveRange(132, 33, step: 3) // Runtime Error since t //////////////////// let exclusiveRangeValue = ExclusiveRange(11, 21) -exclusiveRangeValue.count // 10 exclusiveRangeValue.contains(20) // True exclusiveRangeValue.contains(21) // False for i in exclusiveRangeValue { @@ -120,21 +115,18 @@ for i in exclusiveRangeValue { } let exclusiveRangeValueWithStep = ExclusiveRange(11, 19, step: 2) -exclusiveRangeValueWithStep.count // 4 exclusiveRangeValueWithStep.contains(19) // False for i in exclusiveRangeValueWithStep { // i will be 11, 13, 15, 17 } let exclusiveRangeValueBackwards = ExclusiveRange(132, 33) -exclusiveRangeValueBackwards.count // 99 exclusiveRangeValueBackwards.contains(1) // False for i in exclusiveRangeValue { // i will be 132, 131, 130, ... 35, 34 } let exclusiveRangeValueBackwards = ExclusiveRange(132, 33, step: -3) -exclusiveRangeValueBackwards.count // 15 exclusiveRangeValueBackwards.contains(35) // False exclusiveRangeValueBackwards.contains(34) // True for i in exclusiveRangeValue { From e961077f4c3f6757141d074fc2ca0c9f151959e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 5 Jul 2023 13:48:53 -0700 Subject: [PATCH 43/47] accept --- cadence/20230602-cadence-range.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index ed12ab94..376309e7 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -1,5 +1,5 @@ --- -status: draft +status: accepted flip: 96 authors: darkdrag00n (darkdrag00n@proton.me) sponsor: Bastian Müller (bastian@dapperlabs.com) From 2ab8fdf1b4d28a0f39d1c28dbb9897fca22a3b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 5 Jul 2023 13:49:17 -0700 Subject: [PATCH 44/47] update date --- cadence/20230602-cadence-range.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index 376309e7..1b0af7c2 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -3,7 +3,7 @@ status: accepted flip: 96 authors: darkdrag00n (darkdrag00n@proton.me) sponsor: Bastian Müller (bastian@dapperlabs.com) -updated: 2023-06-19 +updated: 2023-07-05 --- # FLIP 96: Range Types From 5f318f4da341e66030ef7b88e75c92042ac26a39 Mon Sep 17 00:00:00 2001 From: Supun Setunga Date: Wed, 5 Jul 2023 13:51:31 -0700 Subject: [PATCH 45/47] Change member access semantics (#89) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Bernatik Co-authored-by: Bastian Müller --- cadence/20230517-member-access-semnatics.md | 243 ++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 cadence/20230517-member-access-semnatics.md diff --git a/cadence/20230517-member-access-semnatics.md b/cadence/20230517-member-access-semnatics.md new file mode 100644 index 00000000..5bce98b3 --- /dev/null +++ b/cadence/20230517-member-access-semnatics.md @@ -0,0 +1,243 @@ +--- +status: accepted +flip: 89 +authors: Supun Setunga (supun.setunga@dapperlabs.com) +sponsor: Supun Setunga (supun.setunga@dapperlabs.com) +updated: 2023-07-05 +--- + +# FLIP 89: Change Member Access Semantics + +## Objective + +This proposal suggest to return a reference when accessing a member of a container (field of a composite value, +key of a map, index of an array), if the parent value is also a reference and the accessed member is a container type. + +## Motivation + +A previous version of Cadence ("Secure Cadence") restricted the potential foot-gun of mutating container-typed +`let` fields/variables via the +[Cadence mutability restrictions FLIP](https://github.com/onflow/flips/blob/main/cadence/20211129-cadence-mutability-restrictions.md). +However, this was a partial solution, and was only applicable for arrays and dictionaries, but did not solve it for +user-defined types. + +There are still ways to mutate such fields by: +- Directly mutating a nested composite typed field. +- Mutating a field by calling a mutating function on the field. +- Mutating the field via a reference. + +More details on this problem is described in the [FLIP for improving mutability restrictions](https://github.com/onflow/flips/pull/58). + +This proposal is aimed at moving one step closer to solving this problem by returning references for member-access, +so that [Entitlements](https://github.com/onflow/flips/pull/54) can be used to control who can perform mutating +operations via references. + +The [Mutability Restrictions Vision](https://github.com/onflow/flips/pull/97) explains how this proposed change +contributes to solving the aforementioned problems, and how the final solution looks like, with examples. + +## User Benefit + +As mentioned in the previous section, this change enables using Entitlements to prevent accidental mutations via references. + +## Design Proposal + +This proposal suggests field-access (i.e. `foo.bar`) and index-access (`foo[bar]`) to +return a reference to the targeting (field or element) value, instead of the value itself, if: + - The parent (i.e. `foo`) is a reference to a container-typed value. + - The accessed field/element is again container-typed. + +where a "container" is any of: + - Dictionary + - Array + - Composite + - An optional of above + +### Resource Example: + +For example, consider the below `Collection` resource which has two fields: one (`id`) is String-typed, +and the other (`ownedNFTs`) is dictionary-typed. + +```cadence +pub resource Collection { + + // Primitive-typed field + pub var id: String + + // Dictionary typed field + pub var ownedNFTs: @{UInt64: NFT} +} +``` + +#### Case I: Code owns the container value + +Assume `collection` is of type `Collection`. i.e. the code owns the value. +Then, there is no change to the current behavior. + +```cadence +var collection: @Collection <- ... + +// `collection.ownedNFTs` would return the concrete value, which is of type `@{UInt64: NFT}`. +// This is an error because it is not possible to move nested resource. +// This is same as existing semantics. +var ownedNFTs: @{UInt64: NFT} <- collection.ownedNFTs + +// `collection.id` would return the concrete string value. +// This is same as existing semantics. +var id: String = collection.id +``` + +#### Case II: Code only has a reference to the container value + +Assume a reference to the collection `collectionRef` is available, and is of type `&Collection`. +i.e. code doesn't own the value, but has only a reference to the value. + +```cadence +var collectionRef: &Collection = ... + +// `collectionRef.ownedNFTs` would now return a reference of type `&{UInt64: NFT}`. +var ownedNFTsRef: &{UInt64: NFT} = collectionRef.ownedNFTs + +// However, `collectionRef.id` would return the value, since it is a primitive type. +// This is same as existing semantics. +var id: String = collectionRef.id +``` + +It is also important to note that, the returned reference has no entitlements assigned to them. +i.e: they are **non-**`auth` references. + +#### Nested resources + +Assume a nested resource collection as bellow. + +```cadence +pub resource MasterCollection { + pub var kittyCollection: @Collection + pub var topshotCollection: @Collection +} + + +pub resource Collection { + pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + + access(Withdraw) fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") + emit Withdraw(id: token.id, from: self.owner?.address) + return <-token + } +} +``` + +Also, suppose a reference to the `MasterCollection` without any entitlements (i.e: non-auth) is available/borrowed. + +```cadence +var masterCollectionRef: @MasterCollection = ... +``` + +Previously, it was possible to withdraw from the inner collection, despite the `masterCollectionRef` not having the +`Withdraw` entitlement. + +```cadence +masterCollectionRef.kittyCollection.withdraw(24) // OK +``` + +With the proposed changes, this will be an error, since `masterCollectionRef.kittyCollection` is now return a +non-auth reference, and calling `withdraw` is prohibited because that reference doesn't have the `Withdraw` entitlement. + +```cadence +masterCollectionRef.kittyCollection.withdraw(24) // Static Error +``` + +### Struct Example: + +Similarly, consider the below `NFTView` struct which has two fields: one (`id`) is UInt64-typed, +and the other (`royalties`) is array-typed. + +```cadence +pub struct NFTView { + + // Primitive-typed field + pub var id: UInt64 + + // Array typed field + pub var royalties: [Royalty] +} +``` + +#### Case I: Code owns the container value + +Assume `nftView` is of type `NFTView`. i.e. the code owns the value. +Then, there is no change to the current behavior. + +```cadence +var nftView: NFTView = ... + +// `nftView.royalties` would return the concrete value, which is of type `[Royalty]`. +// This is same as existing semantics. +var royalties: [Royalty] = nftView.royalties + +// `nftView.id` would return the concrete `UInt64` value. +// This is same as existing semantics. +var id: UInt64 = collection.id +``` + +#### Case II: Code only has a reference to the container value + +Assume a reference to the nftView `nftViewRef` is available, and is of type `&NFTView`. +i.e. code doesn't own the value, but has only a reference to the value. + +```cadence +var nftViewRef: &Collection = ... + +// `nftViewRef.royalties` would now return a reference of type `&[Royalty]`. +var royaltiesRef: &[Royalty] = nftViewRef.royalties + +// However, `nftViewRef.id` would return the value, since it is a primitive type. +// This is same as existing semantics. +var id: String = nftViewRef.id +``` + +Similar to resources, the returned reference has no entitlements assigned to them. +i.e: they are **non-**`auth` references. + +### Drawbacks + +None + +### Alternatives Considered + +None + +### Performance Implications + +There is no direct performance impact by this change. + +However, since accessing a nested objects through a reference would now be returning reference, +it will avoid the copying of nested objects, which may increase the performance for certain use-cases. + +### Dependencies + +None + +### Engineering Impact + +This change has medium complexity in the implementation. + +### Compatibility + +This is a backward incompatible change. + +### User Impact + +Many deployed contracts might be affected by this change. + +## Related Issues + +None + +## Prior Art + +None + +## Questions and Discussion Topics + +None \ No newline at end of file From 98df56ce43f9142606b832361c22f15e966c49ef Mon Sep 17 00:00:00 2001 From: Jeff Doyle Date: Wed, 5 Jul 2023 14:24:24 -0700 Subject: [PATCH 46/47] Update Interaction Template Interface Fungible Token Transfer FLIP (#117) --- ...nteraction-template-interface-fungible-token-transfer.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/20220913-interaction-template-interface-fungible-token-transfer.md b/application/20220913-interaction-template-interface-fungible-token-transfer.md index 1cdc5113..87acd4f4 100644 --- a/application/20220913-interaction-template-interface-fungible-token-transfer.md +++ b/application/20220913-interaction-template-interface-fungible-token-transfer.md @@ -1,12 +1,12 @@ --- -status: draft -flip: TBD +status: proposed +flip: 9 authors: Jeffrey Doyle (jeffrey.doyle@dapperlabs.com) sponsor: Jeffrey Doyle (jeffrey.doyle@dapperlabs.com) updated: 2022-09-13 --- -# Interaction Template Interface | Fungible Token Transfer Transaction (DRAFT) +# Interaction Template Interface | Fungible Token Transfer Transaction ## Abstract From 0f4c8d9f2cddd59cab266cb88ce57fdc9215f421 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 11 Jul 2023 12:31:13 -0400 Subject: [PATCH 47/47] add FLIP for removing type requirements --- cadence/20230711-remove-type-requirements.md | 126 +++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 cadence/20230711-remove-type-requirements.md diff --git a/cadence/20230711-remove-type-requirements.md b/cadence/20230711-remove-type-requirements.md new file mode 100644 index 00000000..0c1eeb24 --- /dev/null +++ b/cadence/20230711-remove-type-requirements.md @@ -0,0 +1,126 @@ +--- +status: draft +flip: NNN (do not set) +authors: Daniel Sainati (daniel.sainati@dapperlabs.com) +sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) +updated: 2023-07-11 +--- + +# Remove Type Requirements from Cadence + +## Objective + +Currently, it is possible for a contract interface to declare a nested concrete type within itself. +When this occurs, it requires any contracts that implement this interface to also provide an implementation +of that nested concrete type. So, for example, given the following contract definition: + +```cadence +access(all) contract interface Outer { + access(all) resource Nested { + access(all) field: Int + } +} + +access(all) contract ExampleOuter: Outer { + access(all) resource Nested { + access(all) var field: Int + init(field: Int) { + self.field = field + } + } +} +``` + +The definition of `Outer` includes a definition of a concrete type `Nested`. +However, note that this concrete type is actually defined like an interface, and includes no implementation. +Instead, this definiton of `Nested` requires any contracts implementing `Outer` to provide a definition of `Nested` +that conforms to the specification provided in `Outer`. This is called a nested type requirement. + +## Motivation + +Type requirements are a very complex feature, both in their use and their implementation. + +In their usage, they behave differently than any other concrete type definitions, +and as such are a source of confusion for users. +Additionally they result in a large amount of boilerplate code for any contracts that implement +these interfaces, as they need to implement all of the type requirements, even when they are not +required for the specific functionality of the implementing contract. + +From the implementation side, +they require a great deal of special-cased behavior that complicates the Cadence codebase. + +Removing this feature would simplify the language both for the users and the implementors, +and with the addition of the ability to emit events direclty from interfaces, +the primary use-case for this feature (requiring contracts to define certain events) has been removed. + +## User Benefit + +This will simplify the language for users. + +## Design Proposal + +This will require two related changes to the codebase: + +### Defining Concrete Events in Interfaces + +First, the semantics of declaring an event in an interface will need to be changed. +Currently, a definition such as + +```cadence +access(all) contract interface Interface { + access(all) event Foo() +} +``` + +does not declare a concrete event type `Foo`, but rather specifies a type requirement enforcing +that all concrete contracts implementing `Interface` also specify a `Foo` event type. +This is unnecessary boilerplate, since implementing `Interface` gives the implementer no choice +in how they implement `Foo`; they must simply copy the definition of `Foo` from the interface +to the concrete contract. + +We can remove this unnecessary code duplication by changing the semantics of this code to instead +define a concrete event type `Foo`, which can be referenced as such within `Interface` (i.e. if it is +emitted by a condition or default implementation of one of `Interface`'s functions), or as a qualified +type `Interface.Foo` elsewhere. + +### Ban Non-Event Concrete Type Declarations in Interfaces + +Coupled with this change to events would be a ban on definitions of all other concrete types inside interfaces. +Specifically, resources, structs, enums, and attachments would no longer be declarable inside of interfaces. +Attempting to declare a concrete type in an interface would result in a static error. + +Removing the ability to define a non-event concrete type in an interface, +coupled with the change to the semantics of event definitions, would mean that the necessary first step of +creating a type requirement (a concrete type definition in a contract interface) would become impossible, +thus allowing us to remove all references and uses of this feature from the Cadence codebase. + +### Drawbacks + +This will break any code that currently relies on nested type requirements. + +### Alternatives Considered + +It is possible to leave this feature present in the language without blocking anything else. +However, the release of Stable Cadence is our only chance to remove this complex legacy feature, +and if we don't do it now we will be forced to support it indefinitely. + +It is also possible to change all concrete type declarations in interfaces to instead declare +a qualified concrete type, instead of just having events behave this way and banning the definitions +for other types. This would extend the changes to the semantics for event definitions to all concrete types. + +### Tutorials and Examples + +Existing tutorials or examples that make use of type requirements will need to be updated. + +### User Impact + +This will break a large amount of existing user code. +Existing contracts that provide implementations for type requirements will not be updatable (since nested +type definitions cannot be removed), however these themselves will not break. Rather, the upstream +contract interfaces that provide the type requirements will instead break. These will be removable +as they are not actually nested type definitions. + +## Questions and Discussion Topics + +* Between banning all non-event nested concrete definitions and changing them to behave like the proposed +new event definitions, which do we prefer?