From 974314d71230c2a7102638480f2437290b4cf35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 10 Mar 2026 13:44:17 -0700 Subject: [PATCH] implemented -> released --- ...0211129-cadence-mutability-restrictions.md | 2 +- ...11208-cadence-remove-optional-reference.md | 2 +- .../20211208-cadence-storage-api-changes.md | 2 +- .../20211210-cadence-numeric-supertypes.md | 2 +- cadence/20220203-capability-controllers.md | 8 +- .../20220516-reference-creation-semantics.md | 2 +- ...0220708-resource-reference-invalidation.md | 4 +- cadence/20220715-cadence-purity-analysis.md | 2 +- cadence/20220725-cadence-borrowContract.md | 2 +- cadence/20220908-publish-claim-capability.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 | 192 +++++++++--------- ...20230417-events-emitted-from-interfaces.md | 20 +- cadence/20230503-improve-conformance.md | 4 +- cadence/20230505-remove-priv-and-pub.md | 34 ++-- cadence/20230505-remove-restricted-types.md | 32 +-- cadence/20230517-member-access-semnatics.md | 12 +- ...230519-built-in-mutability-entitlements.md | 16 +- cadence/20230525-account-type.md | 2 +- cadence/20230602-cadence-range.md | 4 +- cadence/20230623-entitlement-improvements.md | 4 +- cadence/20230711-remove-type-requirements.md | 82 ++++---- cadence/20230713-random-function.md | 62 +++--- cadence/20230811-destructor-removal.md | 94 ++++----- .../20230816-relax-interface-conformance.md | 2 +- .../20230913-restrict-capabilities-publish.md | 16 +- .../20231016-entitlement-mapping-syntax.md | 18 +- ...0231016-reject-references-to-references.md | 2 +- ...231023-cadence-attachments-entitlements.md | 54 ++--- ...3-capcon-get-capability-api-improvement.md | 14 +- ...e-non-public-entitled-interface-members.md | 2 +- cadence/20240604-cadence-type-removal.md | 36 ++-- .../20240612-import-contract-as-reference.md | 16 +- cadence/20240726-pre-cadence-1-import.md | 2 +- .../20240923-simple-string-interpolation.md | 18 +- cadence/20241010-stringer-interface.md | 2 +- cadence/20241212-import-aliasing.md | 4 +- cadence/20250815-128-bit-fixed-point-types.md | 6 +- ...-Fix-number-type-division-inconsistancy.md | 6 +- 43 files changed, 397 insertions(+), 397 deletions(-) diff --git a/cadence/20211129-cadence-mutability-restrictions.md b/cadence/20211129-cadence-mutability-restrictions.md index dcba19684..20879088d 100644 --- a/cadence/20211129-cadence-mutability-restrictions.md +++ b/cadence/20211129-cadence-mutability-restrictions.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 a060afcb1..68f381efd 100644 --- a/cadence/20211208-cadence-remove-optional-reference.md +++ b/cadence/20211208-cadence-remove-optional-reference.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 45310cd32..885f9e781 100644 --- a/cadence/20211208-cadence-storage-api-changes.md +++ b/cadence/20211208-cadence-storage-api-changes.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 f740afced..3f6833882 100644 --- a/cadence/20211210-cadence-numeric-supertypes.md +++ b/cadence/20211210-cadence-numeric-supertypes.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 0e458fdc8..c858c33dd 100644 --- a/cadence/20220203-capability-controllers.md +++ b/cadence/20220203-capability-controllers.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 798 authors: Janez Podhostnik (janez.podhostnik@dapperlabs.com), Bastian Müller (bastian@dapperlabs.com) updated: 2024-06-26 @@ -565,18 +565,18 @@ Existing links and capabilities need to be migrated. ### Migration of storage links Each existing storage link is dereferenced to its *target storage path* (`/storage`). -To determine the target storage path, the link's *source capability path* (`/public` or `/private`) +To determine the target storage path, the link's *source capability path* (`/public` or `/private`) is followed until a storage (`/storage`) path is encountered. For each valid link, a new Storage Capability Controller will be issued. -If the source path is public (`/public`), the resulting capability gets published. +If the source path is public (`/public`), the resulting capability gets published. Note that it is not necessary for the storage path to contain any value at the time of migration. ### Migration of account links For each existing account link a new Accout Capability Controller will be issued. -If the source path is public (`/public`), the resulting capability gets published. +If the source path is public (`/public`), the resulting capability gets published. ### Migration of capabilities diff --git a/cadence/20220516-reference-creation-semantics.md b/cadence/20220516-reference-creation-semantics.md index 7829ed0a1..96e1b5dd0 100644 --- a/cadence/20220516-reference-creation-semantics.md +++ b/cadence/20220516-reference-creation-semantics.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 941 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) diff --git a/cadence/20220708-resource-reference-invalidation.md b/cadence/20220708-resource-reference-invalidation.md index b1eb3cca1..3305f8147 100644 --- a/cadence/20220708-resource-reference-invalidation.md +++ b/cadence/20220708-resource-reference-invalidation.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 1043 authors: Supun Setunga (supun.setunga@dapperlabs.com) sponsor: Supun Setunga (supun.setunga@dapperlabs.com) @@ -120,7 +120,7 @@ Developers will have to update their code to remove the use of references to mov 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. +[1] Sample Cadence code for the potential security foot-gun of references with stack to stack transfers. ```cadence access(all) contract Buyer { diff --git a/cadence/20220715-cadence-purity-analysis.md b/cadence/20220715-cadence-purity-analysis.md index 1562e703c..bd125bc4e 100644 --- a/cadence/20220715-cadence-purity-analysis.md +++ b/cadence/20220715-cadence-purity-analysis.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 1056 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) diff --git a/cadence/20220725-cadence-borrowContract.md b/cadence/20220725-cadence-borrowContract.md index 51415fde2..4a71d6fb3 100644 --- a/cadence/20220725-cadence-borrowContract.md +++ b/cadence/20220725-cadence-borrowContract.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 1071 authors: Deniz Mert Edincik (deniz@edincik.com) sponsor: Austin Kline (austin@flowty.io) diff --git a/cadence/20220908-publish-claim-capability.md b/cadence/20220908-publish-claim-capability.md index eda2650d9..c0d8e2e10 100644 --- a/cadence/20220908-publish-claim-capability.md +++ b/cadence/20220908-publish-claim-capability.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 1122 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 0b6daa0a4..e02afc7f3 100644 --- a/cadence/20220921-attachments.md +++ b/cadence/20220921-attachments.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 a76ed4a7a..e89d399f5 100644 --- a/cadence/20221011-for-loop-semantics.md +++ b/cadence/20221011-for-loop-semantics.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 d3292415e..fe5ca4f25 100644 --- a/cadence/20221018-change-fun-type-syntax.md +++ b/cadence/20221018-change-fun-type-syntax.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 ce406800c..c62032007 100644 --- a/cadence/20221024-interface-inheritance.md +++ b/cadence/20221024-interface-inheritance.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 c9dec6b1a..65a2a5e26 100644 --- a/cadence/20221207-authaccount-capabilities.md +++ b/cadence/20221207-authaccount-capabilities.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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 e68c975d6..e1f59c9b5 100644 --- a/cadence/20221214-auth-remodel.md +++ b/cadence/20221214-auth-remodel.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 54 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) @@ -20,34 +20,34 @@ Currently in Cadence, when users are in possession of a reference value, unless with an `auth` type, users are unable to downcast that reference to a more specific type. This restriction exists for security reasons; it should not be possible for someone with a `&{Balance}` reference to downcast that to a `&Vault`. Cadence's current access control model relies on exposing limited interfaces to grant others capabilities -to resources they own. +to resources they own. However, this can often result in restrictions that are unnecessary and onerous to users. In the above example, a user with a `&{Balance}` reference would not be able to cast that reference to a `&{Receiver}` reference, despite the fact -that there would be no safety concerns in doing so; it should be possible to call `deposit` regardless of what kind of -reference a user possesses. +that there would be no safety concerns in doing so; it should be possible to call `deposit` regardless of what kind of +reference a user possesses. The proposed change is designed to overcome this limitation by allowing developers to directly mark which fields and functions -should be access-limited using these new bespoke modifiers, and which should be generally available to anyone. - +should be access-limited using these new bespoke modifiers, and which should be generally available to anyone. + ## User Benefit This feature would make interacting with references significantly easier, as users would no longer be restricted from -accessing methods like `deposit` that are safe for anyone to use, just because they do not possess a reference of the specific type, -or because they are trying to write a generic method that works, say, on any `NFT` type. +accessing methods like `deposit` that are safe for anyone to use, just because they do not possess a reference of the specific type, +or because they are trying to write a generic method that works, say, on any `NFT` type. -It would also increase safety, as we would be able to do additional checking on the values and types to which users create capabilities. -For example, it is currently possible for a user to (presumably accidentally) create a public Capability directly to a `Vault` object, -rather than a Capability to a `&{Balance, Receiver}` restricted type as is intended. With these changes, such a Capability still would +It would also increase safety, as we would be able to do additional checking on the values and types to which users create capabilities. +For example, it is currently possible for a user to (presumably accidentally) create a public Capability directly to a `Vault` object, +rather than a Capability to a `&{Balance, Receiver}` restricted type as is intended. With these changes, such a Capability still would not be subject to having its funds `withdraw`n, as this `Vault` Capability would not be `auth(Provider)`. In order to have access to an `auth` method like `withdraw`, the user would need to explicitly create the Capability with an `auth(Provider)` reference, and we could enforce statically -(or warn) that `auth` reference capabilies should not be stored publicly. +(or warn) that `auth` reference capabilies should not be stored publicly. ## Design Proposal ### Entitlements -The first part of this FLIP proposes to add a new declaration type to Cadence: `entitlement`s. `entitlement` declarations are simple, +The first part of this FLIP proposes to add a new declaration type to Cadence: `entitlement`s. `entitlement` declarations are simple, just the keyword `entitlement` and the name; we only require that they be pre-declared to guard against typos and other minor errors. A sample `entitlement` may look like this: @@ -72,12 +72,12 @@ resource R { ``` A single member definition can include multiple entitlements, using either a `|` or a `,` separator when defining the list. -An entitlement list defined using a `|` functions like a disjunction (or an "or"); it is accessible to any `auth` reference with any of those entitlements. -An entitlement list defined using a `,` functions like a conjunction set (or an "and"); it is accessible only to an `auth` reference with all of those entitlements. +An entitlement list defined using a `|` functions like a disjunction (or an "or"); it is accessible to any `auth` reference with any of those entitlements. +An entitlement list defined using a `,` functions like a conjunction set (or an "and"); it is accessible only to an `auth` reference with all of those entitlements. -Note that these operators cannot be mixed within a single list; any entitlement access modifier may use either `|` or `,`, but not both. +Note that these operators cannot be mixed within a single list; any entitlement access modifier may use either `|` or `,`, but not both. -So, for example, in +So, for example, in ```cadence entitlement E @@ -90,9 +90,9 @@ resource R { `foo` is only calleable on a reference to `R` that is `auth` for both `E` and `F`, while `bar` is calleable on any `auth` reference that is `auth` for either `E` or `F` (or both). -Like `access(contract)` and `access(account)`, this new modifier sits exactly between `pub` and `priv` (or equivalently `access(self)`) -in permissiveness; it allows less access than `pub`, but strictly more than `priv`, as an `access(E)` field or function can be used anywhere -in the implementation of the composite. To see why, consider that `self` is necessarily of the same type as the composite, meaning +Like `access(contract)` and `access(account)`, this new modifier sits exactly between `pub` and `priv` (or equivalently `access(self)`) +in permissiveness; it allows less access than `pub`, but strictly more than `priv`, as an `access(E)` field or function can be used anywhere +in the implementation of the composite. To see why, consider that `self` is necessarily of the same type as the composite, meaning that the access rules defined above allow any `access(I)` members to be accessed on it. A table summarizing the new access modifiers is included here: @@ -101,7 +101,7 @@ that the access rules defined above allow any `access(I)` members to be accessed | `access(self)` (`priv`) | Methods defined within the same type object. | | `access(contract)` | Methods defined within the same smart contract object. | | `access(account)` | Methods defined in a contract deployed to the same account. | -| `access(E)` | Code holding an `auth(E)` reference for some defined entitlement `E`. | +| `access(E)` | Code holding an `auth(E)` reference for some defined entitlement `E`. | | `access(all)` (`pub`) | Any code with any reference to the object. | As specified above, note that actual ownership of an object grants access to any `access(E)` member for any `E`. @@ -133,15 +133,15 @@ let ref: auth(E) &R = &r ref.foo() ``` -Note also that while the normal interface implementation subtyping rules would allow a composite to implement an `access(E)` interface member with a `pub` -composite member, as this is less restrictive, in order to prevent users from accidentally surrendering authority and security this way, we prevent this statically. +Note also that while the normal interface implementation subtyping rules would allow a composite to implement an `access(E)` interface member with a `pub` +composite member, as this is less restrictive, in order to prevent users from accidentally surrendering authority and security this way, we prevent this statically. As such, the below code would not typecheck. ```cadence pub entitlement E pub resource interface I { - access(E) fun foo() + access(E) fun foo() } pub resource R: I { @@ -149,7 +149,7 @@ pub resource R: I { } ``` -If users would like to expose an access-limited function to `pub` users, they can do so by wrapping the `access(E)` function in a `pub` function. +If users would like to expose an access-limited function to `pub` users, they can do so by wrapping the `access(E)` function in a `pub` function. As with normal subtyping, this would also be statically rejected: @@ -157,7 +157,7 @@ As with normal subtyping, this would also be statically rejected: pub entitlement E pub resource interface I { - pub fun foo() + pub fun foo() } pub resource R: I { @@ -165,20 +165,20 @@ pub resource R: I { } ``` -since if this were to typecheck, anybody with a `&R` reference could upcast it to `&{I}` and thus gain the ability to call `foo`. +since if this were to typecheck, anybody with a `&R` reference could upcast it to `&{I}` and thus gain the ability to call `foo`. -When multiple interfaces declare the same function with different entitlements, a composite implementing both interfaces must use the `|` union of the function's entitlement +When multiple interfaces declare the same function with different entitlements, a composite implementing both interfaces must use the `|` union of the function's entitlement sets as the access modifier for that function. E.g. ```cadence pub entitlement E pub resource interface I { - access(E) fun foo() + access(E) fun foo() } pub entitlement F pub resource interface G { - access(F) fun foo() + access(F) fun foo() } pub resource R: I, G { @@ -194,10 +194,10 @@ pub resource T: I, G { ### Safely Downcastable References -The second, more complex part of this proposal, is a change to the behavior of references to allow the `auth` modifier not to -refer to the entire referenced value, but to the specific set of interfaces to which the referenced value has `auth` permissions (the reference's entitlements). +The second, more complex part of this proposal, is a change to the behavior of references to allow the `auth` modifier not to +refer to the entire referenced value, but to the specific set of interfaces to which the referenced value has `auth` permissions (the reference's entitlements). To express this, the `auth` keyword can now be used with similar syntax to that of restricted types: `auth(E1, E2, ...)`, where the `E`s -in the parentheses denote the entitlements. This permits these references to access `access(E)` members for any `E` entitlement they possess. +in the parentheses denote the entitlements. This permits these references to access `access(E)` members for any `E` entitlement they possess. So, for example, given two entitlement definitions and a composite definition: ```cadence @@ -211,30 +211,30 @@ pub resource R { ``` a value of type `auth(A) &R` would be able to access `foo`, because the reference has the `A` entitlement, but not `bar`, because -it does not have an entitlement for `B`. However, `baz` would be accessible on this reference, since it has `pub` access. +it does not have an entitlement for `B`. However, `baz` would be accessible on this reference, since it has `pub` access. -The other part of this change is to remove the limitations on resource downcasting that used to exist. Prior to this change, +The other part of this change is to remove the limitations on resource downcasting that used to exist. Prior to this change, non-`auth` references could not be downcast at all, since the sole purpose of the `auth` keyword was to indicate that references could be downcast. With the proposed change, all reference types can be downcast or upcast the same way any other type would be. So, for example `&{I} as! &R` would be valid, as would `&AnyResource as? &{I}` or `&{I} as? &{J}`, using the hierarchy defined above (for any `J`). -However, the `auth`-ness (and the reference's set of entitlements) would not change on downcasting, nor would that set be expandable via casting. -In fact, the set of entitlements to which a reference is authorized is purely a static construct, and entitlements do not exist as a concept at runtime. -In particular, what this means that it is not ever possible to downcast a reference to a type with a more restrictive set of entitlements. +However, the `auth`-ness (and the reference's set of entitlements) would not change on downcasting, nor would that set be expandable via casting. +In fact, the set of entitlements to which a reference is authorized is purely a static construct, and entitlements do not exist as a concept at runtime. +In particular, what this means that it is not ever possible to downcast a reference to a type with a more restrictive set of entitlements. -As such, while `auth(A, B) &R` would be statically upcastable to `auth(A) &R`, since this decreases the permissions on the +As such, while `auth(A, B) &R` would be statically upcastable to `auth(A) &R`, since this decreases the permissions on the reference, it would not be possible to go from `auth(A) &R` to `auth(A, B) &R`. The subtyping rules for `auth` references is that `auth (U1, U2, ... ) &X <: auth (T1, T2, ... ) &X` whenever `{U1, U2, ...}` is a superset of `{T1, T2, ...}`, or equivalently `∀T ∈ {T1, T2, ...}, ∃U ∈ {U1, U2, ...}, T = U`. Of course, all `auth` reference types -would remain subtypes of all non-`auth` reference types as before. +would remain subtypes of all non-`auth` reference types as before. -In addition to the `,`-separated list of entitlements (which defines a conjunction/"and" set for `auth` modifiers similarly to its behavior for `access` modifiers), it is also possible, +In addition to the `,`-separated list of entitlements (which defines a conjunction/"and" set for `auth` modifiers similarly to its behavior for `access` modifiers), it is also possible, although very rarely necessary, to define `|`-separated entitlement lists in `auth` modifers for references, like so: `auth(E1 | E2 | ...) &T`. In this case, the type denotes that the reference to `T` is authorized for **at least one** of the entitled specified, not that it is `auth` for all of them. This means, for example, that an `auth(A | B) &R` reference -would not be permitted to call an `access(A)` function on `R`, because we only know that the reference is authorized for one of `A` **or** `B`, and cannot guarantee that it is permitted to -call an `A`-entitled function. However, an `auth(A | B) &R` reference could call an `access(A | B)` function on `R`, because the function requires one of `A` or `B`, and we know -that our reference has at least one of these entitlements. +would not be permitted to call an `access(A)` function on `R`, because we only know that the reference is authorized for one of `A` **or** `B`, and cannot guarantee that it is permitted to +call an `A`-entitled function. However, an `auth(A | B) &R` reference could call an `access(A | B)` function on `R`, because the function requires one of `A` or `B`, and we know +that our reference has at least one of these entitlements. ```cadence entitlement E @@ -257,14 +257,14 @@ The subtyping rules for `|`-separated entitlement lists allow lists to expand on the reference's entitlements and thus permits fewer operations. In general, `auth (U1 | U2 | ... ) &X <: auth (T1 | T2 | ... ) &X` whenever `{U1, U2, ...}` is a subset of `{T1, T2, ...}`, or equivalently `∀U ∈ {U1, U2, ...}, ∃T ∈ {T1, T2, ...}, T = U`. -`,`-separated entitlement lists subtype `|`-separated ones as long as the two sets are not disjoint; that is, as long as there is an entitlement in the subtype set that is also in the supertype set. -This is because we are casting from a type that is known to possess all of the listed entitlements to a type that is only guaranted to possess one. More specifically, +`,`-separated entitlement lists subtype `|`-separated ones as long as the two sets are not disjoint; that is, as long as there is an entitlement in the subtype set that is also in the supertype set. +This is because we are casting from a type that is known to possess all of the listed entitlements to a type that is only guaranted to possess one. More specifically, `auth (U1, U2, ... ) &X <: auth (T1 | T2 | ... ) &X` whenever `{U1, U2, ...}` is not disjoint from `{T1, T2, ...}`, or equivalently `∃U ∈ {U1, U2, ...}, ∃T ∈ {T1, T2, ...}, T = U`. In practice `|`-separated entitlement lists never subtype `,`-separated ones except in the trivial case. This is because we are attempting to upcast (change the type without gaining any new specificity) from a reference where we only know we possess at least one of the listed entitlement to one where we know we possess all of them. This is only possible when all of the references -in both lists are equal. More specifically, `auth (U1 | U2 | ... ) &X <: auth (T1, T2, ... ) &X` whenever `∀U ∈ {U1, U2, ...}, ∀T ∈ {T1, T2, ...}, T = U`. -As one can see, this is only possible when every `U` and `T` are the same entitlement, or when the two entitlement lists each only have a single equivalent element. +in both lists are equal. More specifically, `auth (U1 | U2 | ... ) &X <: auth (T1, T2, ... ) &X` whenever `∀U ∈ {U1, U2, ...}, ∀T ∈ {T1, T2, ...}, T = U`. +As one can see, this is only possible when every `U` and `T` are the same entitlement, or when the two entitlement lists each only have a single equivalent element. ### Entitlement Mapping and Nested Values @@ -290,18 +290,18 @@ resource OuterResource { } init(r: @SubResource) { - self.childResource <- r + self.childResource <- r } } ``` With this pattern, we can store to a `SubResource` on an `OuterResource` value, and create different ways to access that nested resource depending on the entitlement oneposseses. -Somoneone with only an unauthorized reference to `OuterResource` can only call the `getPubRef` function, and thus can only get an unauthorized reference to `SubResource` that lets them call `foo`. +Somoneone with only an unauthorized reference to `OuterResource` can only call the `getPubRef` function, and thus can only get an unauthorized reference to `SubResource` that lets them call `foo`. However, someone with a `OuterEntitlement`-authorized refererence to the `OuterResource` can call the `getEntitledRef` function, giving them a `SubEntitlement`-authorized reference to `SubResource` that -allows them to call `bar`. +allows them to call `bar`. This pattern is functional, but it is unfortunate that we are forced to "duplicate" the accessors to `SubResource`, duplicating the code and storing two functions on the object, essentially creating -two different views to the same object that are stored as different functions. To avoid necessitating this duplication, we add support to the language for "entitlement mappings", a way to declare +two different views to the same object that are stored as different functions. To avoid necessitating this duplication, we add support to the language for "entitlement mappings", a way to declare statically how entitlements are propagated from parents to child objects in a nesting hierarchy. So, the above example could be equivalently written as: ```cadence @@ -322,7 +322,7 @@ resource SubResource { resource OuterResource { access(self) let childResource: @SubResource // by referering to `Map` here, we declare that the entitlements we receive when accessing the `getRef` function on this resource - // will depend on the entitlements we possess to the resource during the access. + // will depend on the entitlements we possess to the resource during the access. access(Map) fun getRef(): auth(Map) &SubResource { return &self.childResource as auth(Map) &SubResource } @@ -350,16 +350,16 @@ entitlement mapping M { } ``` -If this mapping were used to define the `auth` access of a nested resource reference, one could obtain a `C`-entitled reference to that nested resource with either an -`A` or a `B` entitled outer reference. Conversely, an `A`-entitled outer reference would yield a nested reference entitled for both `C` and `D`. Specifically, if the +If this mapping were used to define the `auth` access of a nested resource reference, one could obtain a `C`-entitled reference to that nested resource with either an +`A` or a `B` entitled outer reference. Conversely, an `A`-entitled outer reference would yield a nested reference entitled for both `C` and `D`. Specifically, if the field with the nested reference were called `foo`, then we'd get these different outputs for differently typed `ref` inputs: * if `ref` was typed as `&Outer`, then `ref.foo` would just be an `&Inner` * if `ref` was typed as `auth(A) Outer`, then `ref.foo` would be `auth(C, D) &Inner`, since `A` maps to both of these outputs * if `ref` was typed as `auth(B) Outer`, then `ref.foo` would be `auth(C) &Inner`, since `B` maps only to `C` * if `ref` was typed as `auth(A | B) Outer`, then `ref.foo` would be `auth(C) &Inner`, since `C` is mapped to by both of these inputs -Note, however, that because the `|` and `,` typed entitlement sets cannot be mixed (this is a restriction for simplicity more than anything else), it is not possible to use non 1:1 -mappings in situations where their output would be an unrepresentable entitlement set. So with this mapping: +Note, however, that because the `|` and `,` typed entitlement sets cannot be mixed (this is a restriction for simplicity more than anything else), it is not possible to use non 1:1 +mappings in situations where their output would be an unrepresentable entitlement set. So with this mapping: ```cadence entitlement mapping M { @@ -369,7 +369,7 @@ entitlement mapping M { F -> D } ``` -We would have the following access relationship: +We would have the following access relationship: * if `ref` was typed as `&auth(E) Outer`, then `ref.foo` would be `auth(A, B) &Inner` * if `ref` was typed as `&auth(F) Outer`, then `ref.foo` would be `auth(C, D) &Inner` @@ -399,19 +399,19 @@ resource OuterResource { If this were to succeed, then a user could create an `OuterResource` with only a `B`-entitled reference to `SubResource`, and use the mapping on it to get a `D`-entitled reference to the `SubResource`, since the owner of the `OuterResource` can get any entitled reference to it. In order to be a valid initial value for the `self.ref` field here, the `ref` argument to the constructor would need to have type `auth(B, D, E) &SubResource`. This is most easily achievable if the creator of the `OuterResource` is also -the owner of the inner resource. +the owner of the inner resource. #### Attachments and Entitlements -Attachments would interact with entitlements and access-limited members in a nuanced but intuitive manner, using the entitlement mapping feature described above. Instead -of requiring that all attachment declarations are `pub`, they can additionally be declared with an `access(E)` modifier, where `E` is the name of an entitlement mapping. +Attachments would interact with entitlements and access-limited members in a nuanced but intuitive manner, using the entitlement mapping feature described above. Instead +of requiring that all attachment declarations are `pub`, they can additionally be declared with an `access(E)` modifier, where `E` is the name of an entitlement mapping. When declared with an entitlement mapping access, the attachment's entitlements are propagated from the entitlements of its `base` value according to the mapping. Attachments would remain `pub` accessible, but would permit the declaration of `access`-limited members. So, for example, given some declarations like: ```cadence entitlement E entitlement F entitlement mapping M { - E -> F + E -> F } access(M) attachment A for R {} ``` @@ -420,11 +420,11 @@ given a reference to `r` called `ref`, when `ref` has type `&R` then `ref[A]` ha owned values are considered fully entitled, accessing `A` directly off of an `@R`-typed value `r` will yield a reference to `A` that is fully entitled, that is, an `A` reference that is authorized for the entire image of `M`. -Within the declaration of the attachment itself, the members of the attachments can use any entitlements that exist in the image of `M`, but cannot use other entitlements as the -attachment access semantics would make it impossible to obtain a reference to the attachment with entitlements not in the image of `M`. +Within the declaration of the attachment itself, the members of the attachments can use any entitlements that exist in the image of `M`, but cannot use other entitlements as the +attachment access semantics would make it impossible to obtain a reference to the attachment with entitlements not in the image of `M`. Within `A`'s member functions, the `self` value is an `&A` reference that is fully entitled to the image of `M`. This results in similar behavior to regular composite declarations, -where `self` is fully entitled because it is an owned value. +where `self` is fully entitled because it is an owned value. Meanwhile, the `base` value would have slightly more complex semantics. In the default case, the `base` value is an unentitled reference, which will prevent attachment authors from using the `base` to access restricted functionality on the base resource. However, if the author of an attachment needs a specific entitlement on the `base` @@ -437,7 +437,7 @@ entitlement F entitlement X entitlement Y entitlement mapping M { - E -> F + E -> F X -> Y } access(M) attachment A for R { @@ -446,12 +446,12 @@ access(M) attachment A for R { } ``` -`base` will be considered to possess an `X` entitlement within all the members of `A`. +`base` will be considered to possess an `X` entitlement within all the members of `A`. Creating attachments that require certain entitlements can be done with an extension to the original `attach` expression: `attach A() to v with X, Y, ...`. Here the `A()` is an attachment constructor call as before, while `v` is the value to which the attachment is to be attached. However, after this the user may optionally -provide a `with` followed by a list of entitlements which they wish to give to `A`. This list must superset the list of entitlements required by `A`'s declaration, -or the attach expression will fail to typecheck. This way the user must be explicit about what permissions they are giving to each attachment they create. +provide a `with` followed by a list of entitlements which they wish to give to `A`. This list must superset the list of entitlements required by `A`'s declaration, +or the attach expression will fail to typecheck. This way the user must be explicit about what permissions they are giving to each attachment they create. Putting all of these rules together, we can see that given the following declaration: ```cadence @@ -479,16 +479,16 @@ access(ConverterMap) attachment CurrencyConverter for Provider { } access(ConvertAndWithdraw) fun withdraw(_ amount: UFix64): @Vault { - let convertedAmount = self.convert(amount) + let convertedAmount = self.convert(amount) // this is permitted because the attachment declaration explicitly requires an entitlement to `Withdraw` - return <-base.withdraw(amount: amount) + return <-base.withdraw(amount: amount) } access(all) fun deposit (from: @Vault) { // cast is permissable under the new reference casting rules let baseReceiverOptional = base as? &{Receiver} if let baseReceiver = baseReceiverOptional { - let convertedVault <- self.convertVault(<-from) + let convertedVault <- self.convertVault(<-from) // this is ok because `deposit` has `all` access baseReceiver.deposit(from: <-convertedVault) } @@ -502,14 +502,14 @@ let converterRef = authVaultReference[CurrencyConverter]! // has type auth(Conve ### Drawbacks -This dramatically increases the complexity of references and capabilities by requiring users to think not only about which types they -are creating the references with, but also which entitlements they are providing on each reference they create. It also increases -the implementation complexity of the type system significantly by adding an additional dimension to the reference type's subtype heirarchy. +This dramatically increases the complexity of references and capabilities by requiring users to think not only about which types they +are creating the references with, but also which entitlements they are providing on each reference they create. It also increases +the implementation complexity of the type system significantly by adding an additional dimension to the reference type's subtype heirarchy. ### Best Practices This would encourage users to use the new `auth` access modifier to restrict access on their contracts and resources; and use different -entitlement sets to control access. +entitlement sets to control access. ### Tutorials and Examples @@ -582,41 +582,41 @@ access(all) resource Vault: Provider, Receiver, Balance { Note how the primary difference here is that `withdraw` now requires a `Withdraw` entitlement. -Then, someone with a `&{Balance}` reference would be able to cast this to a `&{Receiver}` and call `deposit` on it. +Then, someone with a `&{Balance}` reference would be able to cast this to a `&{Receiver}` and call `deposit` on it. They would also be able to cast this to a `&Vault` reference, but because this reference is not entitled to `Withdraw`, -they would be unable to call the `withdraw` function. However, if a user possessed a `auth(Withdraw) &{Balance}` reference, +they would be unable to call the `withdraw` function. However, if a user possessed a `auth(Withdraw) &{Balance}` reference, they would be able to cast this to `auth(Withdraw) &Vault` and call `withdraw`. ### Compatibility -This would not be backwards compatible with existing code, and thus would need to be part of the Stable Cadence release. +This would not be backwards compatible with existing code, and thus would need to be part of the Stable Cadence release. Most contracts would need to be audited and rewritten to use the new access modifiers, as they would immediately become -vulnerable to having `pub` fields accessed from now-downcastable references. +vulnerable to having `pub` fields accessed from now-downcastable references. ### User Impact There is a huge user impact to rolling out this change; every single contract would become invalid, and would need to be manually audited by the authors in order to be used. This is because all code previously written using the old model of access control (wherein giving someone -a `&{Balance}` would prevent them from calling `pub` functions on `Provider` like `withdraw`), would become invalidated, allowing everyone -to call `pub` members like `withdraw` unless those methods were updated to be `access(Withdraw)`. +a `&{Balance}` would prevent them from calling `pub` functions on `Provider` like `withdraw`), would become invalidated, allowing everyone +to call `pub` members like `withdraw` unless those methods were updated to be `access(Withdraw)`. ### Rollout -There are two cases that need handling to migrate to this new paradigm: contracts and data. +There are two cases that need handling to migrate to this new paradigm: contracts and data. -Existing references in storage (i.e. `Capability` values) would need to be migrated, as they would no longer be semantically valid under the new system. +Existing references in storage (i.e. `Capability` values) would need to be migrated, as they would no longer be semantically valid under the new system. The simplest way to do this would be to ensure existing capabilities stay usable by converting existing capabilities and links' reference types to `auth` references, along with creating -entitlements that map 1:1 with existing interfaces, e.g. `Capability<&Vault{Withdraw}>` -> `Capability`. Specifically, all existing -references would become `auth` with regard to their entire borrow type, as this does not add any additional power to these `Capability` values that did not previously exist. -For example, `&Vault{Provider}` previously had the ability to call `withdraw`, which was `pub` on `Provider`. After this change, it will still have the ability to call `withdraw`, +entitlements that map 1:1 with existing interfaces, e.g. `Capability<&Vault{Withdraw}>` -> `Capability`. Specifically, all existing +references would become `auth` with regard to their entire borrow type, as this does not add any additional power to these `Capability` values that did not previously exist. +For example, `&Vault{Provider}` previously had the ability to call `withdraw`, which was `pub` on `Provider`. After this change, it will still have the ability to call `withdraw`, as it is now `access(Withdraw)` on `Provider`, but the reference now has `auth(Withdraw)`access to that type. However, this does not handle the previously mentioned problem wherein existing contracts become vulnerable to exploitation, as all their `pub` functions would become -accessible to anybody with any kind of reference to a contract or resource. +accessible to anybody with any kind of reference to a contract or resource. To handle this case we woukld "freeze" all existing contracts, preventing calling any code defined in them or interacting with their data until they are updated at least once after the release of this feature (it's also possible that given the large number of breaking changes being released with Cadence 1.0, this restriction would happen -automatically and would not need special handling). Developers would be encouraged to give their contracts and resources the proper access modifiers. +automatically and would not need special handling). Developers would be encouraged to give their contracts and resources the proper access modifiers. ## Alternatives Considered @@ -636,21 +636,21 @@ pub resource R: auth A, B { } ``` -Then, given a reference of type `&R`, only the functions and fields defined on `B` would be accessible, since the reference is non-`auth`. In -order to access the fields and functions on `A`, one would need an `auth` reference to `R`, since `A` was declared as `auth` in `R`'s conformances. +Then, given a reference of type `&R`, only the functions and fields defined on `B` would be accessible, since the reference is non-`auth`. In +order to access the fields and functions on `A`, one would need an `auth` reference to `R`, since `A` was declared as `auth` in `R`'s conformances. The upside of this proposal was that there was a single decision point, in that the implementor of the concrete type needed to decide which interfaces -would be `auth` and which would be not, and the creators of the interfaces and the users of the concrete types would have no decisions to make other than +would be `auth` and which would be not, and the creators of the interfaces and the users of the concrete types would have no decisions to make other than whether or not the reference they are creating should be `auth` or not. -The drawback of this compared to the proposal in this FLIP is that it lacks granularity; an entire interface must be made `auth` or not, whereas in the +The drawback of this compared to the proposal in this FLIP is that it lacks granularity; an entire interface must be made `auth` or not, whereas in the FLIP's proposal individual functions can be declared with `auth` access or `pub` access. This allows the creator of the interface (and then later, the creator of the reference type) to exert more fine-grained control over what is accessible. By contrast, the implementor of the concrete type has little -to no say in the access-control on their value beyond selecting which interfaces they wish to conform to. +to no say in the access-control on their value beyond selecting which interfaces they wish to conform to. ## Prior Art -`entitlement`s function similarly to facets in the Object Capabilities model. +`entitlement`s function similarly to facets in the Object Capabilities model. ## Questions and Discussion Topics @@ -662,4 +662,4 @@ for `auth`-references, which would prevent accidentally allowing anybody to get some entitlement `A` and `B`, it would be useful to be able to declare `C` as the intersection of `A` and `B` or the union. Additionally it would be valuable to be able to declare `C` as a subset of `A` or `B`'s functions to reduce code repetition. However, this is not a necessary part of the initial implementation of this FLIP, as it can be added later in a non-breaking way. As such this feature is -out of scope for this FLIP. +out of scope for this FLIP. diff --git a/cadence/20230417-events-emitted-from-interfaces.md b/cadence/20230417-events-emitted-from-interfaces.md index 4057a035c..bfb568f4c 100644 --- a/cadence/20230417-events-emitted-from-interfaces.md +++ b/cadence/20230417-events-emitted-from-interfaces.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released 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) @@ -41,18 +41,18 @@ Suppose the `FungibleToken` is a contract, and has a `TokenWithdrawal` event dec With function pre/post conditions being able to emit events, the `withdraw` function would look like below. -```cadence +```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 { + + 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) - } - } + emit TokenWithdrawal(type:type, amount:amount, from:from) + } + } } } ``` diff --git a/cadence/20230503-improve-conformance.md b/cadence/20230503-improve-conformance.md index 28cc00409..7b5892671 100644 --- a/cadence/20230503-improve-conformance.md +++ b/cadence/20230503-improve-conformance.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 83 authors: Supun Setunga (supun.setunga@dapperlabs.com) sponsor: Supun Setunga (supun.setunga@dapperlabs.com) @@ -11,7 +11,7 @@ updated: 2023-06-19 ## 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 +by allowing conditions defined in other interfaces to coexist with a default function implementation coming from a different interface. ## Motivation diff --git a/cadence/20230505-remove-priv-and-pub.md b/cadence/20230505-remove-priv-and-pub.md index 323b627eb..b1e9119cf 100644 --- a/cadence/20230505-remove-priv-and-pub.md +++ b/cadence/20230505-remove-priv-and-pub.md @@ -1,9 +1,9 @@ --- -status: implemented +status: released flip: 84 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) -updated: 2023-05-05 +updated: 2023-05-05 --- # FLIP 84: Remove `pub` and `priv` aliases for access modifiers @@ -12,53 +12,53 @@ updated: 2023-05-05 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. +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, +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. +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 +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. +and `priv` to be `access(all)` and `access(self)` respectively. ## User Benefit -This will increase the readability and consistency of user code. +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. +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 +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. +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, +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. +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 +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. +truly `access(all)` and which should be rewritten to use entitlements. ## Questions and Discussion Topics diff --git a/cadence/20230505-remove-restricted-types.md b/cadence/20230505-remove-restricted-types.md index bf23461f7..344f38711 100644 --- a/cadence/20230505-remove-restricted-types.md +++ b/cadence/20230505-remove-restricted-types.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 85 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) @@ -14,49 +14,49 @@ Currently in Cadence, a restricted type consists of a type (often confusingly al 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. +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, +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, +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. +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. +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. +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. +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. +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`. +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. +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. +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. +as a vestigial feature without much of a use case. ### Compatibility diff --git a/cadence/20230517-member-access-semnatics.md b/cadence/20230517-member-access-semnatics.md index 44056f468..43961b931 100644 --- a/cadence/20230517-member-access-semnatics.md +++ b/cadence/20230517-member-access-semnatics.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 89 authors: Supun Setunga (supun.setunga@dapperlabs.com) sponsor: Supun Setunga (supun.setunga@dapperlabs.com) @@ -13,7 +13,7 @@ updated: 2023-07-05 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 +## Motivation A previous version of Cadence ("Secure Cadence") restricted the potential foot-gun of mutating container-typed `let` fields/variables via the @@ -88,7 +88,7 @@ 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`. +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 @@ -118,7 +118,7 @@ pub resource MasterCollection { 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) @@ -140,8 +140,8 @@ Previously, it was possible to withdraw from the inner collection, despite the ` 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. +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 diff --git a/cadence/20230519-built-in-mutability-entitlements.md b/cadence/20230519-built-in-mutability-entitlements.md index 23e85973c..755debf6e 100644 --- a/cadence/20230519-built-in-mutability-entitlements.md +++ b/cadence/20230519-built-in-mutability-entitlements.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 86 authors: Supun Setunga (supun.setunga@dapperlabs.com) sponsor: Supun Setunga (supun.setunga@dapperlabs.com) @@ -133,7 +133,7 @@ mutableDictionaryRef.remove("John") // OK Similar to functions, the assignment operator for arrays/dictionaries would also have the `Mutate` and `Insert` entitlements. -Think of assignment as a built-in function with `Mutate` and `Insert` entitlements. +Think of assignment as a built-in function with `Mutate` and `Insert` entitlements. e.g: ```cadence access(Mutate | Insert) set(keyOrIndex, value) { ... } @@ -192,7 +192,7 @@ those changes, and leaning towards an entitlement-based solution. ### Putting It All Together -Now let's see how this solves the mutability foot-gun. +Now let's see how this solves the mutability foot-gun. Let's consider the `NonFungibleToken.Collection` example: ```cadence @@ -208,7 +208,7 @@ pub resource Collection: NonFungibleToken.Collection { The original intention of the `Collection` resource is to make `ownedNFTs` readable to outsiders, but must not be mutable. -```cadence +```cadence // `collection.ownedNFTs` result in a `&{UInt64: NonFungibleToken.NFT}` var ownedNFTsRef: &{UInt64: NonFungibleToken.NFT} = collection.ownedNFTs ``` @@ -216,7 +216,7 @@ var ownedNFTsRef: &{UInt64: NonFungibleToken.NFT} = collection.ownedNFTs The field `collection.ownedNFTs` is readable since it is `pub` access modifier. It is not mutable since it has no entitlements. -```cadence +```cadence var len = ownedNFTsRef.length // OK: read only operation ownedNFTsRef["someNFT"] <- someNft // Static Error: `append` needs `Mutate` entitlement @@ -272,9 +272,9 @@ pub resource Collection: NonFungibleToken.Collection { Assume the author set the access modifier of the `delete` method to be `pub` instead of `access(Mutate)`. Now anyone with an un-entitled reference to `Collection` can modify `ownedNFTs`. -However, this is in a way a good thing to have, and eliminates the problem of the previous -[FLIP proposed to eliminate the mutability foot-gun](https://github.com/onflow/flips/pull/58), -where having to annotate each and every mutating function could quickly become an overkill. +However, this is in a way a good thing to have, and eliminates the problem of the previous +[FLIP proposed to eliminate the mutability foot-gun](https://github.com/onflow/flips/pull/58), +where having to annotate each and every mutating function could quickly become an overkill. Also, certain mutating operations are in-fact safe. For example: `deposit()` function of `Collection` does mutate the object, however, it is of no harm of anyone calling the `deposit()` function. diff --git a/cadence/20230525-account-type.md b/cadence/20230525-account-type.md index f7836ac57..6124aacf1 100644 --- a/cadence/20230525-account-type.md +++ b/cadence/20230525-account-type.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 92 authors: Bastian Müller (bastian@dapperlabs.com) sponsor: Bastian Müller (bastian@dapperlabs.com) diff --git a/cadence/20230602-cadence-range.md b/cadence/20230602-cadence-range.md index 1b0af7c20..c48950cee 100644 --- a/cadence/20230602-cadence-range.md +++ b/cadence/20230602-cadence-range.md @@ -1,5 +1,5 @@ --- -status: accepted +status: released flip: 96 authors: darkdrag00n (darkdrag00n@proton.me) sponsor: Bastian Müller (bastian@dapperlabs.com) @@ -143,7 +143,7 @@ let invalidDirection = ExclusiveRange(132, 33, step: 3) // Runtime Error 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`. +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. diff --git a/cadence/20230623-entitlement-improvements.md b/cadence/20230623-entitlement-improvements.md index 175fa5b03..bf466cf05 100644 --- a/cadence/20230623-entitlement-improvements.md +++ b/cadence/20230623-entitlement-improvements.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 94 authors: Supun Setunga (supun.setunga@dapperlabs.com) sponsor: Supun Setunga (supun.setunga@dapperlabs.com) @@ -117,7 +117,7 @@ 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 +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. diff --git a/cadence/20230711-remove-type-requirements.md b/cadence/20230711-remove-type-requirements.md index 461355ede..9cbcb4147 100644 --- a/cadence/20230711-remove-type-requirements.md +++ b/cadence/20230711-remove-type-requirements.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 118 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) @@ -10,8 +10,8 @@ updated: 2023-07-24 ## 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 +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 @@ -31,27 +31,27 @@ access(all) contract ExampleOuter: Outer { } ``` -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. +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. +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. +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. +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. +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. +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. +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 @@ -66,7 +66,7 @@ contract interface Interface { } ``` -would instead be written as +would instead be written as ``` contract interface Interface { @@ -83,10 +83,10 @@ 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 +First, the semantics of declaring an event in an interface will need to be changed. +Currently, a definition such as -```cadence +```cadence access(all) contract interface Interface { access(all) event Foo() } @@ -96,51 +96,51 @@ does not declare a concrete event type `Foo`, but rather specifies a type requir 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. +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). Note that -the semantics of `emit` require that the emitted event is defined in the same scope as the `emit` statement, +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). Note that +the semantics of `emit` require that the emitted event is defined in the same scope as the `emit` statement, so `Foo` would not be emittable outside of `Interface`. This is in order to ensure that the author -of `Interface` and `Foo` can be certain that all emitted `Foo` events originate from `Interface` code, and -cannot originate from elsewhere. +of `Interface` and `Foo` can be certain that all emitted `Foo` events originate from `Interface` code, and +cannot originate from 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. +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. +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. +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 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. +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. +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. +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. +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 diff --git a/cadence/20230713-random-function.md b/cadence/20230713-random-function.md index d361cea6c..aaf816119 100644 --- a/cadence/20230713-random-function.md +++ b/cadence/20230713-random-function.md @@ -1,8 +1,8 @@ --- -status: Released +status: released flip: 120 authors: Tarak Ben Youssef (tarak.benyoussef@dapperlabs.com) -sponsor: +sponsor: updated: 2023-08-22 --- @@ -24,17 +24,17 @@ where `UnsignedInteger` covers all Cadence's fixed-size unsigned integer types, #### Safe randomness -The Flow Virtual Machine (FVM) provides the implementation of `unsafeRandom` as part of the Flow protocol. -The FVM implementation has been using the block hash as a source of entropy. +The Flow Virtual Machine (FVM) provides the implementation of `unsafeRandom` as part of the Flow protocol. +The FVM implementation has been using the block hash as a source of entropy. This source can be manipulated by miners (i.e consensus nodes) -and should not be relied on to derive secure randomness, +and should not be relied on to derive secure randomness, hence the `unsafe` suffix in the function name. FVM [underwent changes](https://github.com/onflow/flow-go/pull/4498) that update the source of entropy to rely on the secure distributed randomness generated within the Flow -protocol by [the random beacon](https://arxiv.org/pdf/2002.07403.pdf) component. +protocol by [the random beacon](https://arxiv.org/pdf/2002.07403.pdf) component. The Flow beacon is designed to generate decentralized, unbiased, unpredictable and verifiable -randomness. +randomness. Miners have negligible control to bias or predict the beacon output. @@ -66,52 +66,52 @@ that calls an on-chain casino contract, that rolls a dice to find out if the transaction sender wins. The transaction can be written so that it triggers an error if the game outcome is a loss. Developers writing a similar casino contract should be aware of the transaction -abortion scenario by non-trusted users. This limitation is inherent to any smart contract platform that allows transactions to roll back atomically and cannot be solved through safe randomness alone. +abortion scenario by non-trusted users. This limitation is inherent to any smart contract platform that allows transactions to roll back atomically and cannot be solved through safe randomness alone. Note that post-selection is not an issue when the transaction sender is trusted. -Removing the `unsafe` prefix completely would suggest to developers that the function is immune to all exploits. -Users may not realize that post-selection needs to be addressed using other patterns or techniques without an explicit warning. -The FLIP suggests to replace the `unsafe` prefix by the `revertible` prefix. -`revertible` is descriptive of the remaining issue of the function, +Removing the `unsafe` prefix completely would suggest to developers that the function is immune to all exploits. +Users may not realize that post-selection needs to be addressed using other patterns or techniques without an explicit warning. +The FLIP suggests to replace the `unsafe` prefix by the `revertible` prefix. +`revertible` is descriptive of the remaining issue of the function, and serves as a reminder to developers to read more about the function documentation and be aware of the post-selection issue. ### function generalized header -Many applications require a random number less than an upper-bound `N` rather than a random number without constraints. For example, sampling a random element from an array requires picking a random index less than the array size. -`N` is commonly called the modulo. In security-sensitive applications, it is important to maintain a uniform distribution of the random output. -Returning the remainder of the division of a 64-bits number by `N` (using the modulo operation `%`) is known to result in a biased distribution where smaller outputs are more likely to be sampled than larger ones. -This is known as the "modulo bias". -There are safe solutions to avoid the modulo bias such as rejection sampling and large modulo reduction. Although these solutions can be implemented purely in Cadence, it is safer to provide the secure functions and abstract the complexity away from developers. -This also avoids using unsafe methods. The FLIP suggests to add an optional unsigned-integer argument `N` to the `revertibleRandom` function. -If `N` is provided, the returned random is uniformly sampled strictly less than `N`. The function errors if `N` is equal to `0`. +Many applications require a random number less than an upper-bound `N` rather than a random number without constraints. For example, sampling a random element from an array requires picking a random index less than the array size. +`N` is commonly called the modulo. In security-sensitive applications, it is important to maintain a uniform distribution of the random output. +Returning the remainder of the division of a 64-bits number by `N` (using the modulo operation `%`) is known to result in a biased distribution where smaller outputs are more likely to be sampled than larger ones. +This is known as the "modulo bias". +There are safe solutions to avoid the modulo bias such as rejection sampling and large modulo reduction. Although these solutions can be implemented purely in Cadence, it is safer to provide the secure functions and abstract the complexity away from developers. +This also avoids using unsafe methods. The FLIP suggests to add an optional unsigned-integer argument `N` to the `revertibleRandom` function. +If `N` is provided, the returned random is uniformly sampled strictly less than `N`. The function errors if `N` is equal to `0`. If `N` is not provided, the returned output has no constraints. A more convenient way of using `random` is to cover all fixed-size unsigned integer types (`UInt8`, `UInt16`, `UInt32`, `UInt64`, `UInt128`, `UInt256`, `Word8`, `Word16`, `Word32`, `Word64`). -The type applies to the optional argument `modulo` as well as the returned value. -This would abstract the complexity of generating randoms of different types using 64-bits values as a building block. -The new suggested function signature is therefore `fun revertibleRandom([modulo: T]): T`, +The type applies to the optional argument `modulo` as well as the returned value. +This would abstract the complexity of generating randoms of different types using 64-bits values as a building block. +The new suggested function signature is therefore `fun revertibleRandom([modulo: T]): T`, where `T` can be any type from the above list. Note that `UInt` is a variable-size type and is not supported by the function. ## User Benefit Cadence uses the prefix `unsafe` to warn developers of the risks of using -the random function. +the random function. Risks related to the safety of the random source are addressed by the FVM recent updates. However, post-selecting randoms after they are revealed is not addressed by the function and developers should be reminded of the remaining risk. -Replacing `unsafe` by `revertible` clarifies the assumption about the random source safety while being descriptive of the possible issue. +Replacing `unsafe` by `revertible` clarifies the assumption about the random source safety while being descriptive of the possible issue. If developers are not familiar with using randomness, the prefix serves as an invitation to look at the documentation and learn about the function risks. -The generalized function signature offers safe and more flexible ways to use randomness. +The generalized function signature offers safe and more flexible ways to use randomness. Without such change, developers are required to implement extra logic and take the risk of making mistakes. ## Design Proposal 1. As a first step: - Update Cadence's [runtime interface](https://github.com/onflow/cadence/blob/8a128022e0a5171f4c3a173911944a2f43548b98/runtime/interface.go#L107) `UnsafeRandom() (uint64, error)` to `ReadRandom(byte[]) error`. - - Add a new Cadence function `fun revertibleRandom([modulo: T]): T`, backed by a safe FVM implementation. - `fun unsafeRandom(): UInt64` remains available to avoid immediate breaking changes. + - Add a new Cadence function `fun revertibleRandom([modulo: T]): T`, backed by a safe FVM implementation. + `fun unsafeRandom(): UInt64` remains available to avoid immediate breaking changes. Note that both functions will be backed by the same safe FVM implementation. 2. As a second step, deprecate `fun unsafeRandom(): UInt64` as part of the Stable Cadence release (aka Cadence v1.0). @@ -128,8 +128,8 @@ Renaming the random function to simply `random` has been considered. Below are s - A language should try to provide as-safe-as-possible tools, but it can't guarantee that any program written in that language is totally safe. There is always some responsibility that falls on the language developer. It is possible to write very unsafe contracts and Cadence can't prevent it (using the cryptography functions as an example). -The generalized function signature could be omitted from the proposal because it is possible to implement `fun revertibleRandom([modulus; T]): T` purely on Cadence using `fun revertibleRandom(): UInt64`. -However, this requires developers to be familiar with safe low-level implementations and it may result in bugs and vulnerabilities. +The generalized function signature could be omitted from the proposal because it is possible to implement `fun revertibleRandom([modulus; T]): T` purely on Cadence using `fun revertibleRandom(): UInt64`. +However, this requires developers to be familiar with safe low-level implementations and it may result in bugs and vulnerabilities. It is safer to have these tools provided natively by Cadence. ### Performance Implications @@ -146,7 +146,7 @@ The Cadence repository needs to implement the generalized function signature (op ### Best Practices The current proposal and the new FVM implementation -do not propose solutions for the transaction abortion issue. +do not propose solutions for the transaction abortion issue. Solutions to abortion such as safe design patterns and commit-reveal schemes can be discussed outside this FLIP (for instance this [separate FLIP](https://github.com/onflow/flips/pull/123) suggests a safe pattern to use randomness). @@ -177,7 +177,7 @@ Please refer to [Best Practices](#best-practices) section. ### Randomness in script execution -`executeScriptAtBlock` and `ExecuteScriptAtLatestBlock` are used to execute Cadence read-only code against the execution state at a past sealed block or the latest sealed blocked, respectively. +`executeScriptAtBlock` and `ExecuteScriptAtLatestBlock` are used to execute Cadence read-only code against the execution state at a past sealed block or the latest sealed blocked, respectively. The FVM implementation of `revertibleRandom` uses the transaction hash to diversify the random sequence per transaction. This does not add new entropy but prevents generating the same randoms for different transactions. For this reason, it is not possible to replicate Cadence's `revertibleRandom` behavior in scripts. The FLIP suggests to use the same source of randomness for scripts as for transactions, and to diversify the random sequence per script using the hash of the script code. diff --git a/cadence/20230811-destructor-removal.md b/cadence/20230811-destructor-removal.md index 522f3e7df..888dfce37 100644 --- a/cadence/20230811-destructor-removal.md +++ b/cadence/20230811-destructor-removal.md @@ -1,26 +1,26 @@ --- -status: implemented +status: released flip: 131 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) -updated: 2023-08-30 +updated: 2023-08-30 --- # FLIP 131: Removal of Custom Destructors ## Objective -This FLIP proposes to remove support for destructors from Cadence. -In particular, resources will neither be required nor able to declare a special `destroy` method. -Instead, any nested resources will automatically be destroyed when the resource is destroyed. +This FLIP proposes to remove support for destructors from Cadence. +In particular, resources will neither be required nor able to declare a special `destroy` method. +Instead, any nested resources will automatically be destroyed when the resource is destroyed. ## Motivation -The primary motivation for this is to resolve the "trolling attack" that can be used to +The primary motivation for this is to resolve the "trolling attack" that can be used to exploit resources and attachments, whereby a `panic`ing destructor is added to a resource or attachment without the owner's knowledge, and thus unremovably takes up space in an account. By removing the ability -to declare custom destructors, malicious actors would not be able to prevent the destruction or removal -of a resource or attachment. +to declare custom destructors, malicious actors would not be able to prevent the destruction or removal +of a resource or attachment. In addition to trolling, the existence of customizeable destructors also requires developers to be extremely careful when writing contracts because they can have arbitrary side effects. Developers could, for example, write a destructor for a @@ -40,38 +40,38 @@ Previous discussions around the attachments/deletion trolling attack have alread As such, solution proposals that either only address the storage cost aspect of the problem, only address the attachments-specific portion of the problem, -or otherwise do not ensure that a user is always able to delete any resource they own, are not sufficient for addressing this issue. +or otherwise do not ensure that a user is always able to delete any resource they own, are not sufficient for addressing this issue. We have proposed other solutions to this in the past, including: -* Try-Catch, where a destructor would be required to catch any potential panics and handle them in a way that guarantees successful deletion +* Try-Catch, where a destructor would be required to catch any potential panics and handle them in a way that guarantees successful deletion of the resource. * Banning panicking operations in a destructor entirely * Successfully cleaning up a resource when its destructor panics before aborting execution * Separating destruction into a two-phase process that separates clean-up from actually deleting the resource -The issue with all of these is either that they significantly complicate the language, are technically very challenging to implement, or both. +The issue with all of these is either that they significantly complicate the language, are technically very challenging to implement, or both. ## User Benefit The primary benefit of this change would be the ability to enable the attachments feature without any -security concerns. +security concerns. -However, a secondary benefit is that the language would change to reflect the practical realities of Cadence on-chain more closely. +However, a secondary benefit is that the language would change to reflect the practical realities of Cadence on-chain more closely. Although the language guarantees that the `destroy` method of a resource is invoked whenever that resource is destroyed with the `destroy` statement, the reality is more complicated. There are ways to take a resource (e.g. an NFT or a token) "out of circulation" without actually destroying it; an easy example would be sending that resource to a locked account where it is irretrievable. Such resources are destroyed in -the sense that they cannot be interacted with further, and as such any logic that relies on destructors to guarantee an accurate count of how many -of a resource exist (e.g. `totalSupply` in the Fungible Token contract), to prevent the destruction of resources that do not satisfy certain conditions, -or to emit an event when a resource is destroyed, is in practice impossible. -As such, removing support for custom destructors would prevent developers being mislead about the possible guarantees that can be made about their resources. +the sense that they cannot be interacted with further, and as such any logic that relies on destructors to guarantee an accurate count of how many +of a resource exist (e.g. `totalSupply` in the Fungible Token contract), to prevent the destruction of resources that do not satisfy certain conditions, +or to emit an event when a resource is destroyed, is in practice impossible. +As such, removing support for custom destructors would prevent developers being mislead about the possible guarantees that can be made about their resources. ## Design Proposal -The design is simple; `destroy` will no longer be a declarable special function. Instead, +The design is simple; `destroy` will no longer be a declarable special function. Instead, when a resource is destroyed, any nested resources in that resource will be recursively destroyed as well. Effectively, -the behavior will be the same as if the author of the `destroy` method had simply done the minimal implementation of that method, -destroying sub-resources and nothing else. +the behavior will be the same as if the author of the `destroy` method had simply done the minimal implementation of that method, +destroying sub-resources and nothing else. So, e.g. a resource `R` defined like this: @@ -89,18 +89,18 @@ resource R { } ``` -would automatically destroy the `subResource` and `subArray` fields when it itself is destroyed. Users would not be able to -rely on any specific order for the execution of these destructors, but because nothing can happen in destructors except for destruction -of sub-resource, it would not be possible for the order to matter. The order is deterministic (in the way that iterating over an atree dictionary +would automatically destroy the `subResource` and `subArray` fields when it itself is destroyed. Users would not be able to +rely on any specific order for the execution of these destructors, but because nothing can happen in destructors except for destruction +of sub-resource, it would not be possible for the order to matter. The order is deterministic (in the way that iterating over an atree dictionary is deterministic), but will not be specified by the language. ### Destruction Events -In order to continue to support the critical use case of off-chain tracking of destroyed resources, +In order to continue to support the critical use case of off-chain tracking of destroyed resources, support will be added for defining a default event to be automatically emitted whenever a resource is destroyed. -Resource (and resource interface) types will support the definition of a `ResourceDestroyed` event in the body of the resource definition, -to be automatically emitted whenever that resource is `destroy`ed. In the case of a resource interface, the `ResourceDestroyed` event +Resource (and resource interface) types will support the definition of a `ResourceDestroyed` event in the body of the resource definition, +to be automatically emitted whenever that resource is `destroy`ed. In the case of a resource interface, the `ResourceDestroyed` event would be emitted whenever any resources conforming to that interface are destroyed; this behavior is equivalent to how a `destroy` defined in an interface would work today, if an event were emitted in its pre or post conditions. So, for example: @@ -118,12 +118,12 @@ resource R: I, J { } ``` -if a value of type `@R` is destroyed, three events would be emitted: `I.ResourceDestroyed`, `J.ResourceDestroyed` and `R.ResourceDestroyed`. +if a value of type `@R` is destroyed, three events would be emitted: `I.ResourceDestroyed`, `J.ResourceDestroyed` and `R.ResourceDestroyed`. -`ResourceDestroyed` events will not be `emit`able normally; any `emit` statement attempting to `emit` one will fail statically. -This is to ensure that these events are only emitted on resource destruction. +`ResourceDestroyed` events will not be `emit`able normally; any `emit` statement attempting to `emit` one will fail statically. +This is to ensure that these events are only emitted on resource destruction. -Like other events, `ResourceDestroyed` can have fields. +Like other events, `ResourceDestroyed` can have fields. However, as this event is emitted automatically rather than manually, the syntax for declaring specifying the values associated with these fields is different. A `ResourceDestroyed` event declaration has support for default arguments provided to its parameters, like so: @@ -137,11 +137,11 @@ resource R { } ``` -In this example, the `R.ResourceDestroyed` event has two fields, `x` and `y`, whose values are specified by the given arguments. -In this case `x`'s value is `3`, while `y`'s value is whatever `self.foo` contains at the time that `R` is destroyed. +In this example, the `R.ResourceDestroyed` event has two fields, `x` and `y`, whose values are specified by the given arguments. +In this case `x`'s value is `3`, while `y`'s value is whatever `self.foo` contains at the time that `R` is destroyed. The possible arguments are restricted to expressions that cannot possibly abort during evaluation. The following expression are allowed: -* Constant expressions whose type is numerical (e.g. `Int`, `UFix64` or `Word16`), `String`, `Bool`, `Address`, or `nil` +* Constant expressions whose type is numerical (e.g. `Int`, `UFix64` or `Word16`), `String`, `Bool`, `Address`, or `nil` * field accesses (e.g. `self.foo`, `base.nestedResource.bar`, or `foo?.field`) whose type is one of the aforementioned permitted types * the accessed expression must also necessarily obey these restrictions * indexed access expressions on dictionaries (e.g. `dict[0]`) whose type is one of the aforementioned permitted types @@ -158,24 +158,24 @@ In particular, some expressions that are not allowed because they may abort are: * Dereference or force expressions, which may fail if the reference or optional is `nil` These arguments are also evaluated lazily when the resource is destroyed; i.e. any field accesses will use the values -in those fields at time of resource destruction, rather than resource creation. +in those fields at time of resource destruction, rather than resource creation. ### Drawbacks -This will break a large amount of existing code, and further increase the Stable Cadence migration burden. +This will break a large amount of existing code, and further increase the Stable Cadence migration burden. ### Compatibility -This will not be backwards compatible. Developers will need to restructure their contracts accordingly. -Destructors that were previously used to guarantee event emission can be rewritten with default events, but -cases that actually used `panic` or performed state tracking in destructors will need to be restructured. +This will not be backwards compatible. Developers will need to restructure their contracts accordingly. +Destructors that were previously used to guarantee event emission can be rewritten with default events, but +cases that actually used `panic` or performed state tracking in destructors will need to be restructured. ### Alternatives Considered -There has been some other discussion of potential alternatives to this in the past for solving the "trolling attack". +There has been some other discussion of potential alternatives to this in the past for solving the "trolling attack". The attack relies on a user defining an aborting destructor to make it impossible to destroy an attachment, and as such potential solutions have been proposed to specifically ban panicking or aborting operations in destructors, or to have some kind of try-catch mechanism to continue -destruction after an abort. +destruction after an abort. The issue with both of these solutions is their technical complexity; we estimate that either would take between 6 months to a year to design and implement, and as they are both breaking changes, we would need to delay the release of Stable Cadence until the feature was complete. The hope @@ -183,7 +183,7 @@ with this proposal is that the simpler change would both solve the problem and a ### User Impact -To evaluate the impact of this change, existing contracts on Mainnet were surveyed. +To evaluate the impact of this change, existing contracts on Mainnet were surveyed. A [custom linter](https://github.com/onflow/cadence-tools/pull/194) was defined to identify contracts containing complex destructors, where a complex destructor is defined as one that performs and logic beyond recursively destroying sub-resources. @@ -196,19 +196,19 @@ Of these, 6 distinct categories of operations were identified (note that some de * Conditions/Assertions: this destructor asserts a condition, either with a pre/post condition or an assert statement. 29 of the complex destructors are of this kind * Logging: this destructor logs some data. 17 of the complex destructors are of this kind * Panic: this destructor panics under some circumstances. 10 of the complex destructors are of this kind -* Other complex operations: this destructor performs some logic that is not included in these categories (e.g. function call, resource movement). 211 of the complex destructors are of this kind. +* Other complex operations: this destructor performs some logic that is not included in these categories (e.g. function call, resource movement). 211 of the complex destructors are of this kind. -Based on this data, we can see that the two largest use cases for complex destructors currently is emitting an event signalling destruction, and decrementing the total supply for a token of some kind. +Based on this data, we can see that the two largest use cases for complex destructors currently is emitting an event signalling destruction, and decrementing the total supply for a token of some kind. While developers cannot actually rely on this logic to actually execute (events will not be emitted nor supply decremented when a resource is sent to a burner account), these use cases would be most -negatively impacted by this change. +negatively impacted by this change. -The Condition/Assertion and Panic categories are uncommon, and also anti-patterns. -Destructors being able to abort execution is the source of the attachments-related "trolling" attack in the first place, +The Condition/Assertion and Panic categories are uncommon, and also anti-patterns. +Destructors being able to abort execution is the source of the attachments-related "trolling" attack in the first place, and any solution we come up with for this would necessarily involve circumventing these operations. ## Prior Art -Move is an example of a resource-based smart contract language that does not allow the definition of custom destructors. +Move is an example of a resource-based smart contract language that does not allow the definition of custom destructors. ## Questions and Discussion Topics diff --git a/cadence/20230816-relax-interface-conformance.md b/cadence/20230816-relax-interface-conformance.md index f433417bf..2d97f66ac 100644 --- a/cadence/20230816-relax-interface-conformance.md +++ b/cadence/20230816-relax-interface-conformance.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 134 authors: Supun Setunga (supun.setunga@dapperlabs.com) sponsor: Supun Setunga (supun.setunga@dapperlabs.com) diff --git a/cadence/20230913-restrict-capabilities-publish.md b/cadence/20230913-restrict-capabilities-publish.md index c39d6856e..980e98489 100644 --- a/cadence/20230913-restrict-capabilities-publish.md +++ b/cadence/20230913-restrict-capabilities-publish.md @@ -1,6 +1,6 @@ --- -status: imlemented -flip: 196 +status: released +flip: 196 authors: Deniz Mert Edincik (deniz@edincik.com) sponsors: Bastian Mueller (bastian@dapperlabs.com) updated: 2023-10-24 @@ -18,18 +18,18 @@ As this shift in behavior can cause problems, this FLIP strives to address this ## Motivation -Before the introduction of the new controller-based capabilities API, public capabilities were guaranteed to point to storage at the same address. However, with the introduction of the API, it is now possible to obtain another account's public capability and republish it as one's own, while still maintaining the link to the other account's storage. +Before the introduction of the new controller-based capabilities API, public capabilities were guaranteed to point to storage at the same address. However, with the introduction of the API, it is now possible to obtain another account's public capability and republish it as one's own, while still maintaining the link to the other account's storage. A lot of scenarios, such as voting and gating using the proof of Non-Fungible Token (NFT) ownership, usually involve checking if an account owns a certain balance or resource by verifying the public path capability. Now, the responsibility of protection falls on the developers, which is an extra burden and holds the potential of introducing bugs and security issues. -The current suggested method of defence against this issue is always checking for the `address` of the capability or the `owner` of the resource after borrowing. +The current suggested method of defence against this issue is always checking for the `address` of the capability or the `owner` of the resource after borrowing. Unfortunately, this is an error-prone approach that developers can easily forget. In addition, the new `capabilities.borrow` convenience function gets the capability and borrows it in one call. -Developers will likely forget to still `get` and check the address of the capability, when needed. +Developers will likely forget to still `get` and check the address of the capability, when needed. ## User Benefit -This proposal aims to add a restriction, in order to decrease developer burden and decrease the risk of bugs and security issues. +This proposal aims to add a restriction, in order to decrease developer burden and decrease the risk of bugs and security issues. The restriction already exists in the currently available linking-based capability API, so this proposal simply proposes to keep the existing restriction, and prevent a regression in the API in terms of safety and usability. ## Design Proposal @@ -46,10 +46,10 @@ I don't think there will be any performance implications. ### Engineering Impact -There is already a Draft PR implementation by Bastian (https://github.com/onflow/cadence/pull/2782) +There is already a Draft PR implementation by Bastian (https://github.com/onflow/cadence/pull/2782) ### Compatibility -As this is an additional restriction, it is backwards compatible with the API. +As this is an additional restriction, it is backwards compatible with the API. diff --git a/cadence/20231016-entitlement-mapping-syntax.md b/cadence/20231016-entitlement-mapping-syntax.md index 757faa974..eadd4d6e5 100644 --- a/cadence/20231016-entitlement-mapping-syntax.md +++ b/cadence/20231016-entitlement-mapping-syntax.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 210 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) @@ -14,8 +14,8 @@ This proposes a syntax change to make entitlement-mapped fields more visually di ## Motivation -User feedback has indicated that entitlement mappings are too easy to confuse with entitlements, -and since one of them has default behavior for public access and the other prevents it, +User feedback has indicated that entitlement mappings are too easy to confuse with entitlements, +and since one of them has default behavior for public access and the other prevents it, it can be difficult to reason about what fields and functions are publicly available in the presence of both entitled and mapped fields. @@ -37,23 +37,23 @@ It is not immediately obvious that given a reference `r` of type `&R`, `r.foo` w ## User Benefit -This will make it easier for users to distinguish between entitled members and mapped members. +This will make it easier for users to distinguish between entitled members and mapped members. ## Design Proposal Currently, an entitlement mapped field or an entitlement mapped reference is specified by using the -name of a mapping (e.g. `M`) in an `access` or `auth` modifier (e.g. `access(M)` or `auth(M)`). +name of a mapping (e.g. `M`) in an `access` or `auth` modifier (e.g. `access(M)` or `auth(M)`). Instead, we would require the keyword `mapping` to be present in the modifiers to indicate -that `M` is a mapping here, rather than an entitlement. +that `M` is a mapping here, rather than an entitlement. So the above modifiers would become `access(mapping M)` and `auth(mapping M)` ### Drawbacks This makes the creation of entitlement mapped fields and functions 16 characters more verbose. I.e. a function -that was previously declared as `access(M) fun foo(): auth(M) &T` would instead have to be declared as -`access(mapping M) fun foo(): auth(mapping M) &T`, which is more verbose. +that was previously declared as `access(M) fun foo(): auth(M) &T` would instead have to be declared as +`access(mapping M) fun foo(): auth(mapping M) &T`, which is more verbose. ### Alternatives Considered -We have not discussed alternative syntactic changes, but are open to suggestions. +We have not discussed alternative syntactic changes, but are open to suggestions. diff --git a/cadence/20231016-reject-references-to-references.md b/cadence/20231016-reject-references-to-references.md index 4ce10634e..ea9b8ee65 100644 --- a/cadence/20231016-reject-references-to-references.md +++ b/cadence/20231016-reject-references-to-references.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 211 authors: Bastian Mueller (bastian@dapperlabs.com) sponsor: Bastian Mueller (bastian@dapperlabs.com) diff --git a/cadence/20231023-cadence-attachments-entitlements.md b/cadence/20231023-cadence-attachments-entitlements.md index a2df05310..fa3f29323 100644 --- a/cadence/20231023-cadence-attachments-entitlements.md +++ b/cadence/20231023-cadence-attachments-entitlements.md @@ -1,16 +1,16 @@ --- -status: implemented +status: released flip: 217 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) -updated: 2023-10-24 +updated: 2023-10-24 --- # FLIP 217: Attachment + Entitlements ## Objective -This FLIP proposes to remove the ability for attachments to `require` entitlements to their `base`, +This FLIP proposes to remove the ability for attachments to `require` entitlements to their `base`, to remove a foot-gun from the language, and replace it with a per-function entitlement inference for the `base` and `self` variables in attachments. @@ -18,9 +18,9 @@ the `base` and `self` variables in attachments. Currently, attachments present a major foot-gun with respect to their interaction with entitlements. In particular, it is possible to authorize an attachment to some entitlement, and then use that to obtain access -to the attachment's base value. While this is safe in and of itself, if a value with attachments is transferred +to the attachment's base value. While this is safe in and of itself, if a value with attachments is transferred to another user, the attachments on that value are transferred as well and may contain attachments with entitlements -that the user is not expecting. +that the user is not expecting. Consider the following example, in which an attachment is used to backdoor a resource: ```cadence @@ -84,7 +84,7 @@ access(all) fun main(): UFix64 { let backdooredVault <- attach Backdoor() to (<- create Vault(balance: 100.0)) with (Withdraw) let c <- create Company(incorporationEquity: <- backdooredVault) var ref = c.getDepositOnlyReference() - + // The following would fail because we only have a Deposit entitlement // var x <- ref.withdraw(amount: ref.balance) // Luckily we have backdoored the underlying vault so we can do this: @@ -95,26 +95,26 @@ access(all) fun main(): UFix64 { destroy c return amountOfFundsStolen -} +} ``` -In this code sample, a resource that wraps a vault is vulnerable to backdooring via an attachment. -A malicious attachment author, as in this example, could write an attachment that requires the ability to `Withdraw` from its base `Vault`, -attach it to this `Vault`, and then provide that input `Vault` to someone else's resource without that other person knowing that the `Vault` +In this code sample, a resource that wraps a vault is vulnerable to backdooring via an attachment. +A malicious attachment author, as in this example, could write an attachment that requires the ability to `Withdraw` from its base `Vault`, +attach it to this `Vault`, and then provide that input `Vault` to someone else's resource without that other person knowing that the `Vault` is compromised. The only way for the author of the `Company` resource in this example to defend against this attack is for them to "sanitize" their `Vault` inputs by enforcing that they have no attachments on them, which is unwieldly and would impose an extremely defensive coding style that is -detrimental to composability on chain. +detrimental to composability on chain. ## User Benefit -This would enable contract authors to write their contracts in a more natural, intuitive style without compromising the safety of their code. +This would enable contract authors to write their contracts in a more natural, intuitive style without compromising the safety of their code. ## Design Proposal -This proposes two main changes to how attachments and entitlements interact. The first changes how access is determined for attachment functions, while +This proposes two main changes to how attachments and entitlements interact. The first changes how access is determined for attachment functions, while the second changes how authorization is decided for attachments on access from references. -1) Removing the `require entitlement` syntax from `attachment` declarations, along with the ability to declare `attachment`s with mapped access. Instead, +1) Removing the `require entitlement` syntax from `attachment` declarations, along with the ability to declare `attachment`s with mapped access. Instead, all attachments will be declared with `access(all)` access on their declaration, and the entitlements of the `self` and `base` references in each function will be determined by the entitlements used in the access of that function. So, for example, the `Backdoor` attachment above would fail if written as: @@ -140,32 +140,32 @@ determined by the entitlements used in the access of that function. So, for exam This definition would type check, as since `sneakyWithdraw` has `Withdraw` access, this means that `self` and `base` are entitled to `Withdraw` in its body. This brings us to the second proposed change: -2) Attachment access always propagates entitlements from its base as if through the `Identity` map. Equivalently, `v[A]` always produces a reference to `A` that is entitled to the same entitlements as `v`. This means that in the above example, the definition of `sneakyWithdraw` is safe because a `Withdraw`-entitled reference to -`Backdoor` can only be obtained from a `Withdraw`-entitled reference to `Vault`. Effectively, this means that the owner of an value with attachments has the sole +2) Attachment access always propagates entitlements from its base as if through the `Identity` map. Equivalently, `v[A]` always produces a reference to `A` that is entitled to the same entitlements as `v`. This means that in the above example, the definition of `sneakyWithdraw` is safe because a `Withdraw`-entitled reference to +`Backdoor` can only be obtained from a `Withdraw`-entitled reference to `Vault`. Effectively, this means that the owner of an value with attachments has the sole ability to decide the entitlements with which those attachments can be used, since they are the only one who can create references to that value. Since references -are invalidated when resources are transferred, resource owners do not "inherit" attachment entitlements upon receiving a value from another user. +are invalidated when resources are transferred, resource owners do not "inherit" attachment entitlements upon receiving a value from another user. Note that this necessarily implies that attachments can only support the same entitlements that exist on the `base` value. I.e. an attachment defined for some -`R` that only has entitlements `X` and `Y` will itself only support `X` and `Y`. +`R` that only has entitlements `X` and `Y` will itself only support `X` and `Y`. ### Drawbacks This does necessarily limit some use cases; it will no longer be possible to define separate entitlements for attachments for any new functionality that they may -add on top of what the base can do. However, this is the least limiting solution we identified. +add on top of what the base can do. However, this is the least limiting solution we identified. ### Alternatives Considered A number of alternatives exist for this change: 1) Leave the attachments feature as is, and encourage developers to code defensively. We would likely need to add some utility features -to attachments, like a `hasAttachments: Bool` field on resource and a `removeAttachment(ty: Type)` method to allow authors to dynamically sanitize inputs to their +to attachments, like a `hasAttachments: Bool` field on resource and a `removeAttachment(ty: Type)` method to allow authors to dynamically sanitize inputs to their resources. This would make writing attachments as simple as possible, as they would have the full range of expressivity they do in the current version of Stable Cadence. However, it would achieve this by placing an extreme burden on the authors of resources by forcing them to consider every possible attachment that might exist on their -resources, and to code extremely defensively at all times. We feel that this is unfeasible, and would be an undue burden on developers. +resources, and to code extremely defensively at all times. We feel that this is unfeasible, and would be an undue burden on developers. -2) Require `base` references to be entitled to the required entitlements to access attachments on them. In the example outlined in the "Motivation" section, one way -to resolve this backdooring issue would be to require that any `Vault` reference on which the `Backdoor` attachment is accessed be itself entitled to `Withdraw`. This way, the `var x <- ref[Backdoor]!.sneakyWithdraw(amount: ref.balance)` line would fail, as `ref` is not entitled to `Withdraw`, and thus `Backdoor` would not be accessible. In general, for some attachement `A` `require`ing entitlement `E`, `v[A]` would require that `v` either be a composite, or a reference entitled to `E`. +2) Require `base` references to be entitled to the required entitlements to access attachments on them. In the example outlined in the "Motivation" section, one way +to resolve this backdooring issue would be to require that any `Vault` reference on which the `Backdoor` attachment is accessed be itself entitled to `Withdraw`. This way, the `var x <- ref[Backdoor]!.sneakyWithdraw(amount: ref.balance)` line would fail, as `ref` is not entitled to `Withdraw`, and thus `Backdoor` would not be accessible. In general, for some attachement `A` `require`ing entitlement `E`, `v[A]` would require that `v` either be a composite, or a reference entitled to `E`. - This idea is convenient because it still allows attachment authors to write most of their use cases as normal, and does not require base resource authors to defend + This idea is convenient because it still allows attachment authors to write most of their use cases as normal, and does not require base resource authors to defend against these kinds of backdooring attacks. There is no harm done in the definition of `Backdoor` in this model, as if `Backdoor` is accessible on any base, that `base` was already able to `withdraw` anyways, so no rights escalation occurs in practice. However, this is crucially limiting for one major reason: it becomes impossible to write an attachment that has multiple entitlements that should each be individually available. Consider the following use case, an attachment for a `Vault` that is designed to automatically convert between an `A` and `B` currency, e.g (in pseudo-code): ``` @@ -188,9 +188,9 @@ to resolve this backdooring issue would be to require that any `Vault` reference ``` In this example, the `BConverter` requires a `Deposit` and `Withdraw` entitlement to its `AVault` base, so that it can `deposit` into it from its own `deposit` function, - and `withdraw` from it in its `withdraw` function. However, it does not need these two entitlements at the same time. So, if we were to require that `BConverter` is only accessible on `AVault` references that are entitled to both `Deposit` and `Withdraw`, it would not be possible to access a `BConverter` on an `auth(Deposit) AVault` reference. This is unfortunate, as there is no reason that we should need to be able to `withdraw` from an `AVault` in order to `deposit` a converted `B` currency into it. + and `withdraw` from it in its `withdraw` function. However, it does not need these two entitlements at the same time. So, if we were to require that `BConverter` is only accessible on `AVault` references that are entitled to both `Deposit` and `Withdraw`, it would not be possible to access a `BConverter` on an `auth(Deposit) AVault` reference. This is unfortunate, as there is no reason that we should need to be able to `withdraw` from an `AVault` in order to `deposit` a converted `B` currency into it. - It could be possible to split the `BConverter` into two attachments `BDepositor` and `BWithdrawer` that each has only one of the two functions and thus requires only one of the two entitlements. Then someone with an `auth(Deposit) &AVault` could access a `BDepositor`, while a `auth(Withdraw) &AVault` would be necessary for to access a `BWithdrawer`. However, this only works when the entitlements in an attachment can be cleanly split like in this example, in more complex use cases this may not be feasible. It furthermore encourages a coding pattern where attachments must only handle exactly one piece of functionality, and "composition" attachments would become necessary to handle interaction between these many different kinds of attachments. Given that the presence of a sub attachment cannot be guaranteed statically, this would also require attachment authors to explicitly handle all possible combinations of sub-attachments that may or may not be necessary for their logic. + It could be possible to split the `BConverter` into two attachments `BDepositor` and `BWithdrawer` that each has only one of the two functions and thus requires only one of the two entitlements. Then someone with an `auth(Deposit) &AVault` could access a `BDepositor`, while a `auth(Withdraw) &AVault` would be necessary for to access a `BWithdrawer`. However, this only works when the entitlements in an attachment can be cleanly split like in this example, in more complex use cases this may not be feasible. It furthermore encourages a coding pattern where attachments must only handle exactly one piece of functionality, and "composition" attachments would become necessary to handle interaction between these many different kinds of attachments. Given that the presence of a sub attachment cannot be guaranteed statically, this would also require attachment authors to explicitly handle all possible combinations of sub-attachments that may or may not be necessary for their logic. 3) Simply remove support for entitlements on attachments. This proposal is maximally safe, in that there is minimal risk of security issues, since it will be impossible -to access any entitled features of the `base` reference. It is, however, also quite limiting, in that it would prevent a large number of potential attachment use cases from being expressible in Cadence. +to access any entitled features of the `base` reference. It is, however, also quite limiting, in that it would prevent a large number of potential attachment use cases from being expressible in Cadence. diff --git a/cadence/20240123-capcon-get-capability-api-improvement.md b/cadence/20240123-capcon-get-capability-api-improvement.md index a7dbc1261..3778efe3d 100644 --- a/cadence/20240123-capcon-get-capability-api-improvement.md +++ b/cadence/20240123-capcon-get-capability-api-improvement.md @@ -1,5 +1,5 @@ --- -status: approved +status: released flip: 242 authors: Austin Kline (austin@flowty.io) sponsor: Bastian Müller @@ -28,10 +28,10 @@ behavior as well for other contracts like Flowty Loans. ## User Benefit -There is value in a Capability not being nil, even if it is not borrowable. +There is value in a Capability not being nil, even if it is not borrowable. Nil is not the same as invalid, because we still have the address field which is something that is used often by developers. -Modifying the behavior for obtaining capabilities to instead give an invalid capability allows developers to make use of that address and react to something not being valid. -It also introduces fewer panic scenarios that are out of general-purpose platforms' control (like if an NFT Collection panics on Royalty creation because of this). +Modifying the behavior for obtaining capabilities to instead give an invalid capability allows developers to make use of that address and react to something not being valid. +It also introduces fewer panic scenarios that are out of general-purpose platforms' control (like if an NFT Collection panics on Royalty creation because of this). Even an invalid capability that cannot be borrowed is still valuable, as it provides the address of the account. ## Design Proposal @@ -46,7 +46,7 @@ This "invalid" capability should: 3. Have an ID of 0. 4. Have a runtime type that is the same as the type requested in the type argument of `get` -Capability Controller IDs are stated to be a *non-zero*, which +Capability Controller IDs are stated to be a *non-zero*, which means the value of zero can be used to mark capabilities as invalid. ## Alternatives Considered @@ -56,11 +56,11 @@ It was suggested that anything which is expecting a non-nil Capability could ins ``` struct OptCap { let address: Address - let cap: Capability? + let cap: Capability? } ``` -This might work in cases where the method being called is entirely in control of the caller, but it will not cover cases like Royalties where they are being blindly resolved using the +This might work in cases where the method being called is entirely in control of the caller, but it will not cover cases like Royalties where they are being blindly resolved using the Flow Metadata Standard. In cases like that, the caller has no way to protect itself again an optional capability that will panic when being created diff --git a/cadence/20240415-remove-non-public-entitled-interface-members.md b/cadence/20240415-remove-non-public-entitled-interface-members.md index 211492c6e..3b7431e94 100644 --- a/cadence/20240415-remove-non-public-entitled-interface-members.md +++ b/cadence/20240415-remove-non-public-entitled-interface-members.md @@ -1,5 +1,5 @@ --- -status: approved +status: released flip: 262 authors: Bastian Müller (bastian.mueller@flowfoundation.org) updated: 2024-04-15 diff --git a/cadence/20240604-cadence-type-removal.md b/cadence/20240604-cadence-type-removal.md index b33096b32..cd7d8eef1 100644 --- a/cadence/20240604-cadence-type-removal.md +++ b/cadence/20240604-cadence-type-removal.md @@ -1,6 +1,6 @@ --- -status: accepted -flip: 275 +status: released +flip: 275 authors: Daniel Sainati (daniel.sainati@flowfoundation.org) sponsor: Daniel Sainati (daniel.sainati@flowfoundation.org) updated: 2024-10-30 @@ -12,12 +12,12 @@ updated: 2024-10-30 This adds a new pragma to Cadence that when processed by the contract update validator will allow a type to be removed from a contract, and also prevent a type with the same name from being -added to that contract later. +added to that contract later. ## Motivation As originally outlined in https://github.com/onflow/cadence/issues/3210, users have been asking for -the ability to remove types from their contracts as they become outdated or otherwise unnecessary. +the ability to remove types from their contracts as they become outdated or otherwise unnecessary. The Cadence 1.0 upgrade in particular had exacerbated this need, as the changes to access control have rendered a number of types obsolete. @@ -32,10 +32,10 @@ This will allow users to remove deprecated or unnecessary type definitions from ## Design Proposal The proposal is to introduces a new `#removedType` pragma to Cadence. -This pragma takes a single argument, an identifier specifying the type that got removed. +This pragma takes a single argument, an identifier specifying the type that got removed. Importantly, this identifier is not qualified, i.e. to remove a type `R` from a contract `C`, `#removedType(R)` would be used, rather than `#removedType(C.R)`. -This is because the pragma is added at the same scope at which the type to be removed was originally defined. +This is because the pragma is added at the same scope at which the type to be removed was originally defined. So, for example, to remove a resource `R` from `C` defined like so: ```cadence @@ -55,27 +55,27 @@ the pragma would be placed here: access(all) contract C { #removedType(R) - + // ... contract body } ``` Placing the pragma at the top level, or nested inside another definition in `C` has no effect, and does not permit the removal of `R`. -When used correctly, the pragma is processed by the contract update validator and allows an update to `C` to be +When used correctly, the pragma is processed by the contract update validator and allows an update to `C` to be performed that does not include a definition of the resource type `R`, even though the old version of `C` did include `R`. -In fact, when the `#removedType(T)` pragma is present, the contract update validator will reject any update to the +In fact, when the `#removedType(T)` pragma is present, the contract update validator will reject any update to the contract that includes a definition of `T` at the same scope level as the pragma. This is to prevent the type from being added back later with incompatible changes that would otherwise circumvent the contract update validation restrictions. Additionally, once present in a contract, the `#removedType(T)` pragma may never be removed, as this would allow the type -it removed to be re-added, once again potentially circumventing the update validation. +it removed to be re-added, once again potentially circumventing the update validation. Lastly, the `#removedType` pragma may only be used with concrete types (`struct`s, `resource`s, `enum`s, and `attachment`s), -not with interfaces. +not with interfaces. This is due to the fact that a removed interface cannot be removed from any existing conformance lists in which it is present, -and thus removing an interface would irrevocably break any downstream types that inherited from it. +and thus removing an interface would irrevocably break any downstream types that inherited from it. ### Draft Implementation @@ -90,20 +90,20 @@ In some cases this is more feasible than in others; if a resource definition `R` In the latter case, the attachment `A` is likely unusable and will also have to be removed. However, it is worth mentioning that this is no different from someone removing a function definition from a type, -and any downstream code that depends on that particular function being broken, which is already possible. +and any downstream code that depends on that particular function being broken, which is already possible. As such, the backward compatibility of deployed code is not guaranteed by (and is not an objective of) the contract update validation anyway. -Additionally, any existing stored values of the removed type will be broken and un-usable forever. +Additionally, any existing stored values of the removed type will be broken and un-usable forever. Because we do not currently possess a way to remove broken values from storage, the inability to load these values also means they will sit in storage forever. -This change significantly increases the priority of implementing a solution for deleting broken values in storage. +This change significantly increases the priority of implementing a solution for deleting broken values in storage. ### Alternatives Considered -As outlined in https://github.com/onflow/cadence/issues/3210, an alternative pragma specifying a type replacement, -rather than a removal was considered. We elected to do the first, easier solution due to time constraints, but are open -to considering the second given sufficiently good reason. +As outlined in https://github.com/onflow/cadence/issues/3210, an alternative pragma specifying a type replacement, +rather than a removal was considered. We elected to do the first, easier solution due to time constraints, but are open +to considering the second given sufficiently good reason. ## Questions and Discussion diff --git a/cadence/20240612-import-contract-as-reference.md b/cadence/20240612-import-contract-as-reference.md index 4491ae67d..4e877cc7f 100644 --- a/cadence/20240612-import-contract-as-reference.md +++ b/cadence/20240612-import-contract-as-reference.md @@ -1,5 +1,5 @@ --- -status: approved +status: released flip: 277 authors: Supun Setunga (supun.setunga@flowfoundation.org) sponsor: Supun Setunga (supun.setunga@flowfoundation.org) @@ -25,13 +25,13 @@ Otherwise, if someone only got a reference to the composite value, then they can and the entitlements would kick-in to limit what they can do with those fields. Unfortunately, one edge-case that was not considered during the evaluation of the [external mutability improvements FLIP](https://github.com/onflow/flips/pull/89) is that contracts are singletons, and importing a contract provides owned access to that contract value. -The imported contract value behaves like a reference, but is not represented using a reference in the language semantics. +The imported contract value behaves like a reference, but is not represented using a reference in the language semantics. Because of that, if the contract has a container-typed field (e.g., array, dictionary, composite) defined with public access (i.e., `access(all)`), then anyone could modify the content of that field, such as inserting/removing elements, etc. ```cadence access(all) contract Foo { - access(all) var array : [Int] // Can't set a new value to the array, but can "update" the content (insert/remove/etc) + access(all) var array : [Int] // Can't set a new value to the array, but can "update" the content (insert/remove/etc) } ``` @@ -94,20 +94,20 @@ contract Foo { init() { self.array = [] } - + access(all) fun bar() { // Accessing the contract within itself would return the concrete value, not a reference. - + var foo: Foo = Foo // Type the contract value is `Foo` (not `&Foo)` - + var array: [Int] = Foo.array // Accessing field would also return a copy of the concrete value. - + // Modifying fields within the contract is allowed. Foo.array[0] = 3 Foo.array.append(42) Foo.array.remove(at: 0) } -} +} ``` ### Drawbacks diff --git a/cadence/20240726-pre-cadence-1-import.md b/cadence/20240726-pre-cadence-1-import.md index ff1e65c83..8b03f580f 100644 --- a/cadence/20240726-pre-cadence-1-import.md +++ b/cadence/20240726-pre-cadence-1-import.md @@ -1,5 +1,5 @@ --- -status: implemented +status: released flip: 282 authors: bastian.mueller@flowfoundation.org updated: 2024-08-13 diff --git a/cadence/20240923-simple-string-interpolation.md b/cadence/20240923-simple-string-interpolation.md index f06c77691..a19ed30d6 100644 --- a/cadence/20240923-simple-string-interpolation.md +++ b/cadence/20240923-simple-string-interpolation.md @@ -1,8 +1,8 @@ --- -status: accepted +status: released flip: 288 authors: Raymond Zhang (raymond.zhang@flowfoundation.org) -sponsor: Supun Setunga (supun.setunga@flowfoundation.org) +sponsor: Supun Setunga (supun.setunga@flowfoundation.org) updated: 2024-10-30 --- @@ -14,9 +14,9 @@ This FLIP proposes adding support for simple string interpolation limited to ide ## Motivation -Currently Cadence has no support for string interpolation. It is convenient for developers to be able to inline variables in strings as opposed to the current solution of applying `concat` repeatedly. +Currently Cadence has no support for string interpolation. It is convenient for developers to be able to inline variables in strings as opposed to the current solution of applying `concat` repeatedly. -In general many languages support string interpolation for readability and ease-of-use. +In general many languages support string interpolation for readability and ease-of-use. ## User Benefit @@ -32,11 +32,11 @@ The proposed syntax for the string-literal with interpolation looks like follows "Variable = \(someVar)" ``` -The main constraint is backward compatibility, existing Cadence 1.0 code cannot be affected. This change is backwards compatible because `\(` is not currently a valid escape character. +The main constraint is backward compatibility, existing Cadence 1.0 code cannot be affected. This change is backwards compatible because `\(` is not currently a valid escape character. For this initial proposal there will be several limitations on `someVar`: - `someVar` will only be variable references with ability to be extended to expressions in the future -- `someVar` must support the built-in function `toString()` meaning it must be either a `String`, `Number`, `Address`, `Character`, `Bool` or `Path`. +- `someVar` must support the built-in function `toString()` meaning it must be either a `String`, `Number`, `Address`, `Character`, `Bool` or `Path`. This is still useful for the first iteration since there are easy workarounds for these limitations such as extracting expressions into local variables. @@ -74,7 +74,7 @@ None. ### Engineering Impact -This change should be simple to implement. +This change should be simple to implement. ### Best Practices @@ -82,11 +82,11 @@ It may be preferred to use string interpolation over concat once implemented. ### Compatibility -Proposed changes are backwards compatible. +Proposed changes are backwards compatible. ### User Impact -This is a feature addition, no impact. +This is a feature addition, no impact. ## Related Issues diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md index 104a4d8b8..3f81ff01f 100644 --- a/cadence/20241010-stringer-interface.md +++ b/cadence/20241010-stringer-interface.md @@ -1,5 +1,5 @@ --- -status: approved +status: released flip: 293 authors: Raymond Zhang (raymond.zhang@flowfoundation.org) sponsor: Supun Setunga (supun.setunga@flowfoundation.org) diff --git a/cadence/20241212-import-aliasing.md b/cadence/20241212-import-aliasing.md index 0ec1bb586..0d8bb3f23 100644 --- a/cadence/20241212-import-aliasing.md +++ b/cadence/20241212-import-aliasing.md @@ -1,5 +1,5 @@ --- -status: accepted +status: released flip: 314 authors: Raymond Zhang (raymond.zhang@flowfoundation.org) sponsor: Supun Setunga (supun.setunga@flowfoundation.org) @@ -69,7 +69,7 @@ Feature addition, no impact. ## Related Issues -Consider extension for type aliasing in the future. +Consider extension for type aliasing in the future. ## Implementation https://github.com/onflow/cadence/pull/4033 diff --git a/cadence/20250815-128-bit-fixed-point-types.md b/cadence/20250815-128-bit-fixed-point-types.md index c1a60c706..7c957b02f 100644 --- a/cadence/20250815-128-bit-fixed-point-types.md +++ b/cadence/20250815-128-bit-fixed-point-types.md @@ -1,5 +1,5 @@ --- -status: accepted +status: released flip: 341 authors: Supun Setunga (supun.setunga@flowfoundation.org) sponsor: Dieter Shirley (dete@flowfoundation.com) @@ -14,7 +14,7 @@ The objective is to add a set of 128-bit wide fixed-point types, `Fix128` and `U ## Motivation -Cadence currently only supports 64-bit wide decimal fixed-point types, `Fix64` and `UFix64`, +Cadence currently only supports 64-bit wide decimal fixed-point types, `Fix64` and `UFix64`, having the ranges `-92233720368.54775808` through `92233720368.54775807` and `0.0` through `184467440737.09551615` respectively. @@ -41,7 +41,7 @@ Although 27 is the most commonly used value internally by defi protocols, the va introduces a type that can hold values in the trillions (extreme, but plausible values for very large financial calculations). Note that all `UFix64` and `Fix64` values can be converted to the equivalent 128-bit types without any loss of precision or range. -A scaling factor of 24 provides a very high precision for fractional values, while also leaving large enough upper and +A scaling factor of 24 provides a very high precision for fractional values, while also leaving large enough upper and lower bounds sufficient for most real-world use cases (which typically will involve internal calculations that convert back to the 64-bit types). diff --git a/cadence/20250828-Fix-number-type-division-inconsistancy.md b/cadence/20250828-Fix-number-type-division-inconsistancy.md index 9de3056da..ea37ee13e 100644 --- a/cadence/20250828-Fix-number-type-division-inconsistancy.md +++ b/cadence/20250828-Fix-number-type-division-inconsistancy.md @@ -1,5 +1,5 @@ --- -status: accepted +status: released flip: 343 authors: Supun Setunga (supun.setunga@flowfoundation.org), Dieter Shirley (dete@flowfoundation.com) sponsor: Dieter Shirley (dete@flowfoundation.com) @@ -10,7 +10,7 @@ updated: 2025-09-08 ## Objective -Provide a well-defined, consistent behaviour for handling the least-significant digit in arithmetic operations for +Provide a well-defined, consistent behaviour for handling the least-significant digit in arithmetic operations for all Cadence numeric types. ## Motivation @@ -106,7 +106,7 @@ Fix64(-0.00000005) / Fix64(-2.0) == Fix64(0.00000002) Note that this suggested change would only impact the **division (and saturation division) of negative values** for the above types. Division of non-negative numbers, as well as all the other arithmetics on both negative and non-negative numbers, -would remain unchanged. +would remain unchanged. ### Drawbacks