From 04d536ba86b7f697ebf149da13cf737e9c1ef7fc Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 24 Oct 2023 13:02:03 -0400 Subject: [PATCH 1/7] add FLIP --- ...231023-cadence-attachments-entitlements.md | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 cadence/20231023-cadence-attachments-entitlements.md diff --git a/cadence/20231023-cadence-attachments-entitlements.md b/cadence/20231023-cadence-attachments-entitlements.md new file mode 100644 index 00000000..3ed830e7 --- /dev/null +++ b/cadence/20231023-cadence-attachments-entitlements.md @@ -0,0 +1,178 @@ +--- +status: draft +flip: NNN (set to the issue number) +authors: Daniel Sainati (daniel.sainati@dapperlabs.com) +sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) +updated: 2023-10-23 +--- + +# FLIP NNN: Attachment Entitlements Reversion + +## Objective + +This FLIP proposes to remove the ability for attachments to `require` entitlements to their `base`, +to remove a foot-gun from the language. + +## Motivation + +Currently, attachments present a major foot-gun with respect to their interaction with entitlements. +Consider the following example, in which an attachment is used to backdoor a resource: + +``` + +// standard code +access(all) entitlement Withdraw +access(all) entitlement Deposit +access(all) resource Vault { + access(all) var balance: UFix64 + init(balance: UFix64) { + self.balance = balance + } + access(Withdraw) fun withdraw(amount: UFix64): @Vault { + self.balance = self.balance - amount + return <-create Vault(balance: amount) + } + access(Deposit) fun deposit(from: @Vault) { + self.balance = self.balance + from.balance + from.balance = 0.0; + destroy from + } +} + +// Victim code starts - designed without thinking about attachments +access(all) resource Company { + access(self) var vault: @Vault; + init(incorporationEquity: @Vault){ + pre { + incorporationEquity.balance >= 100.0 + } + self.vault <- incorporationEquity + } + access(all) fun getDepositOnlyReference(): auth(Deposit) &Vault { + return &self.vault as auth(Deposit) &Vault + } + destroy() { + destroy self.vault + } +} +// Victim code ends + + +access(all) attachment Backdoor for Vault { + require entitlement Withdraw + access(all) fun sneakyWithdraw(amount: UFix64): @Vault { + return <- base.withdraw(amount: amount) + } +} + + +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: + var x <- ref[Backdoor]!.sneakyWithdraw(amount: ref.balance) + var amountOfFundsStolen = x.balance + destroy x + 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` +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. + +## User Benefit + +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: + +1) `base` is always unentitled. Instead of allowing attachment authors to ask for specific entitlements to the `base` reference with `require` syntax, the `base` reference in an attachment is always unentitled. This means that no entitled methods on the base resource will be callable at any point, and thus will limit attachments to interaction only with the "publicly" visible portion of a resource. This would prevent the backdooring example above by preventing the definition of `Backdoor`; `sneakyWithdraw` would never be defineable because `base` will not be entitled to `Withdraw`. + +2) The `self` reference will be changed to have differing entitlements from function to function. Specifically, given some attachment definition: + + ``` + entitlement mapping M { + // ... + } + + access(M) attachment A for R { + access(X) fun foo() { ... } + } + ``` + + Within `foo`, `self` would be entitled to `X`. In general, within a method body, the `self` reference would always just be entitled to the set of entitlements requested by that method. This change is not strictly necessary for fixing the backdooring problem, but is important to allow us to eventually re-enable entitlements + on the `base` later down the line, should we have a non-breaking means for doing so. + +### Drawbacks + +This does necessarily limit some use cases; in this limited model it will not be possible to write attachments that interact with +any entitled methods on the `base`. Howevever, this proposal does still leave open the possibility of entitlement inference/checking for the `base` +to be re-added in a non-breaking way after the release of Cadence 1.0. + +### 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 +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. + +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 + 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): + + ``` + attachment BConverter for AVault { + require entitlement Deposit, Withdraw + + access(Deposit) deposit(bVault: @BVault) { + let aVault <- create AVault(b.balance * exchangeRate) + base.deposit(<- aVault) // requires Deposit entitlement on base + destroy bVault + } + access(Withdraw) withdraw(amountInB: UFix64): @BVault { + let amountInA = amountInB * exchangeRate + let aVault <- base.withdraw(amountInA) // requires Withdraw entitlement on base + let bVault <- create BVault(a.balance / exchangeRate) + destroy aVault + return <- bVault + } + } + ``` + + 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. + + 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) Revert to the old version of attachment entitlement inference originally proposed in the entitlements FLIP. This FLIP originally proposed a mechanism for inferring the entitlements of the `base` reference in an attachment for each method based on the entitlements of that method and the mapping that was used to define the attachment. I.e. for some attachment declaration: + + ``` + entitlement mapping M { + // ... + } + + access(M) attachment A for R { + access(X) fun foo() { ... } + } + ``` + + We would infer the entitlements that `base` has in the body of `foo` based on `M` and `X`; specifically, `base` in `foo` would be entitled to `M⁻¹(X)` . Essentially, given that an `X` entitlement to `A` is only available via access on an `R` that is entitled to at least `M⁻¹(X)`, this inference is reverse-engineering the entitlements that the `base` would have needed to have in order to make `foo` callable on `A`. + + This is extremely complicated, and we moved away from this proposal for the sake of simplicity, to not further complicate an already complex feature. However, were we to move back to this model it would fully resolve the backdooring issue without sacrificing any expressivity on the part of the attachment author or the resource author. + +While each of these 3 alternatives present a solution to the backdooring problem, we ultimately selected the proposed solution because it solves the issue while also +leaving open the most future improvemetns. By restricting `base` to unentitled references only, in the future we can add more functionality to enable using entitlements with `base` without making any breaking changes. By contrast, each of these 3 proposals would require a breaking change in order to make any alterations to how entitlements interact with `base`. From e83ab39e026773154d5e66ec9ba85a86d9228cde Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 25 Oct 2023 13:00:24 -0400 Subject: [PATCH 2/7] update FLIP --- ...231023-cadence-attachments-entitlements.md | 61 +++++++++---------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/cadence/20231023-cadence-attachments-entitlements.md b/cadence/20231023-cadence-attachments-entitlements.md index 3ed830e7..3ff533c2 100644 --- a/cadence/20231023-cadence-attachments-entitlements.md +++ b/cadence/20231023-cadence-attachments-entitlements.md @@ -18,8 +18,7 @@ to remove a foot-gun from the language. Currently, attachments present a major foot-gun with respect to their interaction with entitlements. Consider the following example, in which an attachment is used to backdoor a resource: -``` - +```cadence // standard code access(all) entitlement Withdraw access(all) entitlement Deposit @@ -96,28 +95,42 @@ This would enable contract authors to write their contracts in a more natural, i This proposes two main changes to how attachments and entitlements interact: -1) `base` is always unentitled. Instead of allowing attachment authors to ask for specific entitlements to the `base` reference with `require` syntax, the `base` reference in an attachment is always unentitled. This means that no entitled methods on the base resource will be callable at any point, and thus will limit attachments to interaction only with the "publicly" visible portion of a resource. This would prevent the backdooring example above by preventing the definition of `Backdoor`; `sneakyWithdraw` would never be defineable because `base` will not be entitled to `Withdraw`. - -2) The `self` reference will be changed to have differing entitlements from function to function. Specifically, given some attachment definition: +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: ``` - entitlement mapping M { - // ... + access(all) attachment Backdoor for Vault { + access(all) fun sneakyWithdraw(amount: UFix64): @Vault { + return <- base.withdraw(amount: amount) + } } + ``` - access(M) attachment A for R { - access(X) fun foo() { ... } + Here, `sneakyWithdraw` withdraw would not type check because it is declared as `access(all)`, meaning that `self` and `base` are unentitled in its body. Conversely, if + the definition were written as + + ``` + access(all) attachment Backdoor for Vault { + access(Withdraw) fun sneakyWithdraw(amount: UFix64): @Vault { + return <- base.withdraw(amount: amount) + } } ``` - Within `foo`, `self` would be entitled to `X`. In general, within a method body, the `self` reference would always just be entitled to the set of entitlements requested by that method. This change is not strictly necessary for fixing the backdooring problem, but is important to allow us to eventually re-enable entitlements - on the `base` later down the line, should we have a non-breaking means for doing so. + 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`. + + 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`. ### Drawbacks -This does necessarily limit some use cases; in this limited model it will not be possible to write attachments that interact with -any entitled methods on the `base`. Howevever, this proposal does still leave open the possibility of entitlement inference/checking for the `base` -to be re-added in a non-breaking way after the release of Cadence 1.0. +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. ### Alternatives Considered @@ -158,21 +171,5 @@ to resolve this backdooring issue would be to require that any `Vault` reference 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) Revert to the old version of attachment entitlement inference originally proposed in the entitlements FLIP. This FLIP originally proposed a mechanism for inferring the entitlements of the `base` reference in an attachment for each method based on the entitlements of that method and the mapping that was used to define the attachment. I.e. for some attachment declaration: - - ``` - entitlement mapping M { - // ... - } - - access(M) attachment A for R { - access(X) fun foo() { ... } - } - ``` - - We would infer the entitlements that `base` has in the body of `foo` based on `M` and `X`; specifically, `base` in `foo` would be entitled to `M⁻¹(X)` . Essentially, given that an `X` entitlement to `A` is only available via access on an `R` that is entitled to at least `M⁻¹(X)`, this inference is reverse-engineering the entitlements that the `base` would have needed to have in order to make `foo` callable on `A`. - - This is extremely complicated, and we moved away from this proposal for the sake of simplicity, to not further complicate an already complex feature. However, were we to move back to this model it would fully resolve the backdooring issue without sacrificing any expressivity on the part of the attachment author or the resource author. - -While each of these 3 alternatives present a solution to the backdooring problem, we ultimately selected the proposed solution because it solves the issue while also -leaving open the most future improvemetns. By restricting `base` to unentitled references only, in the future we can add more functionality to enable using entitlements with `base` without making any breaking changes. By contrast, each of these 3 proposals would require a breaking change in order to make any alterations to how entitlements interact with `base`. +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. From b00f8110792c980feec6d7f60467d6cf84981117 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 25 Oct 2023 13:15:01 -0400 Subject: [PATCH 3/7] add clarification to objective --- cadence/20231023-cadence-attachments-entitlements.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cadence/20231023-cadence-attachments-entitlements.md b/cadence/20231023-cadence-attachments-entitlements.md index 3ff533c2..3808712f 100644 --- a/cadence/20231023-cadence-attachments-entitlements.md +++ b/cadence/20231023-cadence-attachments-entitlements.md @@ -3,15 +3,16 @@ status: draft flip: NNN (set to the issue number) authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) -updated: 2023-10-23 +updated: 2023-10-24 --- -# FLIP NNN: Attachment Entitlements Reversion +# FLIP NNN: Attachment + Entitlements ## Objective This FLIP proposes to remove the ability for attachments to `require` entitlements to their `base`, -to remove a foot-gun from the language. +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. ## Motivation From 49de530ca245f9fe023504c3368a786daa06745d Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 31 Oct 2023 15:15:43 -0400 Subject: [PATCH 4/7] Update cadence/20231023-cadence-attachments-entitlements.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- cadence/20231023-cadence-attachments-entitlements.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cadence/20231023-cadence-attachments-entitlements.md b/cadence/20231023-cadence-attachments-entitlements.md index 3808712f..20c795cb 100644 --- a/cadence/20231023-cadence-attachments-entitlements.md +++ b/cadence/20231023-cadence-attachments-entitlements.md @@ -1,12 +1,12 @@ --- -status: draft -flip: NNN (set to the issue number) +status: proposed +flip: 217 (set to the issue number) authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) updated: 2023-10-24 --- -# FLIP NNN: Attachment + Entitlements +# FLIP 217: Attachment + Entitlements ## Objective From ee4e89af69f550fd3f9ef997ed9bf68ba8c9371e Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 31 Oct 2023 20:28:34 -0400 Subject: [PATCH 5/7] Update cadence/20231023-cadence-attachments-entitlements.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- cadence/20231023-cadence-attachments-entitlements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/20231023-cadence-attachments-entitlements.md b/cadence/20231023-cadence-attachments-entitlements.md index 20c795cb..07e8346e 100644 --- a/cadence/20231023-cadence-attachments-entitlements.md +++ b/cadence/20231023-cadence-attachments-entitlements.md @@ -1,6 +1,6 @@ --- status: proposed -flip: 217 (set to the issue number) +flip: 217 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com) updated: 2023-10-24 From 50478bfec224108b5b7f5aaf20feb891ba3b632b Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 15 Nov 2023 11:19:21 -0500 Subject: [PATCH 6/7] clarify some flip points --- ...231023-cadence-attachments-entitlements.md | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/cadence/20231023-cadence-attachments-entitlements.md b/cadence/20231023-cadence-attachments-entitlements.md index 07e8346e..2b73bfb1 100644 --- a/cadence/20231023-cadence-attachments-entitlements.md +++ b/cadence/20231023-cadence-attachments-entitlements.md @@ -17,66 +17,83 @@ the `base` and `self` variables in attachments. ## Motivation 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 another user, the attachments on that value are transferred as well and may contain attachments with entitlements +that the user is not expecting. Consider the following example, in which an attachment is used to backdoor a resource: ```cadence // standard code access(all) entitlement Withdraw access(all) entitlement Deposit + access(all) resource Vault { + access(all) var balance: UFix64 + init(balance: UFix64) { self.balance = balance } + access(Withdraw) fun withdraw(amount: UFix64): @Vault { self.balance = self.balance - amount return <-create Vault(balance: amount) } + access(Deposit) fun deposit(from: @Vault) { self.balance = self.balance + from.balance - from.balance = 0.0; + from.balance = 0.0 destroy from } + } // Victim code starts - designed without thinking about attachments access(all) resource Company { - access(self) var vault: @Vault; - init(incorporationEquity: @Vault){ + + access(self) var vault: @Vault + + init(incorporationEquity: @Vault) { + pre { incorporationEquity.balance >= 100.0 } + self.vault <- incorporationEquity } + access(all) fun getDepositOnlyReference(): auth(Deposit) &Vault { return &self.vault as auth(Deposit) &Vault } - destroy() { - destroy self.vault - } } // Victim code ends - access(all) attachment Backdoor for Vault { + require entitlement Withdraw + access(all) fun sneakyWithdraw(amount: UFix64): @Vault { return <- base.withdraw(amount: amount) } -} +} 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: var x <- ref[Backdoor]!.sneakyWithdraw(amount: ref.balance) var amountOfFundsStolen = x.balance + destroy x destroy c + return amountOfFundsStolen } ``` @@ -94,7 +111,8 @@ This would enable contract authors to write their contracts in a more natural, i ## Design Proposal -This proposes two main changes to how attachments and entitlements interact: +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, 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 @@ -123,10 +141,12 @@ determined by the entitlements used in the access of that function. So, for exam 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`. +`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. - 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`. +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`. ### Drawbacks From ab584e6dd80e4fa928cb821fb10d4f7780c9e2dd Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Mon, 27 Nov 2023 08:48:36 -0500 Subject: [PATCH 7/7] Update cadence/20231023-cadence-attachments-entitlements.md --- cadence/20231023-cadence-attachments-entitlements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/20231023-cadence-attachments-entitlements.md b/cadence/20231023-cadence-attachments-entitlements.md index 2b73bfb1..029034e6 100644 --- a/cadence/20231023-cadence-attachments-entitlements.md +++ b/cadence/20231023-cadence-attachments-entitlements.md @@ -1,5 +1,5 @@ --- -status: proposed +status: approved flip: 217 authors: Daniel Sainati (daniel.sainati@dapperlabs.com) sponsor: Daniel Sainati (daniel.sainati@dapperlabs.com)