diff --git a/docs/cadence/anti-patterns.mdx b/docs/cadence/anti-patterns.mdx index 91c5f1a75e..328e563c20 100644 --- a/docs/cadence/anti-patterns.mdx +++ b/docs/cadence/anti-patterns.mdx @@ -31,7 +31,7 @@ which provides the opportunity for bad actors to take advantage of. // They could deploy the contract with an Ethereum-style access control list functionality -pub fun transferNFT(id: UInt64, owner: AuthAccount) { +access(all) fun transferNFT(id: UInt64, owner: AuthAccount) { assert(owner(id) == owner.address) transfer(id) @@ -43,7 +43,7 @@ pub fun transferNFT(id: UInt64, owner: AuthAccount) { // should not be accessible in this function // BAD -pub fun transferNFT(id: UInt64, owner: AuthAccount) { +access(all) fun transferNFT(id: UInt64, owner: AuthAccount) { assert(owner(id) == owner.address) transfer(id) @@ -70,70 +70,6 @@ rather than inside contract utility functions. There are some scenarios where using an `AuthAccount` object is necessary, such as a cold storage multi-sig, but those cases are extremely rare and `AuthAccount` usage should still be avoided unless absolutely necessary. -## Auth references and capabilities should be avoided - -### Problem - -[Authorized references](./language/references.mdx) allow downcasting restricted -types to their unrestricted type and should be avoided unless necessary. -The type that is being restricted could expose functionality that was not intended to be exposed. -If the `auth` keyword is used on local variables they will be references. -References are ephemeral and cannot be stored. -This prevents any reference casting to be stored under account storage. -Additionally, if the `auth` keyword is used to store a public capability, serious harm -could happen since the value could be downcasted to a type -that has functionality and values altered. - -### Example - -A commonly seen pattern in NFT smart contracts is including a public borrow function -that borrows an auth reference to an NFT (eg. [NBA Top Shot](https://github.com/dapperlabs/nba-smart-contracts/blob/95fe72b7e94f43c9eff28412ce3642b69dcd8cd5/contracts/TopShot.cdc#L889-L906)). -This allows anyone to access the stored metadata or extra fields that weren't part -of the NFT standard. While generally safe in most scenarios, not all NFTs are built the same. -Some NFTs may have privileged functions that shouldn't be exposed by this method, -so please be cautious and mindful when imitating NFT projects that use this pattern. - -### Another Example - -When we create a public capability for our `FungibleToken.Vault` we do not use an auth capability: - -```cadence -// GOOD: Create a public capability to the Vault that only exposes -// the balance field through the Balance interface -signer.link<&FlowToken.Vault{FungibleToken.Balance}>( - /public/flowTokenBalance, - target: /storage/flowTokenVault -) -``` - -If we were to use an authorized type for the capability, like so: - -```cadence -// BAD: Create an Authorized public capability to the Vault that only exposes -// the balance field through the Balance interface -// Authorized referenced can be downcasted to their unrestricted types, which is dangerous -signer.link( - /public/flowTokenBalance, - target: /storage/flowTokenVault -) -``` - -Then anyone in the network could take that restricted reference -that is only supposed to expose the balance field and downcast it to expose the withdraw field -and steal all our money! - -```cadence -// Exploit of the auth capability to expose withdraw -let balanceRef = getAccount(account) - .getCapability(/public/flowTokenBalance) - .borrow()! - -let fullVaultRef = balanceRef as! &FlowToken.Vault - -// Withdraw the newly exposed funds -let stolenFunds <- fullVaultRef.withdraw(amount: 1000000) -``` - ## Events from resources may not be unique ### Problem @@ -201,9 +137,9 @@ if these fields are mistakenly made public. Ex: ```cadence -pub contract Array { +access(all) contract Array { // array is intended to be initialized to something constant - pub let shouldBeConstantArray: [Int] + access(all) let shouldBeConstantArray: [Int] } ``` @@ -225,7 +161,7 @@ Make sure that any array or dictionary fields in contracts, structs, or resource are `access(contract)` or `access(self)` unless they need to be intentionally made public. ```cadence -pub contract Array { +access(all) contract Array { // array is inteded to be initialized to something constant access(self) let shouldBeConstantArray: [Int] } @@ -252,14 +188,14 @@ The admin resource can then be `link()`ed to a private path in an admin's accoun // Pseudo-code // BAD -pub contract Currency { - pub resource Admin { - pub fun mintTokens() +access(all) contract Currency { + access(all) resource Admin { + access(all) fun mintTokens() } // Anyone in the network can call this function // And use the Admin resource to mint tokens - pub fun createAdmin(): @Admin { + access(all) fun createAdmin(): @Admin { return <-create Admin() } } @@ -267,12 +203,12 @@ pub contract Currency { // This contract makes the admin creation private and in the initializer // so that only the one who controls the account can mint tokens // GOOD -pub contract Currency { - pub resource Admin { - pub fun mintTokens() +access(all) contract Currency { + access(all) resource Admin { + access(all) fun mintTokens() // Only an admin can create new Admins - pub fun createAdmin(): @Admin { + access(all) fun createAdmin(): @Admin { return <-create Admin() } } @@ -300,7 +236,7 @@ which means that anyone can create a new instance of a struct without going thro ### Solution Any contract state-modifying operations related to the creation of structs -should be contained in restricted resources instead of the initializers of structs. +should be contained in resources instead of the initializers of structs. ### Example @@ -313,14 +249,14 @@ which increments the number that tracks the play IDs and emits an event: // Simplified Code // BAD // -pub contract TopShot { +access(all) contract TopShot { // The Record that is used to track every unique play ID - pub var nextPlayID: UInt32 + access(all) var nextPlayID: UInt32 - pub struct Play { + access(all) struct Play { - pub let playID: UInt32 + access(all) let playID: UInt32 init() { @@ -348,24 +284,24 @@ that creates the plays. // Update contract state in admin resource functions // GOOD // -pub contract TopShot { +access(all) contract TopShot { // The Record that is used to track every unique play ID - pub var nextPlayID: UInt32 + access(all) var nextPlayID: UInt32 - pub struct Play { + access(all) struct Play { - pub let playID: UInt32 + access(all) let playID: UInt32 init() { self.playID = TopShot.nextPlayID } } - pub resource Admin { + access(all) resource Admin { // Protected within the private admin resource - pub fun createPlay() { + access(all) fun createPlay() { // Create the new Play var newPlay = Play() diff --git a/docs/cadence/design-patterns.mdx b/docs/cadence/design-patterns.mdx index f22d48e9e9..6cb5c3cbe8 100644 --- a/docs/cadence/design-patterns.mdx +++ b/docs/cadence/design-patterns.mdx @@ -29,7 +29,7 @@ See [Wikipedia's page on magic numbers](https://en.wikipedia.org/wiki/Magic_numb ### Solution -Add a public (`pub`), constant (`let`) field, e.g. a `Path` , to the contract responsible for the value, +Add a public (`access(all)`), constant (`let`) field, e.g. a `Path` , to the contract responsible for the value, and set it in the contract's initializer. Refer to that value via this public field rather than specifying it manually. @@ -38,8 +38,8 @@ Example Snippet: ```cadence // BAD Practice: Do not hard code storage paths -pub contract NamedFields { - pub resource Test {} +access(all) contract NamedFields { + access(all) resource Test {} init() { // BAD: Hard-coded storage path @@ -49,11 +49,11 @@ pub contract NamedFields { // GOOD practice: Instead, use a field // -pub contract NamedFields { - pub resource Test {} +access(all) contract NamedFields { + access(all) resource Test {} // GOOD: field storage path - pub let TestStoragePath: StoragePath + access(all) let TestStoragePath: StoragePath init() { // assign and access the field here and in transactions @@ -81,7 +81,7 @@ Your contract, resource or struct has a field or resource that will need to be r Make sure that the field can be accessed from a script (using a `PublicAccount`) rather than requiring a transaction (using an `AuthAccount`). This saves the time and fees required to read a property using a transaction. -Making the field or function `pub` and exposing it via a `/public/` capability will allow this. +Making the field or function `access(all)` and exposing it via a `/public/` capability will allow this. Be careful not to expose any data or functionality that should be kept private when doing so. @@ -92,7 +92,7 @@ Example: access(self) let totalSupply: UFix64 // GOOD: Field is public, so it can be read and used by anyone -pub let totalSupply: UFix64 +access(all) let totalSupply: UFix64 ``` ## Script-Accessible report @@ -118,9 +118,9 @@ See [Script-Accessible public field/function](#script-accessible-public-fieldfun ### Example Code ```cadence -pub contract AContract { - pub let BResourceStoragePath: StoragePath - pub let BResourcePublicPath: PublicPath +access(all) contract AContract { + access(all) let BResourceStoragePath: StoragePath + access(all) let BResourcePublicPath: PublicPath init() { self.BResourceStoragePath = /storage/BResource @@ -128,15 +128,15 @@ pub contract AContract { } // Resource definition - pub resource BResource { - pub var c: UInt64 - pub var d: String + access(all) resource BResource { + access(all) var c: UInt64 + access(all) var d: String // Generate a struct with the same fields // to return when a script wants to see the fields of the resource // without having to return the actual resource - pub fun generateReport(): BReportStruct { + access(all) fun generateReport(): BReportStruct { return BReportStruct(c: self.c, d: self.d) } @@ -147,9 +147,9 @@ pub contract AContract { } // Define a struct with the same fields as the resource - pub struct BReportStruct { - pub var c: UInt64 - pub var d: String + access(all) struct BReportStruct { + access(all) var c: UInt64 + access(all) var d: String init(c: UInt64, d: String) { self.c = c @@ -172,7 +172,7 @@ transaction { import AContract from 0xAContract // Return the struct with a script -pub fun main(account: Address): AContract.BReportStruct { +access(all) fun main(account: Address): AContract.BReportStruct { // borrow the resource let b = getAccount(account) .getCapability(AContract.BResourcePublicPath) @@ -225,12 +225,12 @@ All fields, functions, types, variables, etc., need to have names that clearly d ```cadence // BAD: Unclear naming // -pub contract Tax { +access(all) contract Tax { // Do not use abbreviations unless absolutely necessary - pub var pcnt: UFix64 + access(all) var pcnt: UFix64 // Not clear what the function is calculating or what the parameter should be - pub fun calculate(num: UFix64): UFix64 { + access(all) fun calculate(num: UFix64): UFix64 { // What total is this referring to? let total = num + (num * self.pcnt) @@ -240,13 +240,13 @@ pub contract Tax { // GOOD: Clear naming // -pub contract TaxUtilities { +access(all) contract TaxUtilities { // Clearly states what the field is for - pub var taxPercentage: UFix64 + access(all) var taxPercentage: UFix64 // Clearly states that this function calculates the // total cost after tax - pub fun calculateTotalCostPlusTax(preTaxCost: UFix64): UFix64 { + access(all) fun calculateTotalCostPlusTax(preTaxCost: UFix64): UFix64 { let postTaxCost = preTaxCost + (preTaxCost * self.taxPercentage) return postTaxCost @@ -267,15 +267,11 @@ Therefore, it is important to be explicit when getting objects or references to ### Solution -A good example of when the code should specify the type being restricted is checking the FLOW balance: -The code must borrow `&FlowToken.Vault{FungibleToken.Balance}`, in order to ensure that it gets a FLOW token balance, +A good example of when the code should specify the type is checking the FLOW balance: +The code must borrow `&FlowToken.Vault`, in order to ensure that it gets a FLOW token balance, and not just `&{FungibleToken.Balance}`, any balance – the user could store another object that conforms to the balance interface and return whatever value as the amount. -When the developer does not care what the concrete type is, they should explicitly indicate that -by using `&AnyResource{Receiver}` instead of `&{Receiver}`. -In the latter case, `AnyResource` is implicit, but not as clear as the former case. - ## Plural names for arrays and maps are preferable e.g. `accounts` rather than `account` for an array of accounts. @@ -303,7 +299,7 @@ This could be used when purchasing an NFT to verify that the NFT was deposited i transaction { - pub let buyerCollectionRef: &NonFungibleToken.Collection + access(all) let buyerCollectionRef: &NonFungibleToken.Collection prepare(acct: AuthAccount) { @@ -426,7 +422,7 @@ and emits an `InboxValueUnpublished` event that the recipient can listen for off It is also important to note that the recipient becomes the owner of the capability object once they have claimed it, and can thus store it or copy it anywhere they have access to. This means providers should only publish capabilities to recipients they trust to use them properly, -or limit the type with which the capability is restricted in order to only give recipients access to the functionality +or limit the type with which the capability is authorized in order to only give recipients access to the functionality that the provider is willing to allow them to copy. ## Capability Revocation @@ -483,7 +479,7 @@ transaction { signer.unlink(/public/exampleTokenReceiver) } - signer.link<&ExampleToken.Vault{FungibleToken.Receiver}>( + signer.link<&ExampleToken.Vault>( /public/exampleTokenReceiver, target: /storage/exampleTokenVault ) diff --git a/docs/cadence/json-cadence-spec.md b/docs/cadence/json-cadence-spec.md index 70176f9377..5e059bbb86 100644 --- a/docs/cadence/json-cadence-spec.md +++ b/docs/cadence/json-cadence-spec.md @@ -729,14 +729,13 @@ Initializer types are encoded a list of parameters to the initializer. --- -## Restricted Types +## Intersection Types ```json { - "kind": "Restriction", + "kind": "Intersection", "typeID": "", - "type": , - "restrictions": [ + "types": [ , , //... diff --git a/docs/cadence/language/access-control.md b/docs/cadence/language/access-control.md index 7719ed8aaa..3dea6efd03 100644 --- a/docs/cadence/language/access-control.md +++ b/docs/cadence/language/access-control.md @@ -18,7 +18,7 @@ In Flow and Cadence, there are two types of access control: by providing references to the objects. 2. Access control within contracts and objects - using `pub` and `access` keywords. + using `access` keywords. For the explanations of the following keywords, we assume that the defining type is either a contract, where capability security @@ -34,10 +34,10 @@ and fields (in structures, and resources) are always only able to be written to and mutated (modified, such as by indexed assignment or methods like `append`) in the scope where it is defined (self). -There are four levels of access control defined in the code that specify where +There are five levels of access control defined in the code that specify where a declaration can be accessed or called. -- **Public** or **access(all)** means the declaration +- Public or **access(all)** means the declaration is accessible/visible in all scopes. This includes the current scope, inner scopes, and the outer scopes. @@ -47,7 +47,18 @@ a declaration can be accessed or called. This does not allow the declaration to be publicly writable though. An element is made publicly accessible / by any code - by using the `pub` or `access(all)` keywords. + by using the `access(all)` keyword. + +- Entitled access means the declaration is only accessible/visible + to the owner of the object, or to references that are authorized to the required entitlements. + + A reference is considered authorized to an entitlement if that entitlement appears in the `auth` portion of the reference type. + + For example, an `access(E, F)` field on a resource `R` can only be accessed by an owned (`@R`-typed) value, + or a reference to `R` that is authorized to the `E` and `F` entitlements (`auth(E, F) &R`). + + An element is made accessible by code in the same containing type + by using the `access(E)` syntax, described in more detail in the entitlements section below. - **access(account)** means the declaration is only accessible/visible in the scope of the entire account where it is defined. This means that @@ -76,30 +87,30 @@ a declaration can be accessed or called. **Access level must be specified for each declaration** -The `(set)` suffix can be used to make variables also publicly writable and mutable. - To summarize the behavior for variable declarations, constant declarations, and fields: -| Declaration kind | Access modifier | Read scope | Write scope | Mutate scope | -|:-----------------|:-------------------------|:-----------------------------------------------------|:------------------|:------------------| -| `let` | `priv` / `access(self)` | Current and inner | *None* | Current and inner | -| `let` | `access(contract)` | Current, inner, and containing contract | *None* | Current and inner | -| `let` | `access(account)` | Current, inner, and other contracts in same account | *None* | Current and inner | -| `let` | `pub`,`access(all)` | **All** | *None* | Current and inner | -| `var` | `access(self)` | Current and inner | Current and inner | Current and inner | -| `var` | `access(contract)` | Current, inner, and containing contract | Current and inner | Current and inner | -| `var` | `access(account)` | Current, inner, and other contracts in same account | Current and inner | Current and inner | -| `var` | `pub` / `access(all)` | **All** | Current and inner | Current and inner | -| `var` | `pub(set)` | **All** | **All** | **All** | +| Declaration kind | Access modifier | Read scope | Write scope | Mutate scope | +|:-----------------|:-------------------|:-----------------------------------------------------|:------------------|:------------------| +| `let` | `access(self)` | Current and inner | *None* | Current and inner | +| `let` | `access(contract)` | Current, inner, and containing contract | *None* | Current and inner | +| `let` | `access(account)` | Current, inner, and other contracts in same account | *None* | Current and inner | +| `let` | `access(all)` | **All** | *None* | Current and inner | +| `let` | `access(E)` | **All** with required entitlements | *None* | Current and inner | +| `var` | `access(self)` | Current and inner | Current and inner | Current and inner | +| `var` | `access(contract)` | Current, inner, and containing contract | Current and inner | Current and inner | +| `var` | `access(account)` | Current, inner, and other contracts in same account | Current and inner | Current and inner | +| `var` | `access(all)` | **All** | Current and inner | Current and inner | +| `var` | `access(E)` | **All** with required entitlements | Current and inner | Current and inner | To summarize the behavior for functions: -| Access modifier | Access scope | -|:-------------------------|:----------------------------------------------------| -| `priv` / `access(self)` | Current and inner | -| `access(contract)` | Current, inner, and containing contract | -| `access(account)` | Current, inner, and other contracts in same account | -| `pub` / `access(all)` | **All** | +| Access modifier | Access scope | +|:-------------------|:----------------------------------------------------| +| `access(self)` | Current and inner | +| `access(contract)` | Current, inner, and containing contract | +| `access(account)` | Current, inner, and other contracts in same account | +| `access(all)` | **All** | +| `access(E)` | **All** with required entitlements | Declarations of structures, resources, events, and [contracts](./contracts.mdx) can only be public. However, even though the declarations/types are publicly visible, @@ -112,13 +123,13 @@ access(self) let a = 1 // Declare a public constant, accessible/visible in all scopes. // -pub let b = 2 +access(all) let b = 2 ``` ```cadence // Declare a public struct, accessible/visible in all scopes. // -pub struct SomeStruct { +access(all) struct SomeStruct { // Declare a private constant field which is only readable // in the current and inner scopes. @@ -127,7 +138,7 @@ pub struct SomeStruct { // Declare a public constant field which is readable in all scopes. // - pub let b: Int + access(all) let b: Int // Declare a private variable field which is only readable // and writable in the current and inner scopes. @@ -138,16 +149,11 @@ pub struct SomeStruct { // so it is only writable in the current and inner scopes, // and readable in all scopes. // - pub var d: Int - - // Declare a public variable field which is settable, - // so it is readable and writable in all scopes. - // - pub(set) var e: Int + access(all) var d: Int // Arrays and dictionaries declared without (set) cannot be // mutated in external scopes - pub let arr: [Int] + access(all) let arr: [Int] // The initializer is omitted for brevity. @@ -160,7 +166,7 @@ pub struct SomeStruct { // Declare a public function which is callable in all scopes. // - pub fun privateTest() { + access(all) fun publicTest() { // ... } @@ -202,14 +208,6 @@ some.d // some.d = 4 -// Valid: can read publicly settable variable field in outer scope. -// -some.e - -// Valid: can set publicly settable variable field in outer scope. -// -some.e = 5 - // Invalid: cannot mutate a public field in outer scope. // some.f.append(0) @@ -221,3 +219,199 @@ some.f[3] = 1 // Valid: can call non-mutating methods on a public field in outer scope some.f.contains(0) ``` + +## Entitlements + +Entitlements are a unique feature of Cadence that provide granular access control to each member of a struct or resource. +Entitlements can be declared using the following syntax: + +```cadence +entitlement E +entitlement F +``` + +creates two entitlements called `E` and `F`. +Entitlements can be imported from other contracts and used the same way as other types. +If using entitlements defined in another contract, the same qualified name syntax is used as for other types: + +```cadence +contract C { + entitlement E +} +``` + +Outside of `C`, `E` is used with `C.E` syntax. +Entitlements exist in the same namespace as types, so if your contract defines a resource called `R`, +it will not be possible to define an entitlement that is also called `R`. + +Entitlements can be used in access modifiers on struct and resource members to specify which references to those composites +are allowed to access those members. +An access modifier can include more than one entitlement, joined with either an `|`, to indicate disjunction or "or", +or a `,`, to indicate conjunction or "and". So, for example: + +```cadence +access(all) resource SomeResource { + + // requires an `E` entitlement to read this field + access(E) let a: Int + + // requires either an `E` or an `F` entitlement to read this field + access(E | F) let b: Int + + // requires both an `E` and an `F` entitlement to read this field + access(E, F) let b: Int + + // intializers omitted for brevity + // ... +} +``` + +Given some values with the annotated types (details on how to create entitled references can be found [here](./references.mdx)): + +```cadence + +let r: @SomeResource = // ... +let refE: auth(E) &SomeResource = // ... +let refF: auth(F) &SomeResource = // ... +let refEF: auth(E, F) &SomeResource = // ... + +// valid, because `r` is owned and thus is "fully entitled" +r.a +// valid, because `r` is owned and thus is "fully entitled" +r.b +// valid, because `r` is owned and thus is "fully entitled" +r.c + +// valid, because `refE` has an `E` entitlement as required +refE.a +// valid, because `refE` has one of the two required entitlements +refE.b +// invalid, because `refE` only has one of the two required entitlements +refE.c + +// invalid, because `refF` has an `E` entitlement, not an `F` +refF.a +// valid, because `refF` has one of the two required entitlements +refF.b +// invalid, because `refF` only has one of the two required entitlements +refF.c + +// valid, because `refEF` has an `E` entitlement +refEF.a +// valid, because `refEF` has both of the two required entitlements +refEF.b +// valid, because `refEF` has both of the two required entitlements +refEF.c +``` + +Note particularly in this example how the owned value `r` can access all entitled members on `SomeResource`; +owned values are not affected by entitled declarations. + +### Entitlement Mappings + +When objects have fields that are child objects, +it can often be valuable to have different views of that reference depending on the entitlements one has on the reference to the parent object. +Consider the following example: + +```cadence +entitlement OuterEntitlement +entitlement SubEntitlement + +resource SubResource { + access(all) fun foo() { ... } + access(SubEntitlement) fun bar() { ... } +} + +resource OuterResource { + access(self) let childResource: @SubResource + + access(all) fun getPubRef(): &SubResource { + return &self.childResource as &SubResource + } + + access(OuterEntitlement) fun getEntitledRef(): auth(SubEntitlement) &SubResource { + return &self.childResource as auth(SubEntitlement) &SubResource + } + + init(r: @SubResource) { + self.childResource <- r + } +} +``` + +With this pattern, we can store a `SubResource` on an `OuterResource` value, +and create different ways to access that nested resource depending on the entitlement one posseses. +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`. + +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 statically how entitlements are propagated from parents to child objects in a nesting hierarchy. +So, the above example could be equivalently written as: + +```cadence +entitlement OuterEntitlement +entitlement SubEntitlement + +// specify a mapping for entitlements called `Map`, which defines a function +// from an input set of entitlements (called the domain) to an output set (called the range or the image) +entitlement mapping Map { + OuterEntitlement -> SubEntitlement +} + +resource SubResource { + access(all) fun foo() { ... } + access(SubEntitlement) fun bar() { ... } +} + +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. + access(Map) fun getRef(): auth(Map) &SubResource { + return &self.childResource as auth(Map) &SubResource + } + + init(r: @SubResource) { + self.childResource = r + } +} + +// given some value `r` of type `@OuterResource` +let pubRef = &r as &OuterResource +let pubSubRef = pubRef.getRef() // has type `&SubResource` + +let entitledRef = &r as auth(OuterEntitlement) &OuterResource +let entitledSubRef = entitledRef.getRef() // `OuterEntitlement` is defined to map to `SubEntitlement`, so this access yields a value of type `auth(SubEntitlement) &SubResource` +Entitlement + +// `r` is an owned value, and is thus considered "fully-entitled" to `OuterResource`, +// so this access yields a value authorized to the entire image of `Map`, in this case `SubEntitlement` +let alsoEntitledSubRef = r.getRef() +``` + +{/* TODO: Update once mappings can be used on regular composite fields */} + +Entitlement mappings may be used either in accessor functions (as in the example above), or in fields whose types are references. Note that this latter +usage will necessarily make the type of the composite non-storage, since it will have a reference field. + +{/* TODO: once the Account type refactor is complete and the documentation updated, let's link here to the Account type page as an example of more complex entitlement mappings */} +Entitlement mappings need not be 1:1; it is valid to define a mapping where multiple inputs map to the same output, or where one input maps to multiple outputs. + +Entitlement mappings preserve the "kind" of the set they are mapping; i.e. mapping an "and" set produces an "and" set, and mapping an "or" set produces an "or" set. +Because "and" and "or" separators cannot be combined in the same set, attempting to map "or"-separated sets through certain complex mappings may result in a type error. For example: + +``` +entitlement mapping M { + A -> B + A -> C + D -> E +} +``` + +attempting to map `(A | D)` through `M` will fail, since `A` should map to `(B, C)` and `D` should map to `E`, but these two outputs cannot be combined into a disjunctive set. \ No newline at end of file diff --git a/docs/cadence/language/accounts.mdx b/docs/cadence/language/accounts.mdx index 4c955c65e6..38fd314b6d 100644 --- a/docs/cadence/language/accounts.mdx +++ b/docs/cadence/language/accounts.mdx @@ -11,35 +11,34 @@ Every account can be accessed through two types, `PublicAccount` and `AuthAccoun which represents the publicly available portion of an account. ```cadence - -pub struct PublicAccount { +access(all) struct PublicAccount { /// The address of the account. - pub let address: Address + access(all) let address: Address /// The FLOW balance of the default vault of this account. - pub let balance: UFix64 + access(all) let balance: UFix64 /// The FLOW balance of the default vault of this account that is available to be moved. - pub let availableBalance: UFix64 + access(all) let availableBalance: UFix64 /// The current amount of storage used by the account in bytes. - pub let storageUsed: UInt64 + access(all) let storageUsed: UInt64 /// The storage capacity of the account in bytes. - pub let storageCapacity: UInt64 + access(all) let storageCapacity: UInt64 /// The contracts deployed to the account. - pub let contracts: PublicAccount.Contracts + access(all) let contracts: PublicAccount.Contracts /// The keys assigned to the account. - pub let keys: PublicAccount.Keys + access(all) let keys: PublicAccount.Keys /// The capabilities of the account. pub let capabilities: PublicAccount.Capabilities /// All public paths of this account. - pub let publicPaths: [PublicPath] + access(all) let publicPaths: [PublicPath] /// Iterate over all the public paths of an account. /// passing each path and type in turn to the provided callback function. @@ -52,41 +51,41 @@ pub struct PublicAccount { /// /// The order of iteration, as well as the behavior of adding or removing objects from storage during iteration, /// is undefined. - pub fun forEachPublic(_ function: fun(PublicPath, Type): Bool) + access(all) fun forEachPublic(_ function: fun(PublicPath, Type): Bool) - pub struct Contracts { + access(all) struct Contracts { /// The names of all contracts deployed in the account. - pub let names: [String] + access(all) let names: [String] /// Returns the deployed contract for the contract/contract interface with the given name in the account, if any. /// /// Returns nil if no contract/contract interface with the given name exists in the account. - pub fun get(name: String): DeployedContract? + access(all) fun get(name: String): DeployedContract? /// Returns a reference of the given type to the contract with the given name in the account, if any. /// /// Returns nil if no contract with the given name exists in the account, /// or if the contract does not conform to the given type. - pub fun borrow(name: String): T? + access(all) fun borrow(name: String): T? } - pub struct Keys { + access(all) struct Keys { /// Returns the key at the given index, if it exists, or nil otherwise. /// /// Revoked keys are always returned, but they have `isRevoked` field set to true. - pub fun get(keyIndex: Int): AccountKey? + access(all) fun get(keyIndex: Int): AccountKey? /// Iterate over all unrevoked keys in this account, /// passing each key in turn to the provided function. /// /// Iteration is stopped early if the function returns `false`. /// The order of iteration is undefined. - pub fun forEach(_ function: fun(AccountKey): Bool) + access(all) fun forEach(_ function: fun(AccountKey): Bool) /// The total number of unrevoked keys in this account. - pub let count: UInt64 + access(all) let count: UInt64 } pub struct Capabilities { @@ -122,44 +121,43 @@ For each signer of the transaction that signs as an authorizer, the correspondin to the `prepare` phase of the transaction. ```cadence - -pub struct AuthAccount { +access(all) struct AuthAccount { /// The address of the account. - pub let address: Address + access(all) let address: Address /// The FLOW balance of the default vault of this account. - pub let balance: UFix64 + access(all) let balance: UFix64 /// The FLOW balance of the default vault of this account that is available to be moved. - pub let availableBalance: UFix64 + access(all) let availableBalance: UFix64 /// The current amount of storage used by the account in bytes. - pub let storageUsed: UInt64 + access(all) let storageUsed: UInt64 /// The storage capacity of the account in bytes. - pub let storageCapacity: UInt64 + access(all) let storageCapacity: UInt64 /// The contracts deployed to the account. - pub let contracts: AuthAccount.Contracts + access(all) let contracts: AuthAccount.Contracts /// The keys assigned to the account. - pub let keys: AuthAccount.Keys + access(all) let keys: AuthAccount.Keys /// The inbox allows bootstrapping (sending and receiving) capabilities. - pub let inbox: AuthAccount.Inbox + access(all) let inbox: AuthAccount.Inbox /// The capabilities of the account. pub let capabilities: AuthAccount.Capabilities /// All public paths of this account. - pub let publicPaths: [PublicPath] + access(all) let publicPaths: [PublicPath] /// All private paths of this account. - pub let privatePaths: [PrivatePath] + access(all) let privatePaths: [PrivatePath] /// All storage paths of this account. - pub let storagePaths: [StoragePath] + access(all) let storagePaths: [StoragePath] /// Saves the given object into the account's storage at the given path. /// @@ -168,7 +166,7 @@ pub struct AuthAccount { /// If there is already an object stored under the given path, the program aborts. /// /// The path must be a storage path, i.e., only the domain `storage` is allowed. - pub fun save(_ value: T, to: StoragePath) + access(all) fun save(_ value: T, to: StoragePath) /// Reads the type of an object from the account's storage which is stored under the given path, /// or nil if no object is stored under the given path. @@ -176,7 +174,7 @@ pub struct AuthAccount { /// If there is an object stored, the type of the object is returned without modifying the stored object. /// /// The path must be a storage path, i.e., only the domain `storage` is allowed. - pub fun type(at: StoragePath): Type? + access(all) fun type(at: StoragePath): Type? /// Loads an object from the account's storage which is stored under the given path, /// or nil if no object is stored under the given path. @@ -192,7 +190,7 @@ pub struct AuthAccount { /// The given type must not necessarily be exactly the same as the type of the loaded object. /// /// The path must be a storage path, i.e., only the domain `storage` is allowed. - pub fun load(from: StoragePath): T? + access(all) fun load(from: StoragePath): T? /// Returns a copy of a structure stored in account storage under the given path, /// without removing it from storage, @@ -207,7 +205,7 @@ pub struct AuthAccount { /// The given type must not necessarily be exactly the same as the type of the copied structure. /// /// The path must be a storage path, i.e., only the domain `storage` is allowed. - pub fun copy(from: StoragePath): T? + access(all) fun copy(from: StoragePath): T? /// Returns a reference to an object in storage without removing it from storage. /// @@ -219,7 +217,7 @@ pub struct AuthAccount { /// The given type must not necessarily be exactly the same as the type of the borrowed object. /// /// The path must be a storage path, i.e., only the domain `storage` is allowed - pub fun borrow(from: StoragePath): T? + access(all) fun borrow(from: StoragePath): T? /// Returns true if the object in account storage under the given path satisfies the given type, /// i.e. could be borrowed using the given type. @@ -227,7 +225,7 @@ pub struct AuthAccount { /// The given type must not necessarily be exactly the same as the type of the borrowed object. /// /// The path must be a storage path, i.e., only the domain `storage` is allowed. - pub fun check(from: StoragePath): Bool + access(all) fun check(from: StoragePath): Bool /// Iterate over all the public paths of an account, /// passing each path and type in turn to the provided callback function. @@ -245,7 +243,7 @@ pub struct AuthAccount { /// then the callback must stop iteration by returning false. /// Otherwise, iteration aborts. /// - pub fun forEachPublic(_ function: fun(PublicPath, Type): Bool) + access(all) fun forEachPublic(_ function: fun(PublicPath, Type): Bool) /// Iterate over all the private paths of an account, /// passing each path and type in turn to the provided callback function. @@ -262,7 +260,7 @@ pub struct AuthAccount { /// or an existing object is removed from a private path, /// then the callback must stop iteration by returning false. /// Otherwise, iteration aborts. - pub fun forEachPrivate(_ function: fun(PrivatePath, Type): Bool) + access(all) fun forEachPrivate(_ function: fun(PrivatePath, Type): Bool) /// Iterate over all the stored paths of an account, /// passing each path and type in turn to the provided callback function. @@ -277,12 +275,12 @@ pub struct AuthAccount { /// or an existing object is removed from a storage path, /// then the callback must stop iteration by returning false. /// Otherwise, iteration aborts. - pub fun forEachStored(_ function: fun(StoragePath, Type): Bool) + access(all) fun forEachStored(_ function: fun(StoragePath, Type): Bool) - pub struct Contracts { + access(all) struct Contracts { /// The names of all contracts deployed in the account. - pub let names: [String] + access(all) let names: [String] /// Adds the given contract to the account. /// @@ -298,7 +296,7 @@ pub struct AuthAccount { /// or if the given name does not match the name of the contract/contract interface declaration in the code. /// /// Returns the deployed contract. - pub fun add( + access(all) fun add( name: String, code: [UInt8] ): DeployedContract @@ -319,33 +317,33 @@ pub struct AuthAccount { /// or if the given name does not match the name of the contract/contract interface declaration in the code. /// /// Returns the deployed contract for the updated contract. - pub fun update__experimental(name: String, code: [UInt8]): DeployedContract + access(all) fun update__experimental(name: String, code: [UInt8]): DeployedContract /// Returns the deployed contract for the contract/contract interface with the given name in the account, if any. /// /// Returns nil if no contract/contract interface with the given name exists in the account. - pub fun get(name: String): DeployedContract? + access(all) fun get(name: String): DeployedContract? /// Removes the contract/contract interface from the account which has the given name, if any. /// /// Returns the removed deployed contract, if any. /// /// Returns nil if no contract/contract interface with the given name exists in the account. - pub fun remove(name: String): DeployedContract? + access(all) fun remove(name: String): DeployedContract? /// Returns a reference of the given type to the contract with the given name in the account, if any. /// /// Returns nil if no contract with the given name exists in the account, /// or if the contract does not conform to the given type. - pub fun borrow(name: String): T? + access(all) fun borrow(name: String): T? } - pub struct Keys { + access(all) struct Keys { /// Adds a new key with the given hashing algorithm and a weight. /// /// Returns the added key. - pub fun add( + access(all) fun add( publicKey: PublicKey, hashAlgorithm: HashAlgorithm, weight: UFix64 @@ -354,12 +352,12 @@ pub struct AuthAccount { /// Returns the key at the given index, if it exists, or nil otherwise. /// /// Revoked keys are always returned, but they have `isRevoked` field set to true. - pub fun get(keyIndex: Int): AccountKey? + access(all) fun get(keyIndex: Int): AccountKey? /// Marks the key at the given index revoked, but does not delete it. /// /// Returns the revoked key if it exists, or nil otherwise. - pub fun revoke(keyIndex: Int): AccountKey? + access(all) fun revoke(keyIndex: Int): AccountKey? /// Iterate over all unrevoked keys in this account, /// passing each key in turn to the provided function. @@ -367,24 +365,24 @@ pub struct AuthAccount { /// Iteration is stopped early if the function returns `false`. /// /// The order of iteration is undefined. - pub fun forEach(_ function: fun(AccountKey): Bool) + access(all) fun forEach(_ function: fun(AccountKey): Bool) /// The total number of unrevoked keys in this account. - pub let count: UInt64 + access(all) let count: UInt64 } - pub struct Inbox { + access(all) struct Inbox { /// Publishes a new Capability under the given name, /// to be claimed by the specified recipient. - pub fun publish(_ value: Capability, name: String, recipient: Address) + access(all) fun publish(_ value: Capability, name: String, recipient: Address) /// Unpublishes a Capability previously published by this account. /// /// Returns `nil` if no Capability is published under the given name. /// /// Errors if the Capability under that name does not match the provided type. - pub fun unpublish(_ name: String): Capability? + access(all) fun unpublish(_ name: String): Capability? /// Claims a Capability previously published by the specified provider. /// @@ -392,7 +390,7 @@ pub struct AuthAccount { /// or if this account is not its intended recipient. /// /// Errors if the Capability under that name does not match the provided type. - pub fun claim(_ name: String, provider: Address): Capability? + access(all) fun claim(_ name: String, provider: Address): Capability? } pub struct Capabilities { @@ -474,7 +472,7 @@ pub struct AuthAccount { pub fun forEachController(_ function: (&AccountCapabilityController): Bool) /// Issue/create a new account capability. - pub fun issue(): Capability + pub fun issue(): Capability } } ``` @@ -813,9 +811,9 @@ The path must be a storage path, i.e., only the domain `storage` is allowed. // Declare a resource named `Counter`. // resource Counter { - pub var count: Int + access(all) var count: Int - pub init(count: Int) { + access(all) init(count: Int) { self.count = count } } @@ -925,9 +923,9 @@ resource interface HasCount { // Declare a resource named `Counter` that conforms to `HasCount` // resource Counter: HasCount { - pub var count: Int + access(all) var count: Int - pub init(count: Int) { + access(all) init(count: Int) { self.count = count } } @@ -960,7 +958,7 @@ counterRef?.count // is `42` // // `hasCountRef` is non-`nil`, as there is an object stored under path `/storage/counter`, // and the stored value of type `Counter` conforms to the requested type `{HasCount}`: -// the type `Counter` implements the restricted type's restriction `HasCount` +// the type `Counter` implements the intersection type's interface `HasCount` let hasCountRef = authAccount.borrow<&{HasCount}>(from: /storage/counter) @@ -969,7 +967,7 @@ let hasCountRef = authAccount.borrow<&{HasCount}>(from: /storage/counter) // // `otherRef` is `nil`, as there is an object stored under path `/storage/counter`, // but the stored value of type `Counter` does not conform to the requested type `{Other}`: -// the type `Counter` does not implement the restricted type's restriction `Other` +// the type `Counter` does not implement the intersection type's interface `Other` let otherRef = authAccount.borrow<&{Other}>(from: /storage/counter) diff --git a/docs/cadence/language/attachments.mdx b/docs/cadence/language/attachments.mdx index e4fb948585..e819898dd5 100644 --- a/docs/cadence/language/attachments.mdx +++ b/docs/cadence/language/attachments.mdx @@ -14,11 +14,11 @@ without requiring the original author of the type to plan or account for the int ## Declaring Attachments Attachments are declared with the `attachment` keyword, which would be declared using a new form of composite declaration: -`pub attachment for : { ... }`, where the attachment functions and fields are declared in the body. +`attachment for : { ... }`, where the attachment functions and fields are declared in the body. As such, the following would be examples of legal declarations of attachments: ```cadence -pub attachment Foo for MyStruct { +access(all) attachment Foo for MyStruct { // ... } @@ -36,7 +36,14 @@ Note that the base type may be either a concrete composite type or an interface. In the former case, the attachment is only usable on values specifically of that base type, while in the case of an interface the attachment is usable on any type that conforms to that interface. -As with other type declarations, attachments may only have a `pub` access modifier (if one is present). +Unlike other type declarations, attachments may use either an `access(all)` access modifier, or an `access(M)` modifier, +where `M` is the name of an entitlement mapping. +When attachments are defined with an `access(all)` modifier, +members on the attachment may not use any entitlements in their access modifiers, +and any references to that attachment are always unauthorized. +When attachments are defined with an an [entitlement mapping](./access-control.md), +members on the attachments may use any entitlements in the range of that mapping, +and any references to that attachments will have their authorization depend on the entitlements present on the base type on which they are accessed. The body of the attachment follows the same declaration rules as composites. In particular, they may have both field and function members, @@ -46,6 +53,8 @@ and such members must be explicitly handled in the `destroy` function. The `self` keyword is available in attachment bodies, but unlike in a composite, `self` is a **reference** type, rather than a composite type: In an attachment declaration for `A`, the type of `self` would be `&A`, rather than `A` like in other composite declarations. +If the attachment declaration uses an `access(all)` access modifier, the `self` reference is always unauthorized, +whereas if it uses an `access(M)` access modifier, the `self` reference is fully-entitled to the range of `M`. If a resource with attachments on it is `destroy`ed, the `destroy` functions of all its attachments are all run in an unspecified order; `destroy` should not rely on the presence of other attachments on the base type in its implementation. @@ -55,29 +64,29 @@ Within the body of an attachment, there is also a `base` keyword available, which contains a reference to the attachment's base value; that is, the composite to which the attachment is attached. Its type, therefore, is a reference to the attachment's declared base type. -So, for an attachment declared `pub attachment Foo for Bar`, the `base` field of `Foo` would have type `&Bar`. +So, for an attachment declared `access(all) attachment Foo for Bar`, the `base` field of `Foo` would have type `&Bar`. So, for example, this would be a valid declaration of an attachment: ``` -pub resource R { - pub let x: Int +access(all) resource R { + access(all) let x: Int init (_ x: Int) { self.x = x } - pub fun foo() { ... } + access(all) fun foo() { ... } } -pub attachment A for R { - pub let derivedX: Int +access(all) attachment A for R { + access(all) let derivedX: Int init (_ scalar: Int) { self.derivedX = base.x * scalar } - pub fun foo() { + access(all) fun foo() { base.foo() } } @@ -86,18 +95,18 @@ pub attachment A for R { For the purposes of external mutation checks or [access control](./access-control.md), the attachment is considered a separate declaration from its base type. -A developer cannot, therefore, access any `priv` fields +A developer cannot, therefore, access any `access(self)` fields (or `access(contract)` fields if the base was defined in a different contract to the attachment) on the `base` value, nor can they mutate any array or dictionary typed fields. ```cadence -pub resource interface SomeInterface { - pub let b: Bool - priv let i: Int - pub let a: [String] +access(all) resource interface SomeInterface { + access(all) let b: Bool + access(self) let i: Int + access(all) let a: [String] } -pub attachment SomeAttachment for SomeContract.SomeStruct { - pub let i: Int +access(all) attachment SomeAttachment for SomeContract.SomeStruct { + access(all) let i: Int init(i: Int) { if base.b { self.i = base.i // cannot access `i` on the `base` value @@ -105,15 +114,42 @@ pub attachment SomeAttachment for SomeContract.SomeStruct { self.i = i } } - pub fun foo() { + access(all) fun foo() { base.a.append("hello") // cannot mutate `a` outside of the composite where it was defined } } ``` +By default, the `base` reference is unauthorized, and thus entitled-access members on the base type are inaccessible in the attachment. +If the author of the attachment wishes to have access to entitled-access members on the base type, +they must declare that their attachment requires certain entitlements to the base, using `require entitlement E` syntax. +Required entitlements must be valid entitlements for the base type, +and requiring entitlements in the attachment declaration will impose additional requirements when the attachment is attached, +as described below. So, for example: + +```cadence +entitlement mapping M { + E -> F +} + +resource R { + access(E) fun foo() { + //... + } +} + +access(M) attachment A for R { + require entitlement E + + access(all) fun bar() { + base.foo() // available because `E` is required above, and thus `base` is type `auth(E) &R`. + } +} +``` + ### Attachment Types -An attachment declared with `pub attachment A for C { ... }` will have a nominal type `A`. +An attachment declared with `access(all) attachment A for C { ... }` will have a nominal type `A`. It is important to note that attachments are not first class values in Cadence, and as such their usage is limited in certain ways. In particular, their types cannot appear outside of a reference type. @@ -135,8 +171,8 @@ the `to` keyword, and an expression that evaluates to the base value for that at Any arguments required by the attachment's `init` function are provided in its constructor call. ```cadence -pub resource R {} -pub attachment A for R { +access(all) resource R {} +access(all) attachment A for R { init(x: Int) { //... } @@ -155,9 +191,9 @@ but it is important to note that the attachment being created will not be access ```cadence -pub resource interface I {} -pub resource R: I {} -pub attachment A for I {} +access(all) resource interface I {} +access(all) resource R: I {} +access(all) attachment A for I {} // ... let r <- create R() // has type @R @@ -169,6 +205,14 @@ Cadence will raise a runtime error if a user attempts to add an attachment to a The type returned by the `attach` expression is the same type as the expression on the right-hand side of the `to`; attaching an attachment to a value does not change its type. +If an attachment has required entitlements to its base, those entitlements must be explicitly provided in the `attach` expression +using an additional `with` syntax. So, for example, if an attachment `A` declared for `R` requires entitlements `E` and `F`, it can +be attached to an `r` of type `@R` like so: + +```cadence +let rWithA <- attach A() to <-r with (E, F) +``` + ## Accessing Attachments Attachments are accessed on composites via type-indexing: @@ -186,7 +230,7 @@ so this indexing returns a reference to the attachment on `v`, rather than the a If the attachment with the given type does not exist on `v`, this expression returns `nil`. Because the indexed value must be a subtype of the indexing attachment's base type, -the owner of a resource can restrict which attachments can be accessed on references to their resource using restricted types, +the owner of a resource can restrict which attachments can be accessed on references to their resource using interface types, much like they would do with any other field or function. E.g. ```cadence @@ -201,6 +245,31 @@ fun foo(r: &{I}) { Hence, if the owner of a resource wishes to allow others to use a subset of its attachments, they can create a capability to that resource with a borrow type that only allows certain attachments to be accessed. +If an attachment is declared with an `access(all)` modifier, +accessing one this way will always produce an unauthorized reference to the attachment. +However, if the attachment is declared with an `access(M)` modifier, where `M` is some entitlement mapping, +then the authorization of the resulting reference will depend on the authorization of the accessed value. + +So, for example, given a declaration + +```cadence +entitlement E +entitlement F +entitlement G +entitlement H +entitlement mapping M { + E -> F + G -> H +} +resource R {} +access(M) attachment A for R {} +``` + +when `A` is accessed on an owned value of type `@R`, it will be fully-authorized to the domain of `M`, +having a type of `auth(F, H) &A`. +However, if `A` is accessed on an `auth(E) &R` reference, then it will only have a `auth(F) &A` type. +If `A` is accessed on an unauthorized `&R` reference, then it will yield an unauthorized `&A` type. + ## Removing Attachments Attachments can be removed from a value with a `remove` statement. diff --git a/docs/cadence/language/capability-based-access-control.md b/docs/cadence/language/capability-based-access-control.md index 8f4da8c592..914b81bdee 100644 --- a/docs/cadence/language/capability-based-access-control.md +++ b/docs/cadence/language/capability-based-access-control.md @@ -140,24 +140,32 @@ This can be done using the `borrow` function of the capability: execution will abort with an error. ```cadence +entitlement Reset + // Declare a resource interface named `HasCount`, that has a field `count` +// and a `resetCount` function requiring a `Reset` entitlement // resource interface HasCount { count: Int + access(Reset) fun resetCount() } // Declare a resource named `Counter` that conforms to `HasCount` // resource Counter: HasCount { - pub var count: Int + access(all) var count: Int - pub init(count: Int) { + access(all) init(count: Int) { self.count = count } - pub fun increment(by amount: Int) { + access(all) fun increment(by amount: Int) { self.count = self.count + amount } + + access(Reset) fun resetCount() { + self.count = 0 + } } // In this example an authorized account is available through the constant `authAccount`. @@ -221,22 +229,19 @@ countRef.count // is `42` // countRef.increment(by: 5) -// Again, attempt to get a get a capability for the counter, but use the type `&Counter`. +// Again, attempt to get a get a capability for the counter, but use the type `auth(Reset) &{HasCount}`. // // Getting the capability succeeds, because it is latent, but borrowing fails // (the result s `nil`), because the capability was created/linked using the type `&{HasCount}`: // -// The resource type `Counter` implements the resource interface `HasCount`, -// so `Counter` is a subtype of `{HasCount}`, but the capability only allows -// borrowing using unauthorized references of `{HasCount}` (`&{HasCount}`) -// instead of authorized references (`auth &{HasCount}`), -// so users of the capability are not allowed to borrow using subtypes, -// and they can't escalate the type by casting the reference either. +// Because the stored capability is not authorized to the `Reset` entitlement, it cannot +// be borrowed with that type, and thus only the functions on `HasCount` that do not require +// an entitlement are available to this capability. // // This shows how parts of the functionality of stored objects // can be safely exposed to other code // -let countCapNew = publicAccount.getCapability<&Counter>(/public/hasCount) +let countCapNew = publicAccount.getCapability(/public/hasCount) let counterRefNew = countCapNew.borrow() // `counterRefNew` is `nil`, the borrow failed diff --git a/docs/cadence/language/composite-types.mdx b/docs/cadence/language/composite-types.mdx index b32eb5bc0c..7718ba9c7a 100644 --- a/docs/cadence/language/composite-types.mdx +++ b/docs/cadence/language/composite-types.mdx @@ -57,11 +57,11 @@ and resources are declared using the `resource` keyword. The keyword is followed by the name. ```cadence -pub struct SomeStruct { +access(all) struct SomeStruct { // ... } -pub resource SomeResource { +access(all) resource SomeResource { // ... } ``` @@ -156,14 +156,14 @@ and the name of the field. // // Both fields are initialized through the initializer. // -// The public access modifier `pub` is used in this example to allow +// The public access modifier `access(all)` is used in this example to allow // the fields to be read in outer scopes. Fields can also be declared // private so they cannot be accessed in outer scopes. // Access control will be explained in a later section. // -pub struct Token { - pub let id: Int - pub var balance: Int +access(all) struct Token { + access(all) let id: Int + access(all) var balance: Int init(id: Int, balance: Int) { self.id = id @@ -175,19 +175,19 @@ pub struct Token { Note that it is invalid to provide the initial value for a field in the field declaration. ```cadence -pub struct StructureWithConstantField { +access(all) struct StructureWithConstantField { // Invalid: It is invalid to provide an initial value in the field declaration. // The field must be initialized by setting the initial value in the initializer. // - pub let id: Int = 1 + access(all) let id: Int = 1 } ``` The field access syntax must be used to access fields – fields are not available as variables. ```cadence -pub struct Token { - pub let id: Int +access(all) struct Token { + access(all) let id: Int init(initialID: Int) { // Invalid: There is no variable with the name `id` available. @@ -201,8 +201,8 @@ pub struct Token { The initializer is **not** automatically derived from the fields, it must be explicitly declared. ```cadence -pub struct Token { - pub let id: Int +access(all) struct Token { + access(all) let id: Int // Invalid: Missing initializer initializing field `id`. } @@ -235,9 +235,9 @@ In an initializer, writes to `self` are considered `view` (unlike within other c as the value being constructed here is by definition local to the context calling the initializer. ```cadence -pub struct Token { - pub let id: Int - pub var balance: Int +access(all) struct Token { + access(all) let id: Int + access(all) var balance: Int view init(id: Int, balance: Int) { self.id = id @@ -256,9 +256,9 @@ that the function is called on. // Declare a structure named "Rectangle", which represents a rectangle // and has variable fields for the width and height. // -pub struct Rectangle { - pub var width: Int - pub var height: Int +access(all) struct Rectangle { + access(all) var width: Int + access(all) var height: Int init(width: Int, height: Int) { self.width = width @@ -268,7 +268,7 @@ pub struct Rectangle { // Declare a function named "scale", which scales // the rectangle by the given factor. // - pub fun scale(factor: Int) { + access(all) fun scale(factor: Int) { self.width = self.width * factor self.height = self.height * factor } @@ -336,8 +336,8 @@ Accessing a field or calling a function of a structure does not copy it. ```cadence // Declare a structure named `SomeStruct`, with a variable integer field. // -pub struct SomeStruct { - pub var value: Int +access(all) struct SomeStruct { + access(all) var value: Int init(value: Int) { self.value = value @@ -386,18 +386,18 @@ of an optional composite type. ```cadence // Declare a struct with a field and method. -pub struct Value { - pub var number: Int +access(all) struct Value { + access(all) var number: Int init() { self.number = 2 } - pub fun set(new: Int) { + access(all) fun set(new: Int) { self.number = new } - pub fun setAndReturn(new: Int): Int { + access(all) fun setAndReturn(new: Int): Int { self.number = new return new } @@ -449,18 +449,18 @@ of an optional composite type. ```cadence // Declare a struct with a field and method. -pub struct Value { - pub var number: Int +access(all) struct Value { + access(all) var number: Int init() { self.number = 2 } - pub fun set(new: Int) { + access(all) fun set(new: Int) { self.number = new } - pub fun setAndReturn(new: Int): Int { + access(all) fun setAndReturn(new: Int): Int { self.number = new return new } diff --git a/docs/cadence/language/contract-updatability.md b/docs/cadence/language/contract-updatability.md index bb5addf41c..614fbf7cbc 100644 --- a/docs/cadence/language/contract-updatability.md +++ b/docs/cadence/language/contract-updatability.md @@ -74,16 +74,16 @@ A field may belong to a contract, struct, resource, or interface. ```cadence // Existing contract - pub contract Foo { - pub var a: String - pub var b: Int + access(all) contract Foo { + access(all) var a: String + access(all) var b: Int } // Updated contract - pub contract Foo { - pub var a: String + access(all) contract Foo { + access(all) var a: String } ``` - It leaves data for the removed field unused at the storage, as it is no longer accessible. @@ -93,17 +93,17 @@ A field may belong to a contract, struct, resource, or interface. ```cadence // Existing contract - pub contract Foo { - pub var a: String - pub var b: Int + access(all) contract Foo { + access(all) var a: String + access(all) var b: Int } // Updated contract - pub contract Foo { - pub var b: Int - pub var a: String + access(all) contract Foo { + access(all) var b: Int + access(all) var a: String } ``` @@ -111,15 +111,15 @@ A field may belong to a contract, struct, resource, or interface. ```cadence // Existing contract - pub contract Foo { - pub var a: String + access(all) contract Foo { + access(all) var a: String } // Updated contract - pub contract Foo { - priv var a: String // access modifier changed to 'priv' + access(all) contract Foo { + access(self) var a: String // access modifier changed to 'access(self)' } ``` @@ -128,16 +128,16 @@ A field may belong to a contract, struct, resource, or interface. ```cadence // Existing contract - pub contract Foo { - pub var a: String + access(all) contract Foo { + access(all) var a: String } // Updated contract - pub contract Foo { - pub var a: String - pub var b: Int // Invalid new field + access(all) contract Foo { + access(all) var a: String + access(all) var b: Int // Invalid new field } ``` - Initializer of a contract only run once, when the contract is deployed for the first time. It does not rerun @@ -150,15 +150,15 @@ A field may belong to a contract, struct, resource, or interface. ```cadence // Existing contract - pub contract Foo { - pub var a: String + access(all) contract Foo { + access(all) var a: String } // Updated contract - pub contract Foo { - pub var a: Int // Invalid type change + access(all) contract Foo { + access(all) var a: Int // Invalid type change } ``` - In an already stored contract, the field `a` would have a value of type `String`. @@ -180,13 +180,13 @@ A field may belong to a contract, struct, resource, or interface. ```cadence // Existing struct - pub struct Foo { + access(all) struct Foo { } // Upated struct - pub struct Foo: T { + access(all) struct Foo: T { } ``` - However, if adding a conformance also requires changing the existing structure (e.g: adding a new field that is @@ -203,26 +203,26 @@ A field may belong to a contract, struct, resource, or interface. ```cadence // Existing struct - pub struct Foo { + access(all) struct Foo { } // Changed to a struct interface - pub struct interface Foo { // Invalid type declaration change + access(all) struct interface Foo { // Invalid type declaration change } ``` - Removing an interface conformance of a struct/resource is not valid. ```cadence // Existing struct - pub struct Foo: T { + access(all) struct Foo: T { } // Upated struct - pub struct Foo { + access(all) struct Foo { } ``` @@ -253,17 +253,17 @@ Below sections describes the restrictions imposed on updating the members of a s ```cadence // Existing enum with `Int` raw type - pub enum Color: Int { - pub case RED - pub case BLUE + access(all) enum Color: Int { + access(all) case RED + access(all) case BLUE } // Updated enum with `UInt8` raw type - pub enum Color: UInt8 { // Invalid change of raw type - pub case RED - pub case BLUE + access(all) enum Color: UInt8 { // Invalid change of raw type + access(all) case RED + access(all) case BLUE } ``` - When the enum value is stored, the raw value associated with the enum-case gets stored. @@ -282,18 +282,18 @@ it originally was (type confusion). ```cadence // Existing enum - pub enum Color: Int { - pub case RED - pub case BLUE + access(all) enum Color: Int { + access(all) case RED + access(all) case BLUE } // Updated enum - pub enum Color: Int { - pub case RED - pub case BLUE - pub case GREEN // valid new enum-case at the bottom + access(all) enum Color: Int { + access(all) case RED + access(all) case BLUE + access(all) case GREEN // valid new enum-case at the bottom } ``` #### Invalid Changes @@ -301,35 +301,35 @@ it originally was (type confusion). ```cadence // Existing enum - pub enum Color: Int { - pub case RED - pub case BLUE + access(all) enum Color: Int { + access(all) case RED + access(all) case BLUE } // Updated enum - pub enum Color: Int { - pub case RED - pub case GREEN // invalid new enum-case in the middle - pub case BLUE + access(all) enum Color: Int { + access(all) case RED + access(all) case GREEN // invalid new enum-case in the middle + access(all) case BLUE } ``` - Changing the name of an enum-case is invalid. ```cadence // Existing enum - pub enum Color: Int { - pub case RED - pub case BLUE + access(all) enum Color: Int { + access(all) case RED + access(all) case BLUE } // Updated enum - pub enum Color: Int { - pub case RED - pub case GREEN // invalid change of names + access(all) enum Color: Int { + access(all) case RED + access(all) case GREEN // invalid change of names } ``` - Previously stored raw values for `Color.BLUE` now represents `Color.GREEN`. i.e: The stored values have changed @@ -342,16 +342,16 @@ it originally was (type confusion). ```cadence // Existing enum - pub enum Color: Int { - pub case RED - pub case BLUE + access(all) enum Color: Int { + access(all) case RED + access(all) case BLUE } // Updated enum - pub enum Color: Int { - pub case RED + access(all) enum Color: Int { + access(all) case RED // invalid removal of `case BLUE` } @@ -360,17 +360,17 @@ it originally was (type confusion). ```cadence // Existing enum - pub enum Color: Int { - pub case RED - pub case BLUE + access(all) enum Color: Int { + access(all) case RED + access(all) case BLUE } // Updated enum - pub enum Color: UInt8 { - pub case BLUE // invalid change of order - pub case RED + access(all) enum Color: UInt8 { + access(all) case BLUE // invalid change of order + access(all) case RED } ``` - Raw value of an enum is implicit, and corresponds to the defined order. diff --git a/docs/cadence/language/contracts.mdx b/docs/cadence/language/contracts.mdx index 5c8beeded0..7d9faa4ad7 100644 --- a/docs/cadence/language/contracts.mdx +++ b/docs/cadence/language/contracts.mdx @@ -28,7 +28,7 @@ Contracts are declared using the `contract` keyword. The keyword is followed by the name of the contract. ```cadence -pub contract SomeContract { +access(all) contract SomeContract { // ... } ``` @@ -36,11 +36,11 @@ pub contract SomeContract { Contracts cannot be nested in each other. ```cadence -pub contract Invalid { +access(all) contract Invalid { // Invalid: Contracts cannot be nested in any other type. // - pub contract Nested { + access(all) contract Nested { // ... } } @@ -50,16 +50,16 @@ One of the simplest forms of a contract would just be one with a state field, a function, and an `init` function that initializes the field: ```cadence -pub contract HelloWorld { +access(all) contract HelloWorld { // Declare a stored state field in HelloWorld // - pub let greeting: String + access(all) let greeting: String // Declare a function that can be called by anyone // who imports the contract // - pub fun hello(): String { + access(all) fun hello(): String { return self.greeting } @@ -110,9 +110,9 @@ but they have to be in the contract and not another top-level definition. // if they were deployed to the account contract storage and // the deployment would be rejected. // -pub resource Vault {} -pub struct Hat {} -pub fun helloWorld(): String {} +access(all) resource Vault {} +access(all) struct Hat {} +access(all) fun helloWorld(): String {} let num: Int ``` @@ -128,13 +128,13 @@ there is no way to create this resource, so it would not be usable. ```cadence // Valid -pub contract FungibleToken { +access(all) contract FungibleToken { - pub resource interface Receiver { + access(all) resource interface Receiver { - pub balance: Int + access(all) balance: Int - pub fun deposit(from: @{Receiver}) { + access(all) fun deposit(from: @{Receiver}) { pre { from.balance > 0: "Deposit balance needs to be positive!" @@ -146,10 +146,10 @@ pub contract FungibleToken { } } - pub resource Vault: Receiver { + access(all) resource Vault: Receiver { // keeps track of the total balance of the accounts tokens - pub var balance: Int + access(all) var balance: Int init(balance: Int) { self.balance = balance @@ -157,7 +157,7 @@ pub contract FungibleToken { // withdraw subtracts amount from the vaults balance and // returns a vault object with the subtracted balance - pub fun withdraw(amount: Int): @Vault { + access(all) fun withdraw(amount: Int): @Vault { self.balance = self.balance - amount return <-create Vault(balance: amount) } @@ -165,7 +165,7 @@ pub contract FungibleToken { // deposit takes a vault object as a parameter and adds // its balance to the balance of the Account's vault, then // destroys the sent vault because its balance has been consumed - pub fun deposit(from: @{Receiver}) { + access(all) fun deposit(from: @{Receiver}) { self.balance = self.balance + from.balance destroy from } @@ -199,7 +199,7 @@ Imagine that these were declared in the above `FungibleToken` contract. ```cadence - pub fun createVault(initialBalance: Int): @Vault { + access(all) fun createVault(initialBalance: Int): @Vault { return <-create Vault(balance: initialBalance) } @@ -238,15 +238,15 @@ The deployed contracts of an account can be accessed through the `contracts` obj Accounts store "deployed contracts", that is, the code of the contract: ```cadence -pub struct DeployedContract { +access(all) struct DeployedContract { /// The address of the account where the contract is deployed at. - pub let address: Address + access(all) let address: Address /// The name of the contract. - pub let name: String + access(all) let name: String /// The code of the contract. - pub let code: [UInt8] + access(all) let code: [UInt8] /// Returns an array of `Type` objects representing all the public type declarations in this contract /// (e.g. structs, resources, enums). @@ -254,12 +254,12 @@ pub struct DeployedContract { /// For example, given a contract /// ``` /// contract Foo { - /// pub struct Bar {...} - /// pub resource Qux {...} + /// access(all) struct Bar {...} + /// access(all) resource Qux {...} /// } /// ``` /// then `.publicTypes()` will return an array equivalent to the expression `[Type(), Type()]` - pub fun publicTypes(): [Type] + access(all) fun publicTypes(): [Type] } ``` @@ -295,8 +295,8 @@ A new contract can be deployed to an account using the `add` function: For example, assuming the following contract code should be deployed: ```cadence -pub contract Test { - pub let message: String +access(all) contract Test { + access(all) let message: String init(message: String) { self.message = message @@ -360,8 +360,8 @@ For example, assuming that a contract named `Test` is already deployed to the ac and it should be updated with the following contract code: ```cadence -pub contract Test { - pub let message: String +access(all) contract Test { + access(all) let message: String init(message: String) { self.message = message @@ -470,19 +470,19 @@ interface by saying `{ContractInterfaceName}.{NestedInterfaceName}` // Declare a contract interface that declares an interface and a resource // that needs to implement that interface in the contract implementation. // -pub contract interface InterfaceExample { +access(all) contract interface InterfaceExample { // Implementations do not need to declare this // They refer to it as InterfaceExample.NestedInterface // - pub resource interface NestedInterface {} + access(all) resource interface NestedInterface {} // Implementations must declare this type // - pub resource Composite: NestedInterface {} + access(all) resource Composite: NestedInterface {} } -pub contract ExampleContract: InterfaceExample { +access(all) contract ExampleContract: InterfaceExample { // The contract doesn't need to redeclare the `NestedInterface` interface // because it is already declared in the contract interface @@ -490,7 +490,7 @@ pub contract ExampleContract: InterfaceExample { // The resource has to refer to the resource interface using the name // of the contract interface to access it // - pub resource Composite: InterfaceExample.NestedInterface { + access(all) resource Composite: InterfaceExample.NestedInterface { } } ``` diff --git a/docs/cadence/language/core-events.md b/docs/cadence/language/core-events.md index 1115b830db..1674a5c711 100644 --- a/docs/cadence/language/core-events.md +++ b/docs/cadence/language/core-events.md @@ -16,7 +16,7 @@ Event name: `flow.AccountCreated` ```cadence -pub event AccountCreated(address: Address) +access(all) event AccountCreated(address: Address) ``` | Field | Type | Description | @@ -31,7 +31,7 @@ Event that is emitted when a key gets added to an account. Event name: `flow.AccountKeyAdded` ```cadence -pub event AccountKeyAdded( +access(all) event AccountKeyAdded( address: Address, publicKey: PublicKey ) @@ -50,7 +50,7 @@ Event that is emitted when a key gets removed from an account. Event name: `flow.AccountKeyRemoved` ```cadence -pub event AccountKeyRemoved( +access(all) event AccountKeyRemoved( address: Address, publicKey: PublicKey ) @@ -69,7 +69,7 @@ Event that is emitted when a contract gets deployed to an account. Event name: `flow.AccountContractAdded` ```cadence -pub event AccountContractAdded( +access(all) event AccountContractAdded( address: Address, codeHash: [UInt8], contract: String @@ -89,7 +89,7 @@ Event that is emitted when a contract gets updated on an account. Event name: `flow.AccountContractUpdated` ```cadence -pub event AccountContractUpdated( +access(all) event AccountContractUpdated( address: Address, codeHash: [UInt8], contract: String @@ -110,7 +110,7 @@ Event that is emitted when a contract gets removed from an account. Event name: `flow.AccountContractRemoved` ```cadence -pub event AccountContractRemoved( +access(all) event AccountContractRemoved( address: Address, codeHash: [UInt8], contract: String @@ -130,7 +130,7 @@ Event that is emitted when a Capability is published from an account. Event name: `flow.InboxValuePublished` ```cadence -pub event InboxValuePublished(provider: Address, recipient: Address, name: String, type: Type) +access(all) event InboxValuePublished(provider: Address, recipient: Address, name: String, type: Type) ``` | Field | Type | Description | @@ -151,7 +151,7 @@ Event that is emitted when a Capability is unpublished from an account. Event name: `flow.InboxValueUnpublished` ```cadence -pub event InboxValueUnpublished(provider: Address, name: String) +access(all) event InboxValueUnpublished(provider: Address, name: String) ``` | Field | Type | Description | @@ -170,7 +170,7 @@ Event that is emitted when a Capability is claimed by an account. Event name: `flow.InboxValueClaimed` ```cadence -pub event InboxValueClaimed(provider: Address, recipient: Address, name: String) +access(all) event InboxValueClaimed(provider: Address, recipient: Address, name: String) ``` | Field | Type | Description | diff --git a/docs/cadence/language/crypto.mdx b/docs/cadence/language/crypto.mdx index 6889747100..2bfaeb1500 100644 --- a/docs/cadence/language/crypto.mdx +++ b/docs/cadence/language/crypto.mdx @@ -9,18 +9,18 @@ The built-in enum `HashAlgorithm` provides the set of hashing algorithms that are supported by the language natively. ```cadence -pub enum HashAlgorithm: UInt8 { +access(all) enum HashAlgorithm: UInt8 { /// SHA2_256 is SHA-2 with a 256-bit digest (also referred to as SHA256). - pub case SHA2_256 = 1 + access(all) case SHA2_256 = 1 /// SHA2_384 is SHA-2 with a 384-bit digest (also referred to as SHA384). - pub case SHA2_384 = 2 + access(all) case SHA2_384 = 2 /// SHA3_256 is SHA-3 with a 256-bit digest. - pub case SHA3_256 = 3 + access(all) case SHA3_256 = 3 /// SHA3_384 is SHA-3 with a 384-bit digest. - pub case SHA3_384 = 4 + access(all) case SHA3_384 = 4 /// KMAC128_BLS_BLS12_381 is an instance of KECCAK Message Authentication Code (KMAC128) mac algorithm. /// Although this is a MAC algorithm, KMAC is included in this list as it can be used hash @@ -29,17 +29,17 @@ pub enum HashAlgorithm: UInt8 { /// It is a customized version of KMAC128 that is compatible with the hashing to curve /// used in BLS signatures. /// It is the same hasher used by signatures in the internal Flow protocol. - pub case KMAC128_BLS_BLS12_381 = 5 + access(all) case KMAC128_BLS_BLS12_381 = 5 /// KECCAK_256 is the legacy Keccak algorithm with a 256-bits digest, as per the original submission to the NIST SHA3 competition. /// KECCAK_256 is different than SHA3 and is used by Ethereum. - pub case KECCAK_256 = 6 + access(all) case KECCAK_256 = 6 /// Returns the hash of the given data - pub fun hash(_ data: [UInt8]): [UInt8] + access(all) fun hash(_ data: [UInt8]): [UInt8] /// Returns the hash of the given data and tag - pub fun hashWithTag(_ data: [UInt8], tag: string): [UInt8] + access(all) fun hashWithTag(_ data: [UInt8], tag: string): [UInt8] } ``` @@ -95,17 +95,17 @@ The built-in enum `SignatureAlgorithm` provides the set of signing algorithms th are supported by the language natively. ```cadence -pub enum SignatureAlgorithm: UInt8 { +access(all) enum SignatureAlgorithm: UInt8 { /// ECDSA_P256 is ECDSA on the NIST P-256 curve. - pub case ECDSA_P256 = 1 + access(all) case ECDSA_P256 = 1 /// ECDSA_secp256k1 is ECDSA on the secp256k1 curve. - pub case ECDSA_secp256k1 = 2 + access(all) case ECDSA_secp256k1 = 2 /// BLS_BLS12_381 is BLS signature scheme on the BLS12-381 curve. /// The scheme is set-up so that signatures are in G_1 (subgroup of the curve over the prime field) /// while public keys are in G_2 (subgroup of the curve over the prime field extension). - pub case BLS_BLS12_381 = 3 + access(all) case BLS_BLS12_381 = 3 } ``` @@ -120,7 +120,7 @@ struct PublicKey { /// Verifies a signature under the given tag, data and public key. /// It uses the given hash algorithm to hash the tag and data. - pub fun verify( + access(all) fun verify( signature: [UInt8], signedData: [UInt8], domainSeparationTag: String, @@ -131,7 +131,7 @@ struct PublicKey { /// This function is only implemented if the signature algorithm /// of the public key is BLS (BLS_BLS12_381). /// If called with any other signature algorithm, the program aborts - pub fun verifyPoP(_ proof: [UInt8]): Bool + access(all) fun verifyPoP(_ proof: [UInt8]): Bool } ``` @@ -328,7 +328,7 @@ For example, to verify two signatures with equal weights for some signed data: ```cadence import Crypto -pub fun test main() { +access(all) fun test main() { let keyList = Crypto.KeyList() let publicKeyA = PublicKey( @@ -380,12 +380,12 @@ pub fun test main() { The API of the Crypto contract related to key lists is: ```cadence -pub struct KeyListEntry { - pub let keyIndex: Int - pub let publicKey: PublicKey - pub let hashAlgorithm: HashAlgorithm - pub let weight: UFix64 - pub let isRevoked: Bool +access(all) struct KeyListEntry { + access(all) let keyIndex: Int + access(all) let publicKey: PublicKey + access(all) let hashAlgorithm: HashAlgorithm + access(all) let weight: UFix64 + access(all) let isRevoked: Bool init( keyIndex: Int, @@ -396,12 +396,12 @@ pub struct KeyListEntry { ) } -pub struct KeyList { +access(all) struct KeyList { init() /// Adds a new key with the given weight - pub fun add( + access(all) fun add( _ publicKey: PublicKey, hashAlgorithm: HashAlgorithm, weight: UFix64 @@ -409,22 +409,22 @@ pub struct KeyList { /// Returns the key at the given index, if it exists. /// Revoked keys are always returned, but they have `isRevoked` field set to true - pub fun get(keyIndex: Int): KeyListEntry? + access(all) fun get(keyIndex: Int): KeyListEntry? /// Marks the key at the given index revoked, but does not delete it - pub fun revoke(keyIndex: Int) + access(all) fun revoke(keyIndex: Int) /// Returns true if the given signatures are valid for the given signed data - pub fun verify( + access(all) fun verify( signatureSet: [KeyListSignature], signedData: [UInt8] ): Bool } -pub struct KeyListSignature { - pub let keyIndex: Int - pub let signature: [UInt8] +access(all) struct KeyListSignature { + access(all) let keyIndex: Int + access(all) let signature: [UInt8] - pub init(keyIndex: Int, signature: [UInt8]) + access(all) init(keyIndex: Int, signature: [UInt8]) } ``` diff --git a/docs/cadence/language/enumerations.md b/docs/cadence/language/enumerations.md index c877a5550f..2f631db6bd 100644 --- a/docs/cadence/language/enumerations.md +++ b/docs/cadence/language/enumerations.md @@ -34,10 +34,10 @@ Enum cases can be compared using the equality operators `==` and `!=`. // Declare an enum named `Color` which has the raw value type `UInt8`, // and declare three enum cases: `red`, `green`, and `blue` // -pub enum Color: UInt8 { - pub case red - pub case green - pub case blue +access(all) enum Color: UInt8 { + access(all) case red + access(all) case green + access(all) case blue } // Declare a variable which has the enum type `Color` and initialize // it to the enum case `blue` of the enum diff --git a/docs/cadence/language/environment-information.md b/docs/cadence/language/environment-information.md index 2f9f4d7c28..a284754929 100644 --- a/docs/cadence/language/environment-information.md +++ b/docs/cadence/language/environment-information.md @@ -34,26 +34,26 @@ To get information about a block, the functions `getCurrentBlock` and `getBlock` The `Block` type contains the identifier, height, and timestamp: ```cadence -pub struct Block { +access(all) struct Block { /// The ID of the block. /// /// It is essentially the hash of the block. /// - pub let id: [UInt8; 32] + access(all) let id: [UInt8; 32] /// The height of the block. /// /// If the blockchain is viewed as a tree with the genesis block at the root, // the height of a node is the number of edges between the node and the genesis block /// - pub let height: UInt64 + access(all) let height: UInt64 /// The view of the block. /// /// It is a detail of the consensus algorithm. It is a monotonically increasing integer /// and counts rounds in the consensus algorithm. It is reset to zero at each spork. /// - pub let view: UInt64 + access(all) let view: UInt64 /// The timestamp of the block. /// @@ -62,7 +62,7 @@ pub struct Block { /// NOTE: It is included by the proposer, there are no guarantees on how much the time stamp can deviate from the true time the block was published. /// Consider observing blocks’ status changes off-chain yourself to get a more reliable value. /// - pub let timestamp: UFix64 + access(all) let timestamp: UFix64 } ``` diff --git a/docs/cadence/language/events.md b/docs/cadence/language/events.md index 376d5c8ea4..962f410357 100644 --- a/docs/cadence/language/events.md +++ b/docs/cadence/language/events.md @@ -28,7 +28,7 @@ Events cannot be declared globally or within resource or struct types. // event GlobalEvent(field: Int) -pub contract Events { +access(all) contract Events { // Event with explicit argument labels // event BarEvent(labelA fieldA: Int, labelB fieldB: Int) @@ -46,7 +46,7 @@ pub contract Events { To emit an event from a program, use the `emit` statement: ```cadence -pub contract Events { +access(all) contract Events { event FooEvent(x: Int, y: Int) // Event with argument labels diff --git a/docs/cadence/language/functions.mdx b/docs/cadence/language/functions.mdx index 7c7f805d18..67742fe6e9 100644 --- a/docs/cadence/language/functions.mdx +++ b/docs/cadence/language/functions.mdx @@ -230,10 +230,10 @@ Functions can be annotated as `view` to indicate that they do not modify any ext A `view` annotation can be added to the beginning of a function declaration or expression like so: ```cadence -view pub fun foo(): Void {} +view access(all) fun foo(): Void {} let x = view fun(): Void {} -pub struct S { - view pub fun foo(): Void {} +access(all) struct S { + view access(all) fun foo(): Void {} view init() } ``` @@ -591,7 +591,7 @@ or passed to functions as arguments. // Declare a function named `transform` which applies a function to each element // of an array of integers and returns a new array of the results. // -pub fun transform(function: fun(Int): Int, integers: [Int]): [Int] { +access(all) fun transform(function: fun(Int): Int, integers: [Int]): [Int] { var newIntegers: [Int] = [] for integer in integers { newIntegers.append(function(integer)) @@ -599,7 +599,7 @@ pub fun transform(function: fun(Int): Int, integers: [Int]): [Int] { return newIntegers } -pub fun double(_ integer: Int): Int { +access(all) fun double(_ integer: Int): Int { return integer * 2 } diff --git a/docs/cadence/language/glossary.mdx b/docs/cadence/language/glossary.mdx index 30c6979335..ac37936b39 100644 --- a/docs/cadence/language/glossary.mdx +++ b/docs/cadence/language/glossary.mdx @@ -23,12 +23,12 @@ let refOfA: &String = &a as &String References may also be authorized if the `&` symbol is preceded by `auth` (otherwise the reference is unauthorized). -Authorized references have the `auth` modifier, i.e. the full syntax is `auth &T`, -whereas unauthorized references do not have a modifier. +Authorized references have the `auth` modifier, along with the set of entitlements to which the reference is authorized, +i.e. the full syntax is `auth(E, F) &T`, whereas unauthorized references do not have a modifier. ```cadence let a: String = "hello" -let refOfA: &String = &a as auth &String +let refOfA: auth(X) &String = &a as auth(X) &String ``` ### Logical Operator @@ -53,8 +53,8 @@ This emphasizes the whole type acts like a resource. ```cadence // Declare a resource named `SomeResource` -pub resource SomeResource { - pub var value: Int +access(all) resource SomeResource { + access(all) var value: Int init(value: Int) { self.value = value @@ -65,7 +65,7 @@ pub resource SomeResource { let a: @SomeResource <- create SomeResource(value: 0) // also in functions declarations -pub fun use(resource: @SomeResource) { +access(all) fun use(resource: @SomeResource) { destroy resource } ``` @@ -187,7 +187,7 @@ If the variable is `nil`, the move succeeds. If it is not nil, the program aborts. ```cadence -pub resource R {} +access(all) resource R {} var a: @R? <- nil a <-! create R() diff --git a/docs/cadence/language/interfaces.mdx b/docs/cadence/language/interfaces.mdx index 2804ec18e6..31284637da 100644 --- a/docs/cadence/language/interfaces.mdx +++ b/docs/cadence/language/interfaces.mdx @@ -60,9 +60,7 @@ or the field requirement may specify nothing, in which case the implementation may either be a variable or a constant field. Field requirements and function requirements must specify the required level of access. -The access must be at least be public, so the `pub` keyword must be provided. -Variable field requirements can be specified to also be publicly settable -by using the `pub(set)` keyword. +The access must be at least be public, so the `access(all)` keyword must be provided. Interfaces can be used in types. This is explained in detail in the section [Interfaces in Types](#interfaces-in-types). @@ -72,16 +70,16 @@ For now, the syntax `{I}` can be read as the type of any value that implements t // Declare a resource interface for a fungible token. // Only resources can implement this resource interface. // -pub resource interface FungibleToken { +access(all) resource interface FungibleToken { // Require the implementing type to provide a field for the balance - // that is readable in all scopes (`pub`). + // that is readable in all scopes (`access(all)`). // // Neither the `var` keyword, nor the `let` keyword is used, // so the field may be implemented as either a variable // or as a constant field. // - pub balance: Int + access(all) balance: Int // Require the implementing type to provide an initializer that // given the initial balance, must initialize the balance field. @@ -111,7 +109,7 @@ pub resource interface FungibleToken { // The type `{FungibleToken}` is the type of any resource // that implements the resource interface `FungibleToken`. // - pub fun withdraw(amount: Int): @{FungibleToken} { + access(all) fun withdraw(amount: Int): @{FungibleToken} { pre { amount > 0: "the amount must be positive" @@ -137,7 +135,7 @@ pub resource interface FungibleToken { // The parameter type `{FungibleToken}` is the type of any resource // that implements the resource interface `FungibleToken`. // - pub fun deposit(_ token: @{FungibleToken}) { + access(all) fun deposit(_ token: @{FungibleToken}) { post { self.balance == before(self.balance) + token.balance: "the amount must be added to the balance" @@ -184,7 +182,7 @@ in terms of name, parameter argument labels, parameter types, and the return typ // It has a variable field named `balance`, that can be written // by functions of the type, but outer scopes can only read it. // -pub resource ExampleToken: FungibleToken { +access(all) resource ExampleToken: FungibleToken { // Implement the required field `balance` for the `FungibleToken` interface. // The interface does not specify if the field must be variable, constant, @@ -192,7 +190,7 @@ pub resource ExampleToken: FungibleToken { // but limit outer scopes to only read from the field, it is declared variable, // and only has public access (non-settable). // - pub var balance: Int + access(all) var balance: Int // Implement the required initializer for the `FungibleToken` interface: // accept an initial balance and initialize the `balance` field. @@ -216,7 +214,7 @@ pub resource ExampleToken: FungibleToken { // NOTE: neither the precondition nor the postcondition declared // in the interface have to be repeated here in the implementation. // - pub fun withdraw(amount: Int): @ExampleToken { + access(all) fun withdraw(amount: Int): @ExampleToken { self.balance = self.balance - amount return create ExampleToken(balance: amount) } @@ -237,7 +235,7 @@ pub resource ExampleToken: FungibleToken { // NOTE: neither the precondition nor the postcondition declared // in the interface have to be repeated here in the implementation. // - pub fun deposit(_ token: @{FungibleToken}) { + access(all) fun deposit(_ token: @{FungibleToken}) { if let exampleToken <- token as? ExampleToken { self.balance = self.balance + exampleToken.balance destroy exampleToken @@ -287,26 +285,24 @@ token.withdraw(amount: 90) The access level for variable fields in an implementation may be less restrictive than the interface requires. For example, an interface may require a field to be -at least public (i.e. the `pub` keyword is specified), +at least contract-accessible (i.e. the `access(contract)` modifier is used), and an implementation may provide a variable field which is public, -but also publicly settable (the `pub(set)` keyword is specified). +(the `access(all)` modifier is used). ```cadence -pub struct interface AnInterface { - // Require the implementing type to provide a publicly readable +access(all) struct interface AnInterface { + // Require the implementing type to provide a contract-readable // field named `a` that has type `Int`. It may be a variable // or a constant field. // - pub a: Int + access(contract) a: Int } -pub struct AnImplementation: AnInterface { - // Declare a publicly settable variable field named `a` that has type `Int`. +access(all) struct AnImplementation: AnInterface { + // Declare a public variable field named `a` that has type `Int`. // This implementation satisfies the requirement for interface `AnInterface`: - // The field is at least publicly readable, but this implementation also - // allows the field to be written to in all scopes. // - pub(set) var a: Int + access(all) var a: Int init(a: Int) { self.a = a @@ -319,7 +315,7 @@ pub struct AnImplementation: AnInterface { Interfaces can be used in types: The type `{I}` is the type of all objects that implement the interface `I`. -This is called a [restricted type](./restricted-types.md): +This is called a [intersection type](./intersection-types.md): Only the functionality (members and functions) of the interface can be used when accessing a value of such a type. @@ -329,18 +325,18 @@ when accessing a value of such a type. // Require implementing types to provide a field which returns the area, // and a function which scales the shape by a given factor. // -pub struct interface Shape { - pub fun getArea(): Int - pub fun scale(factor: Int) +access(all) struct interface Shape { + access(all) fun getArea(): Int + access(all) fun scale(factor: Int) } // Declare a structure named `Square` the implements the `Shape` interface. // -pub struct Square: Shape { +access(all) struct Square: Shape { // In addition to the required fields from the interface, // the type can also declare additional fields. // - pub var length: Int + access(all) var length: Int // Provided the field `area` which is required to conform // to the interface `Shape`. @@ -348,36 +344,36 @@ pub struct Square: Shape { // Since `area` was not declared as a constant, variable, // field in the interface, it can be declared. // - pub fun getArea(): Int { + access(all) fun getArea(): Int { return self.length * self.length } - pub init(length: Int) { + access(all) init(length: Int) { self.length = length } // Provided the implementation of the function `scale` // which is required to conform to the interface `Shape`. // - pub fun scale(factor: Int) { + access(all) fun scale(factor: Int) { self.length = self.length * factor } } // Declare a structure named `Rectangle` that also implements the `Shape` interface. // -pub struct Rectangle: Shape { - pub var width: Int - pub var height: Int +access(all) struct Rectangle: Shape { + access(all) var width: Int + access(all) var height: Int // Provided the field `area which is required to conform // to the interface `Shape`. // - pub fun getArea(): Int { + access(all) fun getArea(): Int { return self.width * self.height } - pub init(width: Int, height: Int) { + access(all) init(width: Int, height: Int) { self.width = width self.height = height } @@ -385,7 +381,7 @@ pub struct Rectangle: Shape { // Provided the implementation of the function `scale` // which is required to conform to the interface `Shape`. // - pub fun scale(factor: Int) { + access(all) fun scale(factor: Int) { self.width = self.width * factor self.height = self.height * factor } @@ -528,8 +524,8 @@ For example, a resource interface may require an implementing type to provide a // which must have a field named `balance`. // resource interface FungibleToken { - pub resource Vault { - pub balance: Int + access(all) resource Vault { + access(all) balance: Int } } @@ -538,8 +534,8 @@ resource interface FungibleToken { // The nested type `Vault` must be provided to conform to the interface. // resource ExampleToken: FungibleToken { - pub resource Vault { - pub var balance: Int + access(all) resource Vault { + access(all) var balance: Int init(balance: Int) { self.balance = balance } @@ -555,13 +551,13 @@ When an interface inherits from another, all the fields, functions, and types of available to the inheriting interface. ```cadence -pub resource interface Receiver { - pub fun deposit(_ something: @AnyResource) +access(all) resource interface Receiver { + access(all) fun deposit(_ something: @AnyResource) } // `Vault` interface inherits from `Receiver` interface. -pub resource interface Vault: Receiver { - pub fun withdraw(_ amount: Int): @Vault +access(all) resource interface Vault: Receiver { + access(all) fun withdraw(_ amount: Int): @Vault } ``` @@ -569,11 +565,11 @@ In the example above, `Vault` inherits `Receiver`. Anyone implementing the `Vaul implement the `Receiver` interface. ```cadence -pub resource MyVault: Vault { +access(all) resource MyVault: Vault { // Must implement all the methods coming from both `Vault` and `Receiver` interfaces. - pub fun deposit(_ something: @AnyResource) {} + access(all) fun deposit(_ something: @AnyResource) {} - pub fun withdraw(_ amount: Int): @Vault {} + access(all) fun withdraw(_ amount: Int): @Vault {} } ``` @@ -588,26 +584,26 @@ The following sections explain how these ambiguities are resolved for different If two fields with identical names have identical types, then it will be valid. ```cadence -pub resource interface Receiver { - pub var id: UInt64 +access(all) resource interface Receiver { + access(all) var id: UInt64 } -pub resource interface Vault: Receiver { +access(all) resource interface Vault: Receiver { // `id` field has the same type as the `Receiver.id`. Hence this is valid. - pub var id: UInt64 + access(all) var id: UInt64 } ``` Otherwise, interface conformance is not valid. ```cadence -pub resource interface Receiver { - pub var id: Int +access(all) resource interface Receiver { + access(all) var id: Int } -pub resource interface Vault: Receiver { +access(all) resource interface Vault: Receiver { // `id` field has a different type than the `Receiver.id`. Hence this is invalid. - pub var id: UInt64 + access(all) var id: UInt64 } ``` @@ -616,29 +612,29 @@ pub resource interface Vault: Receiver { If two functions with identical names also have identical signatures, that is valid. ```cadence -pub resource interface Receiver { - pub fun deposit(_ something: @AnyResource) +access(all) resource interface Receiver { + access(all) fun deposit(_ something: @AnyResource) } -pub resource interface Vault: Receiver { +access(all) resource interface Vault: Receiver { // `deposit` function has the same signature as the `Receiver.deposit`. // Also none of them have any default implementations. // Hence this is valid. - pub fun deposit(_ something: @AnyResource) + access(all) fun deposit(_ something: @AnyResource) } ``` If the signatures of the two functions are different, then the interface conformance is not valid. ```cadence -pub resource interface Receiver { - pub fun deposit(_ something: @AnyResource) +access(all) resource interface Receiver { + access(all) fun deposit(_ something: @AnyResource) } -pub resource interface Vault: Receiver { +access(all) resource interface Vault: Receiver { // Error: `deposit` function has a different signature compared to the `Receiver.deposit`. // So these two cannot co-exist. - pub fun deposit() + access(all) fun deposit() } ``` @@ -650,17 +646,17 @@ to determine the order of the execution of the conditions. Given the pre/post conditions are `view` only, the order of execution would not have an impact on the conditions. ```cadence -pub resource interface Receiver { - pub fun deposit(_ something: @AnyResource) { +access(all) resource interface Receiver { + access(all) fun deposit(_ something: @AnyResource) { pre{ self.balance > 100 } } } -pub resource interface Vault: Receiver { +access(all) resource interface Vault: Receiver { // `deposit` function has the same signature as the `Receiver.deposit`. // Having pre/post condition is valid. // Both conditions would be executed, in a pre-determined order. - pub fun deposit(_ something: @AnyResource) { + access(all) fun deposit(_ something: @AnyResource) { pre{ self.balance > 50 } } } @@ -671,13 +667,13 @@ pub resource interface Vault: Receiver { An interface can provide a default implementation to an inherited function. ```cadence -pub resource interface Receiver { - pub fun log(_ message: String) +access(all) resource interface Receiver { + access(all) fun log(_ message: String) } -pub resource interface Vault: Receiver { +access(all) resource interface Vault: Receiver { // Valid: Provides the implementation for `Receiver.log` method. - pub fun log(_ message: String) { + access(all) fun log(_ message: String) { log(message.append("from Vault")) } } @@ -686,15 +682,15 @@ pub resource interface Vault: Receiver { However, an interface cannot override an inherited default implementation of a function. ```cadence -pub resource interface Receiver { - pub fun log(_ message: String) { +access(all) resource interface Receiver { + access(all) fun log(_ message: String) { log(message.append("from Receiver")) } } -pub resource interface Vault: Receiver { +access(all) resource interface Vault: Receiver { // Invalid: Cannot override the `Receiver.log` method. - pub fun log(_ message: String) { + access(all) fun log(_ message: String) { log(message.append("from Vault")) } } @@ -703,39 +699,39 @@ pub resource interface Vault: Receiver { It is also invalid to have two or more inherited default implementations for an interface. ```cadence -pub resource interface Receiver { - pub fun log(_ message: String) { +access(all) resource interface Receiver { + access(all) fun log(_ message: String) { log(message.append("from Receiver")) } } -pub resource interface Provider { - pub fun log(_ message: String) { +access(all) resource interface Provider { + access(all) fun log(_ message: String) { log(message.append("from Provider")) } } // Invalid: Two default functions from two interfaces. -pub resource interface Vault: Receiver, Provider {} +access(all) resource interface Vault: Receiver, Provider {} ``` Having said that, there can be situations where the same default function can be available via different inheritance paths. ```cadence -pub resource interface Logger { - pub fun log(_ message: String) { +access(all) resource interface Logger { + access(all) fun log(_ message: String) { log(message.append("from Logger")) } } -pub resource interface Receiver: Logger {} +access(all) resource interface Receiver: Logger {} -pub resource interface Provider: Logger {} +access(all) resource interface Provider: Logger {} // Valid: `Logger.log()` default function is visible to the `Vault` interface // via both `Receiver` and `Provider`. -pub resource interface Vault: Receiver, Provider {} +access(all) resource interface Vault: Receiver, Provider {} ``` In the above example, `Logger.log()` default function is visible to the `Vault` interface via both `Receiver` and `Provider`. @@ -749,20 +745,20 @@ A more complex situation is where a default function is available via one inheri is available via another inheritance path. ```cadence -pub resource interface Receiver { - pub fun log(_ message: String) { +access(all) resource interface Receiver { + access(all) fun log(_ message: String) { log(message.append("from Receiver")) } } -pub resource interface Provider { - pub fun log(_ message: String) { +access(all) resource interface Provider { + access(all) fun log(_ message: String) { pre{ message != "" } } } // Valid: Both the default function and the condition would be available. -pub resource interface Vault: Receiver, Provider {} +access(all) resource interface Vault: Receiver, Provider {} ``` In such situations, all rules applicable for default functions inheritance as well as condition inheritance @@ -776,16 +772,16 @@ Type and event definitions would also behave similarly to the default functions. Inherited interfaces can override type definitions and event definitions. ```cadence -pub contract interface Token { - pub struct Foo {} +access(all) contract interface Token { + access(all) struct Foo {} } -pub contract interface NonFungibleToken: Token { - pub struct Foo {} +access(all) contract interface NonFungibleToken: Token { + access(all) struct Foo {} } -pub contract MyToken: NonFungibleToken { - pub fun test() { +access(all) contract MyToken: NonFungibleToken { + access(all) fun test() { let foo: Foo // This will refer to the `NonFungibleToken.Foo` } } @@ -797,32 +793,32 @@ access it using the fully qualified name. e.g: `let foo: Token.Foo`. However, it is not allowed to have two or more inherited type/events definitions with identical names for an interface. ```cadence -pub contract interface Token { - pub struct Foo {} +access(all) contract interface Token { + access(all) struct Foo {} } -pub contract interface Collectible { - pub struct Foo {} +access(all) contract interface Collectible { + access(all) struct Foo {} } // Invalid: Two type definitions with the same name from two interfaces. -pub contract NonFungibleToken: Token, Collectible { +access(all) contract NonFungibleToken: Token, Collectible { } ``` Similar to default functions, there can be situations where the same type/event definition can be available via different inheritance paths. ```cadence -pub contract interface Logger { - pub struct Foo {} +access(all) contract interface Logger { + access(all) struct Foo {} } -pub contract interface Token: Logger {} +access(all) contract interface Token: Logger {} -pub contract interface Collectible: Logger {} +access(all) contract interface Collectible: Logger {} // Valid: `Logger.Foo` struct is visible to the `NonFungibleToken` interface via both `Token` and `Collectible`. -pub contract interface NonFungibleToken: Token, Collectible {} +access(all) contract interface NonFungibleToken: Token, Collectible {} ``` In the above example, `Logger.Foo` type definition is visible to the `NonFungibleToken` interface via both `Token` @@ -835,21 +831,21 @@ However, if at least one of the interfaces in the middle of the chain also overr then the code becomes invalid, as there are multiple implementations present now, which leads to ambiguity. ```cadence -pub contract interface Logger { - pub struct Foo {} +access(all) contract interface Logger { + access(all) struct Foo {} } -pub contract interface Token: Logger { - pub struct Foo {} +access(all) contract interface Token: Logger { + access(all) struct Foo {} } -pub contract interface Collectible: Logger {} +access(all) contract interface Collectible: Logger {} // Invalid: The default implementation of the `Foo` struct by the `Logger` // interface is visible to the `NonFungibleToken` via the `Collectible` interface. // Another implementation of `Foo` struct is visible to the `NonFungibleToken` via the `Token` interface. // This creates ambiguity. -pub resource interface NonFungibleToken: Token, Provider {} +access(all) resource interface NonFungibleToken: Token, Provider {} ``` @@ -873,31 +869,31 @@ This would convert to a Cadence implementation similar to: ```cadence struct interface A: B, C { - pub fun test() { + access(all) fun test() { pre { print("A") } } } struct interface B: D, E { - pub fun test() { + access(all) fun test() { pre { print("B") } } } struct interface C: E { - pub fun test() { + access(all) fun test() { pre { print("C") } } } struct interface D { - pub fun test() { + access(all) fun test() { pre { print("D") } } } struct interface E { - pub fun test() { + access(all) fun test() { pre { print("E") } } } @@ -907,7 +903,7 @@ Any concrete type implementing interface `A` would be equivalent to implementing ```cadence struct Foo: A { - pub fun test() { + access(all) fun test() { pre { print("Foo") } } } @@ -918,7 +914,7 @@ The linearized interface order would be: [A, B, D, E, C]. i.e: same as having: ```cadence struct Foo: A, B, D, C, E { - pub fun test() { + access(all) fun test() { pre { print("Foo") } } } diff --git a/docs/cadence/language/intersection-types.md b/docs/cadence/language/intersection-types.md new file mode 100644 index 0000000000..83d3b74153 --- /dev/null +++ b/docs/cadence/language/intersection-types.md @@ -0,0 +1,92 @@ +--- +title: Intersection Types +sidebar_position: 16 +--- + +Interface types cannot be referenced directly; +instead they must be used as part of intersection types. +An intersection type represents a value that conforms to all of the interfaces listed in the intersection. + +The syntax of a intersection type is `{U1, U2, ... Un}`, +where the types `U1` to `Un` are the interfaces that the type conforms to. + +The members and functions of any of the set of interfaces are available. + +Intersection types are useful for writing functions that work on a variety of different inputs. +For example, by using an intersection type for a parameter's type, +the function may accept any concrete value that implements all the interfaces in that intersection. +The value is restricted to the functionality of the intersection; +if the function accidentally attempts to access other functionality, +this is prevented by the static checker. + +```cadence +access(all) struct interface HasID { + access(all) let id: String +} + +access(all) struct A: HasID { + access(all) let id: String + + init(id: String) { + self.id = id + } +} + +access(all) struct B: HasID { + access(all) let id: String + + init(id: String) { + self.id = id + } +} + +// Create two instances, one of type `A`, and one of type `B`. +// Both types conform to interface `HasID`, so the structs can be assigned +// to variables with type `{HasID}`: Some resource type which only allows +// access to the functionality of resource interface `HasID` + +let hasID1: {HasID} = A(id: "1") +let hasID2: {HasID} = B(id: "2") + +// Declare a function named `getID` which has one parameter with type `{HasID}`. +// The type `{HasID}` is a short-hand for `AnyStruct{HasID}`: +// Some structure which only allows access to the functionality of interface `HasID`. +// +access(all) fun getID(_ value: {HasID}): String { + return value.id +} + +let id1 = getID(hasID1) +// `id1` is "1" + +let id2 = getID(hasID2) +// `id2` is "2" +``` + +If more than two interfaces are present in an intersection type, +any concrete value of that type must implement both of them: + +```cadence +access(all) struct interface HasMetadata { + access(all) let metadata: AnyStruct +} + +access(all) struct C: HasID, HasMetadata { + access(all) let id: String + access(all) var metadata: AnyStruct + + init(id: String) { + self.id = id + } + + fun setMetadata(_ data: AnyStruct) { + self.metadata = data + } +} + +// valid, because `C` implements both `HasID` and `HasMetadata`. +let hasID3: {HasID, HasMetadata} = C(id: "3") + +// valid, because `A` implements only `HasID`. +let hasID4: {HasID, HasMetadata} = A(id: "4") +``` \ No newline at end of file diff --git a/docs/cadence/language/references.mdx b/docs/cadence/language/references.mdx index 02b6f6727c..d564980d28 100644 --- a/docs/cadence/language/references.mdx +++ b/docs/cadence/language/references.mdx @@ -73,13 +73,13 @@ resource interface HasCount { // Declare a resource named `Counter` that conforms to `HasCount` // resource Counter: HasCount { - pub var count: Int + access(all) var count: Int - pub init(count: Int) { + access(all) init(count: Int) { self.count = count } - pub fun increment() { + access(all) fun increment() { self.count = self.count + 1 } } @@ -99,19 +99,12 @@ counterRef.increment() counterRef.count // is `43` ``` -References may be **authorized** or **unauthorized**. - -Authorized references have the `auth` modifier, i.e. the full syntax is `auth &T`, -whereas unauthorized references do not have a modifier. - -Authorized references can be freely upcasted and downcasted, -whereas unauthorized references can only be upcasted. -Also, authorized references are subtypes of unauthorized references. +References can be freely upcasted and downcasted, and are covariant in their referenced type. +So, for example, for some struct `S`, `&S` is a subtype of `&AnyStruct`, but not of `&Int`. ```cadence - -// Create an unauthorized reference to the counter, -// typed with the restricted type `&{HasCount}`, +// Create an reference to the counter, +// typed with the intersection type `&{HasCount}`, // i.e. some resource that conforms to the `HasCount` interface // let countRef = &counter as &{HasCount} @@ -123,37 +116,163 @@ countRef.count // is `43` // countRef.increment() -// Invalid: Cannot conditionally downcast to reference type `&Counter`, -// as the reference `countRef` is unauthorized. -// -// The counter value has type `Counter`, which is a subtype of `{HasCount}`, -// but as the reference is unauthorized, the cast is not allowed. -// It is not possible to "look under the covers" +// We can conditionally downcast `countRef` to a `Counter` if it has +// that type at runtime. // let counterRef2: &Counter = countRef as? &Counter +counterRef2.increment() +``` -// Create an authorized reference to the counter, -// again with the restricted type `{HasCount}`, i.e. some resource -// that conforms to the `HasCount` interface -// -let authCountRef = &counter as auth &{HasCount} +References are ephemeral, i.e. they cannot be [stored](accounts#account-storage). +Instead, consider [storing a capability and borrowing it](capability-based-access-control) when needed. -// Conditionally downcast to reference type `&Counter`. -// This is valid, because the reference `authCountRef` is authorized -// -let counterRef3: &Counter = authCountRef as? &Counter +## Authorized References + +By default, references are **unauthorized**. +However, they may also be **authorized** to a set of [entitlements](./access-control.md#entitlements) + +Authorized references have the `auth` modifier, +along with the set of entitlements to which they are authorized. The full syntax is: +`auth(E, F, G) &T` for a reference authorized to `E`, `F` and `G`, +or `auth(E | F | G) &T` for a refernece authorized to `E`, `F`, **or** `G`. +Authorized references are subtypes of unauthorized references. + +Entitlements can only be given to references when they are created, +and references to a value can only be created by the owner of the value. +When creating a reference, that reference can be given any set of entitlements the value owner wishes to add. -counterRef3.count // is `43` +Possessing an entitlement allows a reference to have access to functions and fields on its referenced type +that require that entitlement. E.g, if we extended the `HasCount` interface with a function: -counterRef3.increment() +```cadence +entitlement Reset -counterRef3.count // is `44` +resource interface HasCount { + count: Int + access(Reset) fun resetCount() +} ``` -References are ephemeral, i.e. they cannot be [stored](accounts#account-storage). -Instead, consider [storing a capability and borrowing it](capability-based-access-control) when needed. +Then an unauthorized reference of type `&{HasCount}` would be unable to call `resetCount`. +However, we can create a reference that can, like so: + + +``` +let authCountRef: auth(Reset) &{HasCount} = &counter + +// Valid, because `authCountRef` is authorized to `Reset` +authCountRef.resetCount() +``` + +It is important to note that while references are covariant (and downcastable) with respect to their reference type, +the authorization portion of the reference can never be downcast. +In fact, the only way to "add" entitlements to a reference is to do so at the time of its creation, like in the example above. +A reference will never have any more entitlements than the set with which it was created, +and the set of entitlements on a reference at runtime will always match the set expressed in its static type. +One implication of this is that upcasting an authorized reference actually changes its runtime type: + +``` +let authCountRef: auth(Reset) &{HasCount} = &counter +let unauthCountRef = authCountRef as &{HasCount} +let authCountRef2 = unauthCountRef as? auth(Reset) &{HasCount} + +// Invalid: `authCountRef2` is `nil`, as the upcast of `authCountRef` cleared the +// `Reset` entitlement from the reference, meaning that it cannot be regained on downcasting. +authCountRef2.resetCount() +``` + +The benefit of this is that there is never any "surprising" behavior with regards to entitlements, +every reference value is transparent about what it is capable of at runtime. + +While entitlement sets on references cannot be downcast, they can be upcast, or used in places expecting supertypes, +and have special subtyping rules based on whether they are `|` or `,`-separated sets. + +In general, an entitlement set `{Us}` is a subtype of an entitlement set `{Vs}` when `{Us}` has more entitlements +in it than `{Vs}`, and when both are `,`-separated (as they will be in most cases), this is the rule exactly: +`{Us}` is a subset of `{Vs}` when it is a superset of `{Vs}`. + +Conversely, if both are `|`-separated, the rule is reversed: +`{Us}` is a subset of `{Vs}` when it is a subset of `{Vs}`. +It may be helpful to think of this as saying that `{Us}` is more specific than `{Vs}` in this case; +`{Vs}` expresses a set of entitlements that the reference **might** possess, +while `{Us}` is expressing a more specific set of potential entitlements. + +Lastly, if `{Us}` is `,`-separated while `{Vs}` is `|`-separated, +then `{Us}` is a subset of `{Vs}` when any of the `Us` also appears in `{Vs}`. +To see why, consider again that `{Vs}` expresses a set of entitlements that the reference **might** possess, +and as long as at least one of these entitlements is in `{Us}` (which is a set of entitlements that we **know** the reference has), +then the description provided by `{Vs}` is correct. + +As an example to illustrate these rules: + +``` +let eRef: auth(E) &T = ... +let efRef: auth(E, F) &T = ... +let eOrFRef: auth(E | F) &T = ... + +// Invalid, `eRef` only has `E` but `F` is required +eRef as auth(F) &T + +// Invalid, `eRef` only has `E` but both `E` and `F` are required +eRef as auth(E, F) &T + +// Valid, `eRef` definitely has `E` and either `E` or `F` is sufficient +eRef as auth(E | F) &T + +// Valid, `efRef` both `E` and `F` but only `F` is required +efRef as auth(F) &T + +// Valid, `efRef` both `E` and `F`, and either is sufficient +efRef as auth(E | F) &T + +// Invalid, `eOrFRef` has one of `E` or `F` but we need to definitely have `F` +eOrFRef as auth(F) &T + +// Invalid, `eOrFRef` has one of `E` or `F` but we need both +eOrFRef as auth(E, F) &T +``` + +### References and Entitlement Mappings + +In most situations, an [entitlement mapping](./access-control.md#entitlement-mappings) is valid in the `auth` portion of a reference type. +However, in certain specific circumstances in the definition of a field or function on a composite type, an entitlement mapping may be used in an `auth` modifier. + +When a field is defined with an entitlement mapping: + +```cadence +entitlement mapping M { + // omitted +} +resource interface I { + access(M) let foo: auth(M) &T +} +``` + +Here, the `M` in `auth(M) &T` indicates that the entitlements that the reference produced by an `iRef.foo` access will have +are determined by the entitlements to `I` that `iRef` has, for some `iRef` value that is a reference to `{I}`. Conceptually, +it creates a correspondence between the "output" reference's type and the "input" access modifier. + +When an accessor function is defined with an entitlement mapping: + +```cadence +entitlement mapping M { + // omitted +} +resource I { + access(self) let myField: T + + access(M) fun getMyField(): auth(M) &T { + return &self.myField as auth(M) &T + } +} +``` + +The `M` in the `auth(M) &T` of the function's return type annotation indicates the same thing as in the field case. +However, in this example `M` is also used in a reference type within the body of the function. +Inside the body of function with entitlement-mapped access, +the name of the entitlement mapping may be used as a stand-in for the output entitlements of the map. -### Reference validity +## Reference validity Ephemeral references stay valid throughout the course of the program. However, **references to resources** can become invalid during the execution of a program, diff --git a/docs/cadence/language/resources.mdx b/docs/cadence/language/resources.mdx index fe9219ec76..17c9ed3f55 100644 --- a/docs/cadence/language/resources.mdx +++ b/docs/cadence/language/resources.mdx @@ -40,8 +40,8 @@ and when it is returned from a function. ```cadence // Declare a resource named `SomeResource`, with a variable integer field. // -pub resource SomeResource { - pub var value: Int +access(all) resource SomeResource { + access(all) var value: Int init(value: Int) { self.value = value @@ -69,7 +69,7 @@ b.value // equals 0 // // The parameter has a resource type, so the type annotation must be prefixed with `@`. // -pub fun use(resource: @SomeResource) { +access(all) fun use(resource: @SomeResource) { // ... } @@ -128,7 +128,7 @@ let someResource: @SomeResource <- create SomeResource(value: 5) // // The parameter has a resource type, so the type annotation must be prefixed with `@`. // -pub fun use(resource: @SomeResource) { +access(all) fun use(resource: @SomeResource) { destroy resource } @@ -137,7 +137,7 @@ pub fun use(resource: @SomeResource) { // The return type is a resource type, so the type annotation must be prefixed with `@`. // The return statement must also use the `<-` operator to make it explicit the resource is moved. // -pub fun get(): @SomeResource { +access(all) fun get(): @SomeResource { let newResource <- create SomeResource() return <-newResource } @@ -149,7 +149,7 @@ Resources **must** be used exactly once. // Declare a function which consumes a resource but does not use it. // This function is invalid, because it would cause a loss of the resource. // -pub fun forgetToUse(resource: @SomeResource) { +access(all) fun forgetToUse(resource: @SomeResource) { // Invalid: The resource parameter `resource` is not used, but must be. } ``` @@ -177,7 +177,7 @@ res.value // This function is invalid, because it does not always use the resource parameter, // which would cause a loss of the resource. // -pub fun sometimesDestroy(resource: @SomeResource, destroyResource: Bool) { +access(all) fun sometimesDestroy(resource: @SomeResource, destroyResource: Bool) { if destroyResource { destroy resource } @@ -192,7 +192,7 @@ pub fun sometimesDestroy(resource: @SomeResource, destroyResource: Bool) { // This function is valid, as it always uses the resource parameter, // and does not cause a loss of the resource. // -pub fun alwaysUse(resource: @SomeResource, destroyResource: Bool) { +access(all) fun alwaysUse(resource: @SomeResource, destroyResource: Bool) { if destroyResource { destroy resource } else { @@ -208,7 +208,7 @@ pub fun alwaysUse(resource: @SomeResource, destroyResource: Bool) { // This function is invalid, because it does not always use the resource parameter, // which would cause a loss of the resource. // -pub fun returnBeforeDestroy(move: Bool) { +access(all) fun returnBeforeDestroy(move: Bool) { let res <- create SomeResource(value: 1) if move { use(resource: <-res) @@ -234,7 +234,7 @@ Instead, use a swap statement (`<->`) or shift statement (`<- target <-`) to replace the resource variable with another resource. ```cadence -pub resource R {} +access(all) resource R {} var x <- create R() var y <- create R() @@ -268,7 +268,7 @@ A resource may have only one destructor. ```cadence var destructorCalled = false -pub resource Resource { +access(all) resource Resource { // Declare a destructor for the resource, which is executed // when the resource is destroyed. @@ -292,7 +292,7 @@ it **must** declare a destructor, which **must** invalidate all resource fields, i.e. move or destroy them. ```cadence -pub resource Child { +access(all) resource Child { let name: String init(name: String) @@ -304,7 +304,7 @@ pub resource Child { // The resource *must* declare a destructor // and the destructor *must* invalidate the resource field. // -pub resource Parent { +access(all) resource Parent { let name: String var child: @Child diff --git a/docs/cadence/language/restricted-types.md b/docs/cadence/language/restricted-types.md index 433e19e79f..358ea4fbce 100644 --- a/docs/cadence/language/restricted-types.md +++ b/docs/cadence/language/restricted-types.md @@ -25,20 +25,20 @@ this is prevented by the static checker. // which has a read-only `count` field // resource interface HasCount { - pub let count: Int + access(all) let count: Int } // Declare a resource named `Counter`, which has a writeable `count` field, // and conforms to the resource interface `HasCount` // -pub resource Counter: HasCount { - pub var count: Int +access(all) resource Counter: HasCount { + access(all) var count: Int init(count: Int) { self.count = count } - pub fun increment() { + access(all) fun increment() { self.count = self.count + 1 } } @@ -77,8 +77,8 @@ unrestrictedCounter.increment() // Declare another resource type named `Strings` // which implements the resource interface `HasCount` // -pub resource Strings: HasCount { - pub var count: Int +access(all) resource Strings: HasCount { + access(all) var count: Int access(self) var strings: [String] init() { @@ -86,7 +86,7 @@ pub resource Strings: HasCount { self.strings = [] } - pub fun append(_ string: String) { + access(all) fun append(_ string: String) { self.strings.append(string) self.count = self.count + 1 } @@ -111,20 +111,20 @@ For example, the type `{HasCount}` is any resource that implements the resource interface `HasCount`. ```cadence -pub struct interface HasID { - pub let id: String +access(all) struct interface HasID { + access(all) let id: String } -pub struct A: HasID { - pub let id: String +access(all) struct A: HasID { + access(all) let id: String init(id: String) { self.id = id } } -pub struct B: HasID { - pub let id: String +access(all) struct B: HasID { + access(all) let id: String init(id: String) { self.id = id @@ -143,7 +143,7 @@ let hasID2: {HasID} = B(id: "2") // The type `{HasID}` is a short-hand for `AnyStruct{HasID}`: // Some structure which only allows access to the functionality of interface `HasID`. // -pub fun getID(_ value: {HasID}): String { +access(all) fun getID(_ value: {HasID}): String { return value.id } diff --git a/docs/cadence/language/run-time-types.md b/docs/cadence/language/run-time-types.md index 81da987d31..5ede0b032a 100644 --- a/docs/cadence/language/run-time-types.md +++ b/docs/cadence/language/run-time-types.md @@ -91,26 +91,25 @@ Run-time types can also be constructed from type identifier strings using built- ```cadence fun CompositeType(_ identifier: String): Type? fun InterfaceType(_ identifier: String): Type? -fun RestrictedType(identifier: String?, restrictions: [String]): Type? +fun IntersectionType(types: [String]): Type? ``` -Given a type identifier (as well as a list of identifiers for restricting interfaces -in the case of `RestrictedType`), these functions will look up nominal types and +Given a type identifier (or a list of identifiers for interfaces +in the case of `IntersectionType`), these functions will look up nominal types and produce their run-time equivalents. If the provided identifiers do not correspond -to any types, or (in the case of `RestrictedType`) the provided combination of +to any types, or (in the case of `IntersectionType`) the provided combination of identifiers would not type-check statically, these functions will produce `nil`. ```cadence -struct Test {} +struct Test: I {} struct interface I {} let type: Type = CompositeType("A.0000000000000001.Test") // `type` is `Type` -let type2: Type = RestrictedType( - identifier: type.identifier, +let type2: Type = IntersectionType( restrictions: ["A.0000000000000001.I"] ) -// `type2` is `Type` +// `type2` is `Type<{I}>` ``` Other built-in functions will construct compound types from other run-types. @@ -124,7 +123,7 @@ fun FunctionType(parameters: [Type], return: Type): Type fun DictionaryType(key: Type, value: Type): Type? // returns `nil` if `type` is not a reference type fun CapabilityType(_ type: Type): Type? -fun ReferenceType(authorized: bool, type: Type): Type +fun ReferenceType(entitlements: [String], type: Type): Type? ``` ### Asserting the Type of a Value @@ -181,21 +180,21 @@ something.isInstance(Type()) // is `false` For example, this allows implementing a marketplace sale resource: ```cadence -pub resource SimpleSale { +access(all) resource SimpleSale { /// The resource for sale. /// Once the resource is sold, the field becomes `nil`. /// - pub var resourceForSale: @AnyResource? + access(all) var resourceForSale: @AnyResource? /// The price that is wanted for the purchase of the resource. /// - pub let priceForResource: UFix64 + access(all) let priceForResource: UFix64 /// The type of currency that is required for the purchase. /// - pub let requiredCurrency: Type - pub let paymentReceiver: Capability<&{FungibleToken.Receiver}> + access(all) let requiredCurrency: Type + access(all) let paymentReceiver: Capability<&{FungibleToken.Receiver}> /// `paymentReceiver` is the capability that will be borrowed /// once a valid purchase is made. @@ -226,7 +225,7 @@ pub resource SimpleSale { /// If the purchase succeeds, the resource for sale is returned. /// If the purchase fails, the program aborts. /// - pub fun buyObject(with funds: @FungibleToken.Vault): @AnyResource { + access(all) fun buyObject(with funds: @FungibleToken.Vault): @AnyResource { pre { // Ensure the resource is still up for sale self.resourceForSale != nil: "The resource has already been sold" diff --git a/docs/cadence/language/values-and-types.mdx b/docs/cadence/language/values-and-types.mdx index 470e8e5ae1..e3a4e7e22d 100644 --- a/docs/cadence/language/values-and-types.mdx +++ b/docs/cadence/language/values-and-types.mdx @@ -950,6 +950,21 @@ let c = str[0] // is the Character "a" let uwu: String = String.fromCharacters(rawUwU) // "UwU" ``` +- + ```cadence + let utf8: [UInt8] + ``` + + The byte array of the UTF-8 encoding + + ```cadence + let a: Character = "a" + let a_bytes = a.utf8 // `a_bytes` is `[97]` + + let bouquet: Character = "\u{1F490}" + let bouquet_bytes = bouquet.utf8 // `bouquet_bytes` is `[240, 159, 146, 144]` + ``` + ## Arrays Arrays are mutable, ordered collections of values. @@ -1201,6 +1216,36 @@ are available for both variable-sized and fixed-sized or variable-sized arrays. let invalidIndices = example.slice(from: 2, upTo: 1) ``` +- + ```cadence + fun reverse(): [T] + ``` + + Returns a new array with contents in the reversed order. + Available if `T` is not resource-kinded. + + ```cadence + let example = [1, 2, 3, 4] + + // Create a new array which is the reverse of the original array. + let reversedExample = example.reverse() + // `reversedExample` is now `[4, 3, 2, 1]` + ``` + + ```cadence + fun reverse(): [T; N] + ``` + + Returns a new fixed-sized array of same size with contents in the reversed order. + + ```cadence + let fixedSizedExample: [String; 3] = ["ABC", "XYZ", "PQR"] + + // Create a new array which is the reverse of the original array. + let fixedArrayReversedExample = fixedSizedExample.reverse() + // `fixedArrayReversedExample` is now `["PQR", "XYZ", "ABC"]` + ``` + #### Variable-size Array Functions The following functions can only be used on variable-sized arrays. diff --git a/docs/cadence/security-best-practices.mdx b/docs/cadence/security-best-practices.mdx index 58c470c3f1..5d8849ac2f 100644 --- a/docs/cadence/security-best-practices.mdx +++ b/docs/cadence/security-best-practices.mdx @@ -11,11 +11,8 @@ Some practices listed below might overlap with advice in the [Cadence Anti-Patte [References](./language/references.mdx) are ephemeral values and cannot be stored. If persistence is required, store a capability and borrow it when needed. -Authorized references (references with the `auth` keyword) allow downcasting, e.g. a restricted type to its unrestricted type and should only be used in some specific cases. - -When exposing functionality, provide the least access necessary. Do not use authorized references, as they can be downcasted, potentially allowing a user to gain access to supposedly restricted functionality. For example, the fungible token standard provides an interface to get the balance of a vault, without exposing the withdrawal functionality. - -Be aware that the subtype or unrestricted type could expose functionality that was not intended to be exposed. Do not use authorized references when exposing functionality. For example, the fungible token standard provides an interface to get the balance of a vault, without exposing the withdrawal functionality. +When exposing functionality, provide the least access necessary. When creating an authorized reference, +create it with only the minimal set of entitlements required to achieve the desired functionality. ## Account Storage @@ -51,14 +48,16 @@ Do not blindly sign a transaction. The transaction could for example change depl ## Types -Use [restricted types and interfaces](./language/restricted-types.md). Always use the most specific type possible, following the principle of least privilege. Types should always be as restrictive as possible, especially for resource types. +Use [intersection types and interfaces](./language/intersection-types.md). Always use the most specific type possible, following the principle of least privilege. Types should always be as restrictive as possible, especially for resource types. If given a less-specific type, cast to the more specific type that is expected. For example, when implementing the fungible token standard, a user may deposit any fungible token, so the implementation should cast to the expected concrete fungible token type. ## Access Control -Declaring a field as [`pub/access(all)`](./language/access-control.md) only protects from replacing the field’s value, but the value itself can still be mutated if it is mutable. Remember that containers, like dictionaries, and arrays, are mutable. +Declaring a field as [`access(all)`](./language/access-control.md) only protects from replacing the field’s value, but the value itself can still be mutated if it is mutable. Remember that containers, like dictionaries, and arrays, are mutable. Prefer non-public access to a mutable state. That state may also be nested. For example, a child may still be mutated even if its parent exposes it through a field with non-settable access. -Do not use the `pub/access(all)` modifier on fields and functions unless necessary. Prefer `priv/access(self)`, or `access(contract)` and `access(account)` when other types in the contract or account need to have access. +Do not use the `access(all)` modifier on fields unless necessary. +Prefer `access(self)`, or `access(contract)` and `access(account)` when other types in the contract or account need to have access, +and entitlement-based access for other cases. diff --git a/docs/cadence/solidity-to-cadence.mdx b/docs/cadence/solidity-to-cadence.mdx index e651501382..99f0fe02d3 100644 --- a/docs/cadence/solidity-to-cadence.mdx +++ b/docs/cadence/solidity-to-cadence.mdx @@ -288,10 +288,10 @@ Scripts are read-only in nature, requiring only a `main` function declaration an import FungibleToken from "../../contracts/FungibleToken.cdc" import ExampleToken from "../../contracts/ExampleToken.cdc" -pub fun main(account: Address): UFix64 { +access(all) fun main(account: Address): UFix64 { let acct = getAccount(account) let vaultRef = acct.getCapability(ExampleToken.VaultPublicPath) - .borrow<&ExampleToken.Vault{FungibleToken.Balance}>() + .borrow<&ExampleToken.Vault>() ?? panic("Could not borrow Balance reference to the Vault") return vaultRef.balance diff --git a/docs/cadence/testing-framework.mdx b/docs/cadence/testing-framework.mdx index 1bc9b2ded2..8aa4bdcf4b 100644 --- a/docs/cadence/testing-framework.mdx +++ b/docs/cadence/testing-framework.mdx @@ -20,22 +20,22 @@ Both `setup` and `tearDown` functions are optional. // A `setup` function that will always run before the rest of the methods. // Can be used to initialize things that would be used across the test cases. // e.g: initialling a blockchain backend, initializing a contract, etc. -pub fun setup() { +access(all) fun setup() { } // Test functions start with the 'test' prefix. -pub fun testSomething() { +access(all) fun testSomething() { } -pub fun testAnotherThing() { +access(all) fun testAnotherThing() { } -pub fun testMoreThings() { +access(all) fun testMoreThings() { } // A `tearDown` function that will always run at the end of all test cases. // e.g: Can be used to stop the blockchain back-end used for tests, etc. or any cleanup. -pub fun tearDown() { +access(all) fun tearDown() { } ``` ## Test Standard Library @@ -80,18 +80,18 @@ fun expect(_ value: AnyStruct, _ matcher: Matcher) A matcher is an object that consists of a test function and associated utility functionality. ```cadence -pub struct Matcher { +access(all) struct Matcher { - pub let test: fun(AnyStruct): Bool + access(all) let test: fun(AnyStruct): Bool - pub init(test: fun(AnyStruct): Bool) { + access(all) init(test: fun(AnyStruct): Bool) { self.test = test } /// Combine this matcher with the given matcher. /// Returns a new matcher that succeeds if this and the given matcher succeed. /// - pub fun and(_ other: Matcher): Matcher { + access(all) fun and(_ other: Matcher): Matcher { return Matcher(test: fun (value: AnyStruct): Bool { return self.test(value) && other.test(value) }) @@ -100,7 +100,7 @@ pub struct Matcher { /// Combine this matcher with the given matcher. /// Returns a new matcher that succeeds if this or the given matcher succeeds. /// - pub fun or(_ other: Matcher): Matcher { + access(all) fun or(_ other: Matcher): Matcher { return Matcher(test: fun (value: AnyStruct): Bool { return self.test(value) || other.test(value) }) @@ -153,9 +153,9 @@ It imitates the behavior of a real network, for testing. ```cadence /// Blockchain emulates a real network. /// -pub struct Blockchain { +access(all) struct Blockchain { - pub let backend: AnyStruct{BlockchainBackend} + access(all) let backend: AnyStruct{BlockchainBackend} init(backend: AnyStruct{BlockchainBackend}) { self.backend = backend @@ -164,7 +164,7 @@ pub struct Blockchain { /// Executes a script and returns the script return value and the status. /// `returnValue` field of the result will be `nil` if the script failed. /// - pub fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult { + access(all) fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult { return self.backend.executeScript(script, arguments) } @@ -172,33 +172,33 @@ pub struct Blockchain { /// The transaction is paid by the service account. /// The returned account can be used to sign and authorize transactions. /// - pub fun createAccount(): Account { + access(all) fun createAccount(): Account { return self.backend.createAccount() } /// Add a transaction to the current block. /// - pub fun addTransaction(_ tx: Transaction) { + access(all) fun addTransaction(_ tx: Transaction) { self.backend.addTransaction(tx) } /// Executes the next transaction in the block, if any. /// Returns the result of the transaction, or nil if no transaction was scheduled. /// - pub fun executeNextTransaction(): TransactionResult? { + access(all) fun executeNextTransaction(): TransactionResult? { return self.backend.executeNextTransaction() } /// Commit the current block. /// Committing will fail if there are un-executed transactions in the block. /// - pub fun commitBlock() { + access(all) fun commitBlock() { self.backend.commitBlock() } /// Executes a given transaction and commits the current block. /// - pub fun executeTransaction(_ tx: Transaction): TransactionResult { + access(all) fun executeTransaction(_ tx: Transaction): TransactionResult { self.addTransaction(tx) let txResult = self.executeNextTransaction()! self.commitBlock() @@ -207,7 +207,7 @@ pub struct Blockchain { /// Executes a given set of transactions and commits the current block. /// - pub fun executeTransactions(_ transactions: [Transaction]): [TransactionResult] { + access(all) fun executeTransactions(_ transactions: [Transaction]): [TransactionResult] { for tx in transactions { self.addTransaction(tx) } @@ -224,7 +224,7 @@ pub struct Blockchain { /// Deploys a given contract, and initializes it with the arguments. /// - pub fun deployContract( + access(all) fun deployContract( name: String, code: String, account: Account, @@ -245,19 +245,19 @@ The `BlockchainBackend` provides the actual functionality of the blockchain. ```cadence /// BlockchainBackend is the interface to be implemented by the backend providers. /// -pub struct interface BlockchainBackend { +access(all) struct interface BlockchainBackend { - pub fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult + access(all) fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult - pub fun createAccount(): Account + access(all) fun createAccount(): Account - pub fun addTransaction(_ tx: Transaction) + access(all) fun addTransaction(_ tx: Transaction) - pub fun executeNextTransaction(): TransactionResult? + access(all) fun executeNextTransaction(): TransactionResult? - pub fun commitBlock() + access(all) fun commitBlock() - pub fun deployContract( + access(all) fun deployContract( name: String, code: String, account: Account, @@ -289,9 +289,9 @@ The returned account consists of the `address` of the account, and a `publicKey` ```cadence /// Account represents info about the account created on the blockchain. /// -pub struct Account { - pub let address: Address - pub let publicKey: PublicKey +access(all) struct Account { + access(all) let address: Address + access(all) let publicKey: PublicKey init(address: Address, publicKey: PublicKey) { self.address = address @@ -306,7 +306,7 @@ Scripts can be run with the `executeScript` function, which returns a `ScriptRes The function takes script-code as the first argument, and the script-arguments as an array as the second argument. ```cadence -let result = blockchain.executeScript("pub fun main(a: String) {}", ["hello"]) +let result = blockchain.executeScript("access(all) fun main(a: String) {}", ["hello"]) ``` The script result consists of the `status` of the script execution, and a `returnValue` if the script execution was @@ -315,10 +315,10 @@ successful, or an `error` otherwise (see [errors](#errors) section for more deta ```cadence /// The result of a script execution. /// -pub struct ScriptResult { - pub let status: ResultStatus - pub let returnValue: AnyStruct? - pub let error: Error? +access(all) struct ScriptResult { + access(all) let status: ResultStatus + access(all) let returnValue: AnyStruct? + access(all) let error: Error? init(status: ResultStatus, returnValue: AnyStruct?, error: Error?) { self.status = status @@ -336,11 +336,11 @@ a list of signers that would sign the transaction, and the transaction arguments ```cadence /// Transaction that can be submitted and executed on the blockchain. /// -pub struct Transaction { - pub let code: String - pub let authorizers: [Address] - pub let signers: [Account] - pub let arguments: [AnyStruct] +access(all) struct Transaction { + access(all) let code: String + access(all) let authorizers: [Address] + access(all) let signers: [Account] + access(all) let arguments: [AnyStruct] init(code: String, authorizers: [Address], signers: [Account], arguments: [AnyStruct]) { self.code = code @@ -384,9 +384,9 @@ The result of a transaction consists of the status of the execution, and an `Err ```cadence /// The result of a transaction execution. /// -pub struct TransactionResult { - pub let status: ResultStatus - pub let error: Error? +access(all) struct TransactionResult { + access(all) let status: ResultStatus + access(all) let error: Error? init(status: ResultStatus, error: Error) { self.status = status @@ -408,7 +408,7 @@ blockchain.commitBlock() A contract can be deployed using the `deployContract` function of the `Blockchain`. ```cadence -let contractCode = "pub contract Foo{ pub let msg: String; init(_ msg: String){ self.msg = msg } pub fun sayHello(): String { return self.msg } }" +let contractCode = "access(all) contract Foo{ access(all) let msg: String; init(_ msg: String){ self.msg = msg } access(all) fun sayHello(): String { return self.msg } }" let err = blockchain.deployContract( name: "Foo", @@ -437,8 +437,8 @@ The `Configuration` struct consists of a mapping of import locations to their ad /// Configuration to be used by the blockchain. /// Can be used to set the address mapping. /// -pub struct Configuration { - pub let addresses: {String: Address} +access(all) struct Configuration { + access(all) let addresses: {String: Address} init(addresses: {String: Address}) { self.addresses = addresses @@ -461,16 +461,16 @@ The import locations for the two contracts can be specified using the two placeh import FooContract from "FooContract" import BarContract from "BarContract" -pub fun main() { +access(all) fun main() { // do something } ``` Then, before executing the script, the address mapping can be specified as follows: ```cadence -pub var blockchain = Test.newEmulatorBlockchain() -pub var accounts: [Test.Account] = [] +access(all) var blockchain = Test.newEmulatorBlockchain() +access(all) var accounts: [Test.Account] = [] -pub fun setup() { +access(all) fun setup() { // Create accounts in the blockchain. let acct1 = blockchain.createAccount() @@ -500,8 +500,8 @@ Contains a message indicating why the operation failed. ```cadence // Error is returned if something has gone wrong. // -pub struct Error { - pub let message: String +access(all) struct Error { + access(all) let message: String init(_ message: String) { self.message = message diff --git a/docs/cadence/tutorial/02-hello-world.mdx b/docs/cadence/tutorial/02-hello-world.mdx index a8bffa9985..53b9fb4a45 100644 --- a/docs/cadence/tutorial/02-hello-world.mdx +++ b/docs/cadence/tutorial/02-hello-world.mdx @@ -143,12 +143,12 @@ Open the Account `0x01` tab with the file called ```cadence HelloWorld.cdc // HelloWorld.cdc // -pub contract HelloWorld { +access(all) contract HelloWorld { // Declare a public field of type String. // // All fields must be initialized in the init() function. - pub let greeting: String + access(all) let greeting: String // The init() function is required if the contract contains any fields. init() { @@ -156,19 +156,19 @@ pub contract HelloWorld { } // Public function that returns our friendly greeting! - pub fun hello(): String { + access(all) fun hello(): String { return self.greeting } } ``` -The line `pub contract HelloWorld ` declares a contract that is accessible in all scopes (public). -It's followed by `pub let greeting: String` which declares a state constant (`let`) of type `String` that is accessible in all scopes(`pub`). +The line `access(all) contract HelloWorld ` declares a contract that is accessible in all scopes (public). +It's followed by `access(all) let greeting: String` which declares a state constant (`let`) of type `String` that is accessible in all scopes(`access(all)`). You would have used `var` to declare a variable, which means that the value can be changed later on instead of remaining constant like with `let`. -You can use `access(all)` and the `pub` keyword interchangeably. +You can use `access(all)` and the `access(all)` keyword interchangeably. They are both examples of an access control specification that means an interface can be accessed in all scopes, but not written to in all scopes. For more information about the different levels of access control permitted in Cadence, refer to the [Access Control section of the language reference](../language/access-control). @@ -180,7 +180,7 @@ In the above example, the initializer sets the `greeting` field to `"Hello, Worl The last part of our `HelloWorld` contract is a public function called `hello()`. This declaration returns a value of type `String`. Anyone who imports this contract in their transaction or script can read the public fields, -use the public types, and call the public contract functions; i.e. the ones that have `pub` or `access(all)` specified. +use the public types, and call the public contract functions; i.e. the ones that have `access(all)` or `access(all)` specified. Soon you'll deploy this contract to your account and run a transaction that calls its function, but first, let's look at what accounts and transactions are. diff --git a/docs/cadence/tutorial/03-resources.mdx b/docs/cadence/tutorial/03-resources.mdx index 2346a3ddf3..dcc373b4d9 100644 --- a/docs/cadence/tutorial/03-resources.mdx +++ b/docs/cadence/tutorial/03-resources.mdx @@ -53,8 +53,8 @@ Resources are one of Cadence's defining features. In Cadence, resources are a composite type like a struct or a class, but with some special rules. Here is an example definition of a resource: ```cadence -pub resource Money { - pub let balance: Int +access(all) resource Money { + access(all) let balance: Int init() { self.balance = 0 @@ -103,21 +103,21 @@ Open the Account `0x01` tab with file named `HelloWorldResource.cdc`.
```cadence HelloWorldResource.cdc -pub contract HelloWorld { +access(all) contract HelloWorld { // Declare a resource that only includes one function. - pub resource HelloAsset { + access(all) resource HelloAsset { // A transaction can call this function to get the "Hello, World!" // message from the resource. - pub fun hello(): String { + access(all) fun hello(): String { return "Hello, World!" } } // We're going to use the built-in create function to create a new instance // of the HelloAsset resource - pub fun createHelloAsset(): @HelloAsset { + access(all) fun createHelloAsset(): @HelloAsset { return <-create HelloAsset() } @@ -135,8 +135,8 @@ Deploy this code to account `0x01` using the `Deploy` button. We start by declaring a new `HelloWorld` contract in account `0x01`, inside this new `HelloWorld` contract we: -1. Declare the resource `HelloAsset` with public scope `pub` -2. Declare the resource function `hello()` inside `HelloAsset` with public scope `pub` +1. Declare the resource `HelloAsset` with public scope `access(all)` +2. Declare the resource function `hello()` inside `HelloAsset` with public scope `access(all)` 3. Declare the contract function `createHelloAsset()` which `create`s a `HelloAsset` resource 4. The `createHelloAsset()` function uses the move operator (`<-`) to return the resource @@ -154,8 +154,8 @@ Let's walk through this contract in more detail, starting with the resource. Resources are one of the most important things that Cadence introduces to the smart contract design experience: ```cadence -pub resource HelloAsset { - pub fun hello(): String { +access(all) resource HelloAsset { + access(all) fun hello(): String { return "Hello, World!" } } @@ -200,7 +200,7 @@ This prevents anyone from being able to create arbitrary amounts of resource obj In this example, we declared a function that can create `HelloAsset` resources: ```cadence -pub fun createHelloAsset(): @HelloAsset { +access(all) fun createHelloAsset(): @HelloAsset { return <-create HelloAsset() } ``` diff --git a/docs/cadence/tutorial/04-capabilities.mdx b/docs/cadence/tutorial/04-capabilities.mdx index c5f17aeb19..1c8df317c1 100644 --- a/docs/cadence/tutorial/04-capabilities.mdx +++ b/docs/cadence/tutorial/04-capabilities.mdx @@ -88,21 +88,21 @@ Open the Account `0x01` tab with file named `HelloWorldResource.cdc`.
```cadence HelloWorldResource-2.cdc -pub contract HelloWorld { +access(all) contract HelloWorld { // Declare a resource that only includes one function. - pub resource HelloAsset { + access(all) resource HelloAsset { // A transaction can call this function to get the "Hello, World!" // message from the resource. - pub fun hello(): String { + access(all) fun hello(): String { return "Hello, World!" } } // We're going to use the built-in create function to create a new instance // of the HelloAsset resource - pub fun createHelloAsset(): @HelloAsset { + access(all) fun createHelloAsset(): @HelloAsset { return <-create HelloAsset() } @@ -253,7 +253,7 @@ The `HelloAsset` object is stored in `/storage/HelloAssetTutorial`, which only t They want any user in the network to be able to call the `hello()` method. So they make a public capability in `/public/HelloAssetTutorial`. To create a capability, we use the `AuthAccount.link` method to link a new capability to an object in storage. -The type contained in `<>` is the restricted reference type that the capability represents. +The type contained in `<>` is the reference type that the capability represents. The capability says that whoever borrows a reference from this capability can only have access to the fields and methods that are specified by the type in `<>`. The specified type has to be a subtype of the type of the object being linked to, @@ -317,7 +317,7 @@ In the next section, we look at how capabilities can expand the access a script A script is a very simple transaction type in Cadence that cannot perform any writes to the blockchain and can only read the state of an account or contract. -To execute a script, write a function called `pub fun main()`. +To execute a script, write a function called `access(all) fun main()`. You can click the execute script button to run the script. The result of the script will be printed to the console output. @@ -334,7 +334,7 @@ Open the file `Script1.cdc`. ```cadence Script1.cdc import HelloWorld from 0x01 -pub fun main() { +access(all) fun main() { // Cadence code can get an account's public account object // by using the getAccount() built-in function. diff --git a/docs/cadence/tutorial/05-non-fungible-tokens-1.mdx b/docs/cadence/tutorial/05-non-fungible-tokens-1.mdx index bf0c6d8ed7..6eba36195b 100644 --- a/docs/cadence/tutorial/05-non-fungible-tokens-1.mdx +++ b/docs/cadence/tutorial/05-non-fungible-tokens-1.mdx @@ -158,15 +158,15 @@ Open Account `0x01` to see `BasicNFT.cdc`. ```cadence BasicNFT.cdc -pub contract BasicNFT { +access(all) contract BasicNFT { // Declare the NFT resource type - pub resource NFT { + access(all) resource NFT { // The unique ID that differentiates each NFT - pub let id: UInt64 + access(all) let id: UInt64 // String mapping to hold metadata - pub var metadata: {String: String} + access(all) var metadata: {String: String} // Initialize both fields in the init function init(initID: UInt64) { @@ -176,7 +176,7 @@ pub contract BasicNFT { } // Function to create a new NFT - pub fun createNFT(id: UInt64): @NFT { + access(all) fun createNFT(id: UInt64): @NFT { return <-create NFT(initID: id) } diff --git a/docs/cadence/tutorial/05-non-fungible-tokens-2.mdx b/docs/cadence/tutorial/05-non-fungible-tokens-2.mdx index 7f376ae409..478164fe41 100644 --- a/docs/cadence/tutorial/05-non-fungible-tokens-2.mdx +++ b/docs/cadence/tutorial/05-non-fungible-tokens-2.mdx @@ -82,7 +82,7 @@ This example uses a [**Dictionary**: a mutable, unordered collection of key-valu ```cadence // Keys are `Int` // Values are `NFT` -pub let myNFTs: @{Int: NFT} +access(all) let myNFTs: @{Int: NFT} ``` In a dictionary, all keys must have the same type, and all values must have the same type. @@ -137,22 +137,22 @@ It contains what was already in `BasicNFT.cdc` plus additional resource declarat // // Learn more about non-fungible tokens in this tutorial: https://developers.flow.com/cadence/tutorial/non-fungible-tokens-1 -pub contract ExampleNFT { +access(all) contract ExampleNFT { // Declare Path constants so paths do not have to be hardcoded // in transactions and scripts - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - pub let MinterStoragePath: StoragePath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + access(all) let MinterStoragePath: StoragePath // Tracks the unique IDs of the NFT - pub var idCount: UInt64 + access(all) var idCount: UInt64 // Declare the NFT resource type - pub resource NFT { + access(all) resource NFT { // The unique ID that differentiates each NFT - pub let id: UInt64 + access(all) let id: UInt64 // Initialize both fields in the init function init(initID: UInt64) { @@ -164,21 +164,21 @@ pub contract ExampleNFT { // to create public, restricted references to their NFT Collection. // They would use this to publicly expose only the deposit, getIDs, // and idExists fields in their Collection - pub resource interface NFTReceiver { + access(all) resource interface NFTReceiver { - pub fun deposit(token: @NFT) + access(all) fun deposit(token: @NFT) - pub fun getIDs(): [UInt64] + access(all) fun getIDs(): [UInt64] - pub fun idExists(id: UInt64): Bool + access(all) fun idExists(id: UInt64): Bool } // The definition of the Collection resource that // holds the NFTs that a user owns - pub resource Collection: NFTReceiver { + access(all) resource Collection: NFTReceiver { // dictionary of NFT conforming tokens // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NFT} + access(all) var ownedNFTs: @{UInt64: NFT} // Initialize the NFTs field to an empty collection init () { @@ -189,7 +189,7 @@ pub contract ExampleNFT { // // Function that removes an NFT from the collection // and moves it to the calling context - pub fun withdraw(withdrawID: UInt64): @NFT { + access(all) fun withdraw(withdrawID: UInt64): @NFT { // If the NFT isn't found, the transaction panics and reverts let token <- self.ownedNFTs.remove(key: withdrawID)! @@ -200,7 +200,7 @@ pub contract ExampleNFT { // // Function that takes a NFT as an argument and // adds it to the collections dictionary - pub fun deposit(token: @NFT) { + access(all) fun deposit(token: @NFT) { // add the new token to the dictionary with a force assignment // if there is already a value at that key, it will fail and revert self.ownedNFTs[token.id] <-! token @@ -208,12 +208,12 @@ pub contract ExampleNFT { // idExists checks to see if a NFT // with the given ID exists in the collection - pub fun idExists(id: UInt64): Bool { + access(all) fun idExists(id: UInt64): Bool { return self.ownedNFTs[id] != nil } // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + access(all) fun getIDs(): [UInt64] { return self.ownedNFTs.keys } @@ -223,7 +223,7 @@ pub contract ExampleNFT { } // creates a new empty Collection resource and returns it - pub fun createEmptyCollection(): @Collection { + access(all) fun createEmptyCollection(): @Collection { return <- create Collection() } @@ -231,7 +231,7 @@ pub contract ExampleNFT { // // Function that mints a new NFT with a new ID // and returns it to the caller - pub fun mintNFT(): @NFT { + access(all) fun mintNFT(): @NFT { // create a new NFT var newNFT <- create NFT(initID: self.idCount) @@ -317,7 +317,7 @@ of the keys of the dictionary using the built-in `keys` function. ```cadence // getIDs returns an array of the IDs that are in the collection -pub fun getIDs(): [UInt64] { +access(all) fun getIDs(): [UInt64] { return self.ownedNFTs.keys } ``` @@ -373,13 +373,13 @@ is only accessible by its owner. To give external accounts access to the `deposi the `getIDs` function, and the `idExists` function, the owner creates an interface that only includes those fields: ```cadence -pub resource interface NFTReceiver { +access(all) resource interface NFTReceiver { - pub fun deposit(token: @NFT) + access(all) fun deposit(token: @NFT) - pub fun getIDs(): [UInt64] + access(all) fun getIDs(): [UInt64] - pub fun idExists(id: UInt64): Bool + access(all) fun idExists(id: UInt64): Bool } ``` @@ -424,7 +424,7 @@ Open the script file named `Print 0x01 NFTs`. import ExampleNFT from 0x01 // Print the NFTs owned by account 0x01. -pub fun main() { +access(all) fun main() { // Get the public account object for account 0x01 let nftOwner = getAccount(0x01) @@ -519,7 +519,7 @@ This prints a list of the NFTs that account `0x01` owns. import ExampleNFT from 0x01 // Print the NFTs owned by account 0x01. -pub fun main() { +access(all) fun main() { // Get the public account object for account 0x01 let nftOwner = getAccount(0x01) @@ -642,7 +642,7 @@ Execute the script `Print all NFTs` to see the tokens in each account: import ExampleNFT from 0x01 // Print the NFTs owned by accounts 0x01 and 0x02. -pub fun main() { +access(all) fun main() { // Get both public account objects let account1 = getAccount(0x01) diff --git a/docs/cadence/tutorial/06-fungible-tokens.mdx b/docs/cadence/tutorial/06-fungible-tokens.mdx index 989ad1ce8b..25640c9a02 100644 --- a/docs/cadence/tutorial/06-fungible-tokens.mdx +++ b/docs/cadence/tutorial/06-fungible-tokens.mdx @@ -46,7 +46,7 @@ contract LedgerToken { // Transfer tokens from one user to the other // by updating their balances in the central ledger - pub fun transfer(from: Address, to: Address, amount: UFix64) { + access(all) fun transfer(from: Address, to: Address, amount: UFix64) { balances[from] = balances[from] - amount balances[to] = balances[to] + amount } @@ -194,23 +194,23 @@ It is important to remember that each account stores only a copy of the `Vault` The `ExampleToken` contract only needs to be stored in the initial account that manages the token definitions. ```cadence Token.cdc -pub resource Vault: Provider, Receiver { +access(all) resource Vault: Provider, Receiver { // Balance of a user's Vault // we use unsigned fixed point numbers for balances // because they can represent decimals and do not allow negative values - pub var balance: UFix64 + access(all) var balance: UFix64 init(balance: UFix64) { self.balance = balance } - pub fun withdraw(amount: UFix64): @Vault { + access(all) fun withdraw(amount: UFix64): @Vault { self.balance = self.balance - amount return <-create Vault(balance: amount) } - pub fun deposit(from: @Vault) { + access(all) fun deposit(from: @Vault) { self.balance = self.balance + from.balance destroy from } @@ -229,7 +229,7 @@ The language requires that the initialization function `init`, which is only run // Balance of a user's Vault // we use unsigned fixed-point integers for balances because they do not require the // concept of a negative number and allow for more clear precision -pub var balance: UFix64 +access(all) var balance: UFix64 init(balance: UFix64) { self.balance = balance @@ -244,7 +244,7 @@ the balance field is no longer initialized. Then, the deposit function is available for any account to transfer tokens to. ```cadence -pub fun deposit(from: @Vault) { +access(all) fun deposit(from: @Vault) { self.balance = self.balance + from.balance destroy from } @@ -263,7 +263,7 @@ When interacting with resources, you use the `@` symbol to specify the type, and when moving the resource, such as assigning the resource, when passing it as an argument to a function, or when returning it from a function. ```cadence -pub fun withdraw(amount: UInt64): @Vault { +access(all) fun withdraw(amount: UInt64): @Vault { ``` This `@` symbol is required when specifying a resource **type** for a field, an argument, or a return value. @@ -332,7 +332,7 @@ open and should see the code below. // This is a basic implementation of a Fungible Token and is NOT meant to be used in production // See the Flow Fungible Token standard for real examples: https://github.com/onflow/flow-ft -pub contract BasicToken { +access(all) contract BasicToken { // Vault // @@ -346,10 +346,10 @@ pub contract BasicToken { // out of thin air. A special Minter resource or constructor function needs to be defined to mint // new tokens. // - pub resource Vault { + access(all) resource Vault { // keeps track of the total balance of the account's tokens - pub var balance: UFix64 + access(all) var balance: UFix64 // initialize the balance at resource creation time init(balance: UFix64) { @@ -366,7 +366,7 @@ pub contract BasicToken { // created Vault to the context that called so it can be deposited // elsewhere. // - pub fun withdraw(amount: UFix64): @Vault { + access(all) fun withdraw(amount: UFix64): @Vault { self.balance = self.balance - amount return <-create Vault(balance: amount) } @@ -379,7 +379,7 @@ pub contract BasicToken { // It is allowed to destroy the sent Vault because the Vault // was a temporary holder of the tokens. The Vault's balance has // been consumed and therefore can be destroyed. - pub fun deposit(from: @Vault) { + access(all) fun deposit(from: @Vault) { self.balance = self.balance + from.balance destroy from } @@ -392,7 +392,7 @@ pub contract BasicToken { // and store the returned Vault in their storage in order to allow their // account to be able to receive deposits of this token type. // - pub fun createVault(): @Vault { + access(all) fun createVault(): @Vault { return <-create Vault(balance: 30.0) } @@ -556,8 +556,8 @@ Here is an example of how interfaces for the `Vault` resource we defined above w // Interface that enforces the requirements for withdrawing // tokens from the implementing type // -pub resource interface Provider { - pub fun withdraw(amount: UFix64): @Vault { +access(all) resource interface Provider { + access(all) fun withdraw(amount: UFix64): @Vault { post { result.balance == amount: "Withdrawal amount must be the same as the balance of the withdrawn Vault" @@ -567,19 +567,19 @@ pub resource interface Provider { // Interface that enforces the requirements for depositing // tokens into the implementing type // -pub resource interface Receiver { +access(all) resource interface Receiver { // There aren't any meaningful requirements for only a deposit function // but this still shows that the deposit function is required in an implementation. - pub fun deposit(from: @Vault) + access(all) fun deposit(from: @Vault) } // Balance // // Interface that specifies a public `balance` field for the vault // -pub resource interface Balance { - pub var balance: UFix64 +access(all) resource interface Balance { + access(all) var balance: UFix64 } ``` @@ -589,7 +589,7 @@ and that the function arguments, fields of the resource, and any return value ar These interfaces can be stored on-chain and imported into other contracts or resources so that these requirements are enforced by an immutable source of truth that is not susceptible to human error. -You can also see that functions and fields have the `pub` keyword next to them. +You can also see that functions and fields have the `access(all)` keyword next to them. We have explicitly defined these fields as public because all fields and functions in Cadence are private by default, meaning that the local scope can only access them. Users have to make parts of their owned types explicitly public. This helps prevent types from having unintentionally public code. @@ -662,7 +662,7 @@ We already use this pattern in the `VaultMinter` resource in the `mintTokens` fu // using their `Receiver` capability. // We say `&AnyResource{Receiver}` to say that the recipient can be any resource // as long as it implements the ExampleToken.Receiver interface -pub fun mintTokens(amount: UFix64, recipient: Capability<&AnyResource{Receiver}>) { +access(all) fun mintTokens(amount: UFix64, recipient: Capability<&AnyResource{Receiver}>) { let recipientRef = recipient.borrow() ?? panic("Could not borrow a receiver reference to the vault") @@ -978,7 +978,7 @@ Open the script named `Get Balances` in the scripts pane. import FungibleToken from 0x02 // This script reads the Vault balances of two accounts. -pub fun main() { +access(all) fun main() { // Get the accounts' public account objects let acct2 = getAccount(0x02) let acct3 = getAccount(0x03) diff --git a/docs/cadence/tutorial/07-marketplace-setup.mdx b/docs/cadence/tutorial/07-marketplace-setup.mdx index 3b018dd166..49ce2fda3c 100644 --- a/docs/cadence/tutorial/07-marketplace-setup.mdx +++ b/docs/cadence/tutorial/07-marketplace-setup.mdx @@ -177,7 +177,7 @@ import ExampleNFT from 0x02 // // Account 0x01: Vault Balance = 40, NFT.id = 1 // Account 0x02: Vault Balance = 20, No NFTs -pub fun main() { +access(all) fun main() { // Get the accounts' public account objects let acct1 = getAccount(0x01) let acct2 = getAccount(0x02) diff --git a/docs/cadence/tutorial/08-marketplace-compose.mdx b/docs/cadence/tutorial/08-marketplace-compose.mdx index 2762cc26b0..3cbcd9be77 100644 --- a/docs/cadence/tutorial/08-marketplace-compose.mdx +++ b/docs/cadence/tutorial/08-marketplace-compose.mdx @@ -110,7 +110,7 @@ import ExampleNFT from 0x02 // // Account 0x01: Vault Balance = 40, NFT.id = 1 // Account 0x02: Vault Balance = 20, No NFTs -pub fun main() { +access(all) fun main() { // Get the accounts' public account objects let acct1 = getAccount(0x01) let acct2 = getAccount(0x02) @@ -219,27 +219,27 @@ import ExampleNFT from 0x02 // // https://github.com/onflow/nft-storefront -pub contract ExampleMarketplace { +access(all) contract ExampleMarketplace { // Event that is emitted when a new NFT is put up for sale - pub event ForSale(id: UInt64, price: UFix64, owner: Address?) + access(all) event ForSale(id: UInt64, price: UFix64, owner: Address?) // Event that is emitted when the price of an NFT changes - pub event PriceChanged(id: UInt64, newPrice: UFix64, owner: Address?) + access(all) event PriceChanged(id: UInt64, newPrice: UFix64, owner: Address?) // Event that is emitted when a token is purchased - pub event TokenPurchased(id: UInt64, price: UFix64, seller: Address?, buyer: Address?) + access(all) event TokenPurchased(id: UInt64, price: UFix64, seller: Address?, buyer: Address?) // Event that is emitted when a seller withdraws their NFT from the sale - pub event SaleCanceled(id: UInt64, seller: Address?) + access(all) event SaleCanceled(id: UInt64, seller: Address?) // Interface that users will publish for their Sale collection // that only exposes the methods that are supposed to be public // - pub resource interface SalePublic { - pub fun purchase(tokenID: UInt64, recipient: Capability<&AnyResource{ExampleNFT.NFTReceiver}>, buyTokens: @ExampleToken.Vault) - pub fun idPrice(tokenID: UInt64): UFix64? - pub fun getIDs(): [UInt64] + access(all) resource interface SalePublic { + access(all) fun purchase(tokenID: UInt64, recipient: Capability<&AnyResource{ExampleNFT.NFTReceiver}>, buyTokens: @ExampleToken.Vault) + access(all) fun idPrice(tokenID: UInt64): UFix64? + access(all) fun getIDs(): [UInt64] } // SaleCollection @@ -247,7 +247,7 @@ pub contract ExampleMarketplace { // NFT Collection object that allows a user to put their NFT up for sale // where others can send fungible tokens to purchase it // - pub resource SaleCollection: SalePublic { + access(all) resource SaleCollection: SalePublic { /// A capability for the owner's collection access(self) var ownerCollection: Capability<&ExampleNFT.Collection> @@ -278,7 +278,7 @@ pub contract ExampleMarketplace { } // cancelSale gives the owner the opportunity to cancel a sale in the collection - pub fun cancelSale(tokenID: UInt64) { + access(all) fun cancelSale(tokenID: UInt64) { // remove the price self.prices.remove(key: tokenID) self.prices[tokenID] = nil @@ -287,7 +287,7 @@ pub contract ExampleMarketplace { } // listForSale lists an NFT for sale in this collection - pub fun listForSale(tokenID: UInt64, price: UFix64) { + access(all) fun listForSale(tokenID: UInt64, price: UFix64) { pre { self.ownerCollection.borrow()!.idExists(id: tokenID): "NFT to be listed does not exist in the owner's collection" @@ -299,14 +299,14 @@ pub contract ExampleMarketplace { } // changePrice changes the price of a token that is currently for sale - pub fun changePrice(tokenID: UInt64, newPrice: UFix64) { + access(all) fun changePrice(tokenID: UInt64, newPrice: UFix64) { self.prices[tokenID] = newPrice emit PriceChanged(id: tokenID, newPrice: newPrice, owner: self.owner?.address) } // purchase lets a user send tokens to purchase an NFT that is for sale - pub fun purchase(tokenID: UInt64, recipient: Capability<&AnyResource{ExampleNFT.NFTReceiver}>, buyTokens: @ExampleToken.Vault) { + access(all) fun purchase(tokenID: UInt64, recipient: Capability<&AnyResource{ExampleNFT.NFTReceiver}>, buyTokens: @ExampleToken.Vault) { pre { self.prices[tokenID] != nil: "No token matching this ID for sale!" @@ -338,18 +338,18 @@ pub contract ExampleMarketplace { } // idPrice returns the price of a specific token in the sale - pub fun idPrice(tokenID: UInt64): UFix64? { + access(all) fun idPrice(tokenID: UInt64): UFix64? { return self.prices[tokenID] } // getIDs returns an array of token IDs that are for sale - pub fun getIDs(): [UInt64] { + access(all) fun getIDs(): [UInt64] { return self.prices.keys } } // createCollection returns a new collection resource to the caller - pub fun createSaleCollection(ownerCollection: Capability<&ExampleNFT.Collection>, + access(all) fun createSaleCollection(ownerCollection: Capability<&ExampleNFT.Collection>, ownerVault: Capability<&AnyResource{ExampleToken.Receiver}>): @SaleCollection { return <- create SaleCollection(ownerCollection: ownerCollection, ownerVault: ownerVault) } @@ -365,7 +365,7 @@ that was explained in [Non-Fungible Tokens](./05-non-fungible-tokens-1.mdx), wit Then, another user can call the `purchase` method, sending their `ExampleToken.Vault` that contains the currency they are using to make the purchase. The buyer also includes a capability to their NFT `ExampleNFT.Collection` so that the purchased token can be immediately deposited into their collection when the purchase is made. -- This marketplace contract stores a capability: `pub let ownerVault: Capability<&AnyResource{FungibleToken.Receiver}>`. +- This marketplace contract stores a capability: `access(all) let ownerVault: Capability<&AnyResource{FungibleToken.Receiver}>`. The owner of the sale saves a capability to their Fungible Token `Receiver` within the sale. This allows the sale resource to be able to immediately deposit the currency that was used to buy the NFT into the owners `Vault` when a purchase is made. @@ -374,16 +374,16 @@ that was explained in [Non-Fungible Tokens](./05-non-fungible-tokens-1.mdx), wit ```cadence // Event that is emitted when a new NFT is put up for sale - pub event ForSale(id: UInt64, price: UFix64, owner: Address?) + access(all) event ForSale(id: UInt64, price: UFix64, owner: Address?) // Event that is emitted when the price of an NFT changes - pub event PriceChanged(id: UInt64, newPrice: UFix64, owner: Address?) + access(all) event PriceChanged(id: UInt64, newPrice: UFix64, owner: Address?) // Event that is emitted when a token is purchased - pub event TokenPurchased(id: UInt64, price: UFix64, seller: Address?, buyer: Address?) + access(all) event TokenPurchased(id: UInt64, price: UFix64, seller: Address?, buyer: Address?) // Event that is emitted when a seller withdraws their NFT from the sale - pub event SaleCanceled(id: UInt64, seller: Address?) + access(all) event SaleCanceled(id: UInt64, seller: Address?) ``` This contract has a few new features and concepts that are important to cover: @@ -401,7 +401,7 @@ when getting information about their users' accounts or generating analytics. Events are declared by indicating [the access level](../language/access-control), `event`, and the name and parameters of the event, like a function declaration: ```cadence -pub event ForSale(id: UInt64, price: UFix64, owner: Address?) +access(all) event ForSale(id: UInt64, price: UFix64, owner: Address?) ``` Events cannot modify state at all; they indicate when important actions happen in the smart contract. @@ -489,7 +489,7 @@ One last piece to consider about capabilities is the decision about when to use This tutorial used to have the `SaleCollection` directly store the NFTs that were for sale, like so: ```cadence -pub resource SaleCollection: SalePublic { +access(all) resource SaleCollection: SalePublic { /// Dictionary of NFT objects for sale /// Maps ID to NFT resource object @@ -585,7 +585,7 @@ import ExampleNFT from 0x02 import ExampleMarketplace from 0x03 // This script prints the NFTs that account 0x01 has for sale. -pub fun main() { +access(all) fun main() { // Get the public account object for account 0x01 let account1 = getAccount(0x01) @@ -713,7 +713,7 @@ import ExampleMarketplace from 0x03 // // Account 1: Vault balance = 50, No NFTs // Account 2: Vault balance = 10, NFT ID=1 -pub fun main() { +access(all) fun main() { // Get the accounts' public account objects let acct1 = getAccount(0x01) let acct2 = getAccount(0x02) @@ -806,14 +806,14 @@ If we wanted to build a central marketplace on-chain, we could use a contract th ```cadence CentralMarketplace.cdc // Marketplace would be the central contract where people can post their sale // references so that anyone can access them -pub contract Marketplace { +access(all) contract Marketplace { // Data structure to store active sales - pub var tokensForSale: {Address: Capability<&SaleCollection>)} + access(all) var tokensForSale: {Address: Capability<&SaleCollection>)} // listSaleCollection lists a users sale reference in the array // and returns the index of the sale so that users can know // how to remove it from the marketplace - pub fun listSaleCollection(collection: Capability<&SaleCollection>) { + access(all) fun listSaleCollection(collection: Capability<&SaleCollection>) { let saleRef = collection.borrow() ?? panic("Invalid sale collection capability") @@ -822,7 +822,7 @@ pub contract Marketplace { // removeSaleCollection removes a user's sale from the array // of sale references - pub fun removeSaleCollection(owner: Address) { + access(all) fun removeSaleCollection(owner: Address) { self.tokensForSale[owner] = nil } diff --git a/docs/cadence/tutorial/09-voting.mdx b/docs/cadence/tutorial/09-voting.mdx index d4d6f83f48..6e96600910 100644 --- a/docs/cadence/tutorial/09-voting.mdx +++ b/docs/cadence/tutorial/09-voting.mdx @@ -86,25 +86,25 @@ The deployed contract should have the following contents: * */ -pub contract ApprovalVoting { +access(all) contract ApprovalVoting { //list of proposals to be approved - pub var proposals: [String] + access(all) var proposals: [String] // number of votes per proposal - pub let votes: {Int: Int} + access(all) let votes: {Int: Int} // This is the resource that is issued to users. // When a user gets a Ballot object, they call the `vote` function // to include their votes, and then cast it in the smart contract // using the `cast` function to have their vote included in the polling - pub resource Ballot { + access(all) resource Ballot { // array of all the proposals - pub let proposals: [String] + access(all) let proposals: [String] // corresponds to an array index in proposals after a vote - pub var choices: {Int: Bool} + access(all) var choices: {Int: Bool} init() { self.proposals = ApprovalVoting.proposals @@ -120,7 +120,7 @@ pub contract ApprovalVoting { // modifies the ballot // to indicate which proposals it is voting for - pub fun vote(proposal: Int) { + access(all) fun vote(proposal: Int) { pre { self.proposals[proposal] != nil: "Cannot vote for a proposal that doesn't exist" } @@ -130,10 +130,10 @@ pub contract ApprovalVoting { // Resource that the Administrator of the vote controls to // initialize the proposals and to pass out ballot resources to voters - pub resource Administrator { + access(all) resource Administrator { // function to initialize all the proposals for the voting - pub fun initializeProposals(_ proposals: [String]) { + access(all) fun initializeProposals(_ proposals: [String]) { pre { ApprovalVoting.proposals.length == 0: "Proposals can only be initialized once" proposals.length > 0: "Cannot initialize with no proposals" @@ -150,14 +150,14 @@ pub contract ApprovalVoting { // The admin calls this function to create a new Ballot // that can be transferred to another user - pub fun issueBallot(): @Ballot { + access(all) fun issueBallot(): @Ballot { return <-create Ballot() } } // A user moves their ballot to this function in the contract where // its votes are tallied and the ballot is destroyed - pub fun cast(ballot: @Ballot) { + access(all) fun cast(ballot: @Ballot) { var index = 0 // look through the ballot while index < self.proposals.length { @@ -187,7 +187,7 @@ This contract implements a simple voting mechanism where an `Administrator` can ```cadence // function to initialize all the proposals for the voting -pub fun initializeProposals(_ proposals: [String]) { +access(all) fun initializeProposals(_ proposals: [String]) { pre { ApprovalVoting.proposals.length == 0: "Proposals can only be initialized once" proposals.length > 0: "Cannot initialize with no proposals" @@ -206,7 +206,7 @@ pub fun initializeProposals(_ proposals: [String]) { Then they can give `Ballot` resources to other accounts. The other accounts can record their votes on their `Ballot` resource by calling the `vote` function. ```cadence -pub fun vote(proposal: Int) { +access(all) fun vote(proposal: Int) { pre { self.proposals[proposal] != nil: "Cannot vote for a proposal that doesn't exist" } @@ -219,7 +219,7 @@ After a user has voted, they submit their vote to the central smart contract by ```cadence // A user moves their ballot to this function in the contract where // its votes are tallied and the ballot is destroyed -pub fun cast(ballot: @Ballot) { +access(all) fun cast(ballot: @Ballot) { var index = 0 // look through the ballot while index < self.proposals.length { @@ -397,7 +397,7 @@ import ApprovalVoting from 0x01 // This script allows anyone to read the tallied votes for each proposal // -pub fun main() { +access(all) fun main() { // Access the public fields of the contract to log // the proposal names and vote counts diff --git a/docs/cadence/tutorial/10-resources-compose.mdx b/docs/cadence/tutorial/10-resources-compose.mdx index 9cd7c01d2b..15c102e890 100644 --- a/docs/cadence/tutorial/10-resources-compose.mdx +++ b/docs/cadence/tutorial/10-resources-compose.mdx @@ -92,12 +92,12 @@ The deployed contract should have the following contents: // support even more powerful versions of this. // -pub contract KittyVerse { +access(all) contract KittyVerse { // KittyHat is a special resource type that represents a hat - pub resource KittyHat { - pub let id: Int - pub let name: String + access(all) resource KittyHat { + access(all) let id: Int + access(all) let name: String init(id: Int, name: String) { self.id = id @@ -105,7 +105,7 @@ pub contract KittyVerse { } // An example of a function someone might put in their hat resource - pub fun tipHat(): String { + access(all) fun tipHat(): String { if self.name == "Cowboy Hat" { return "Howdy Y'all" } else if self.name == "Top Hat" { @@ -117,35 +117,35 @@ pub contract KittyVerse { } // Create a new hat - pub fun createHat(id: Int, name: String): @KittyHat { + access(all) fun createHat(id: Int, name: String): @KittyHat { return <-create KittyHat(id: id, name: name) } - pub resource Kitty { + access(all) resource Kitty { - pub let id: Int + access(all) let id: Int // place where the Kitty hats are stored - pub var items: @{String: KittyHat} + access(all) var items: @{String: KittyHat} init(newID: Int) { self.id = newID self.items <- {} } - pub fun getKittyItems(): @{String: KittyHat} { + access(all) fun getKittyItems(): @{String: KittyHat} { var other: @{String:KittyHat} <- {} self.items <-> other return <- other } - pub fun setKittyItems(items: @{String: KittyHat}) { + access(all) fun setKittyItems(items: @{String: KittyHat}) { var other <- items self.items <-> other destroy other } - pub fun removeKittyItem(key: String): @KittyHat? { + access(all) fun removeKittyItem(key: String): @KittyHat? { var removed <- self.items.remove(key: key) return <- removed } @@ -155,7 +155,7 @@ pub contract KittyVerse { } } - pub fun createKitty(): @Kitty { + access(all) fun createKitty(): @Kitty { return <-create Kitty(newID: 1) } @@ -169,7 +169,7 @@ The hats are stored in a variable in the Kitty resource. ```cadence // place where the Kitty hats are stored - pub var items: <-{String: KittyHat} + access(all) var items: <-{String: KittyHat} ``` A Kitty owner can take the hats off the Kitty and transfer them individually. Or the owner can transfer a Kitty that owns a hat, and the hat will go along with the Kitty. diff --git a/docs/concepts/hybrid-custody/get-started.mdx b/docs/concepts/hybrid-custody/get-started.mdx index 292b100605..f804dc7ee6 100644 --- a/docs/concepts/hybrid-custody/get-started.mdx +++ b/docs/concepts/hybrid-custody/get-started.mdx @@ -15,8 +15,9 @@ perspective of a wallet or NFT marketplace. Note that the documentation on Hybrid Custody covers the current state and will likely differ from the final -implementation. Builders should be aware that breaking changes may follow before reaching a final community consensus -on implementation. Interested in shaping the conversation? [Join in!](https://github.com/onflow/flips/pull/72). +implementation. **Testnet is currently out of sync with docs and will be updated shortly.** Builders should be aware +that breaking changes may follow before reaching a final community consensus on implementation. Interested in +contributing? [Check out the source!](https://github.com/onflow/hybrid-custody). diff --git a/docs/concepts/hybrid-custody/guides/account-model.mdx b/docs/concepts/hybrid-custody/guides/account-model.mdx index f020cf87bb..6e938692e1 100644 --- a/docs/concepts/hybrid-custody/guides/account-model.mdx +++ b/docs/concepts/hybrid-custody/guides/account-model.mdx @@ -28,8 +28,9 @@ owned assets. Note that the documentation on Hybrid Custody covers the current state and will likely differ from the final -implementation. Builders should be aware that breaking changes may follow before reaching a final community consensus -on implementation. Interested in shaping the conversation? [Join in!](https://github.com/onflow/flips/pull/72). +implementation. **Testnet is currently out of sync with docs and will be updated shortly.** Builders should be aware +that breaking changes may follow before reaching a final community consensus on implementation. Interested in +contributing? [Check out the source!](https://github.com/onflow/hybrid-custody). diff --git a/docs/concepts/hybrid-custody/guides/linking-accounts.mdx b/docs/concepts/hybrid-custody/guides/linking-accounts.mdx index 1ae3071576..d2f717c6b6 100644 --- a/docs/concepts/hybrid-custody/guides/linking-accounts.mdx +++ b/docs/concepts/hybrid-custody/guides/linking-accounts.mdx @@ -19,8 +19,9 @@ of the dApp account as Account Linking. Note that the documentation on Hybrid Custody covers the current state and will likely differ from the final -implementation. Builders should be aware that breaking changes may follow before reaching a final community consensus -on implementation. Interested in shaping the conversation? [Join in!](https://github.com/onflow/flips/pull/72). +implementation. **Testnet is currently out of sync with docs and will be updated shortly.** Builders should be aware +that breaking changes may follow before reaching a final community consensus on implementation. Interested in +contributing? [Check out the source!](https://github.com/onflow/hybrid-custody). diff --git a/docs/concepts/hybrid-custody/guides/walletless-onboarding.mdx b/docs/concepts/hybrid-custody/guides/walletless-onboarding.mdx index a74e16aefc..9b03fd7bfb 100644 --- a/docs/concepts/hybrid-custody/guides/walletless-onboarding.mdx +++ b/docs/concepts/hybrid-custody/guides/walletless-onboarding.mdx @@ -12,8 +12,9 @@ and self-sovereignty at a user’s own pace. Note that the documentation on Hybrid Custody covers the current state and will likely differ from the final -implementation. Builders should be aware that breaking changes may follow before reaching a final community consensus -on implementation. Interested in shaping the conversation? [Join in!](https://github.com/onflow/flips/pull/72). +implementation. **Testnet is currently out of sync with docs and will be updated shortly.** Builders should be aware +that breaking changes may follow before reaching a final community consensus on implementation. Interested in +contributing? [Check out the source!](https://github.com/onflow/hybrid-custody). diff --git a/docs/concepts/hybrid-custody/index.mdx b/docs/concepts/hybrid-custody/index.mdx index 653bcd1001..5168418f0b 100644 --- a/docs/concepts/hybrid-custody/index.mdx +++ b/docs/concepts/hybrid-custody/index.mdx @@ -19,8 +19,9 @@ The full Hybrid Custody experience is enabled by three core components: Note that the documentation on Hybrid Custody covers the current state and will likely differ from the final -implementation. Builders should be aware that breaking changes may follow before reaching a final community consensus -on implementation. Interested in shaping the conversation? [Join in!](https://github.com/onflow/flips/pull/72). +implementation. **Testnet is currently out of sync with docs and will be updated shortly.** Builders should be aware +that breaking changes may follow before reaching a final community consensus on implementation. Interested in +contributing? [Check out the source!](https://github.com/onflow/hybrid-custody). @@ -35,6 +36,16 @@ on implementation. Interested in shaping the conversation? [Join in!](https://gi 1. Upon linking, the user's main account - now the "parent" account - adds the app created account - now the "child" account - to a collection of all linked child accounts. At this point, Hybrid Custody is reached! +### See it in Action + + + + + +Experience the magic of Hybrid Custody in the arcade demo yourself [here](https://walletless-arcade-game.vercel.app/)! + + + ### Why Care? Hybrid Custody grants users access to their linked child accounts without needing to interface with the child account's diff --git a/docs/concepts/nodes/node-operation/upcoming-sporks.mdx b/docs/concepts/nodes/node-operation/upcoming-sporks.mdx index 33d8612e2f..69e9a31318 100644 --- a/docs/concepts/nodes/node-operation/upcoming-sporks.mdx +++ b/docs/concepts/nodes/node-operation/upcoming-sporks.mdx @@ -9,7 +9,9 @@ The following are the upcoming Spork dates. These dates indicate the intention t | Mainnet Spork Date | Spork Info | Testnet Spork Date | Spork Info | | :----------------- | :---------------------------------------------------| ---------------------------------------------- | ---------- | -| June, 2023 (exact date tbd) | Mainnet 23 | June, 2023 (exact date tbd) | | +| Q3 2023 (date TBD) | | Q3 2023 (date TBD) | | +| June 21, 2023 | Mainnet 23 | Jun 8, 2023 | Devnet46 | +| | | Jun 7, 2023 | Devnet45 | | | | Apr 24, 2023 | Devnet44 | | | | Apr 12, 2023 | Devnet43 | | | | Apr 12, 2023 | Devnet42 | diff --git a/docs/tooling/fcl-dev-wallet/_category_.json b/docs/tooling/fcl-dev-wallet/_category_.json new file mode 100644 index 0000000000..063a88b41f --- /dev/null +++ b/docs/tooling/fcl-dev-wallet/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "FCL Dev Wallet", +} \ No newline at end of file diff --git a/docs/tooling/flow-cadut/_category_.json b/docs/tooling/flow-cadut/_category_.json new file mode 100644 index 0000000000..e0d54d98ee --- /dev/null +++ b/docs/tooling/flow-cadut/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Flow Cadut", +} \ No newline at end of file diff --git a/docs/tooling/flow-cli/run-tests.md b/docs/tooling/flow-cli/run-tests.md index 5bc01f12cb..7b3e3cace9 100644 --- a/docs/tooling/flow-cli/run-tests.md +++ b/docs/tooling/flow-cli/run-tests.md @@ -19,29 +19,30 @@ A simple Cadence script `test_script.cdc`, which has a test case for running a c ```cadence import Test -pub fun testSimpleScript() { - var blockchain = Test.newEmulatorBlockchain() - var result = blockchain.executeScript( +pub let blockchain = Test.newEmulatorBlockchain() + +pub fun testSumOfTwo() { + let scriptResult = blockchain.executeScript( "pub fun main(a: Int, b: Int): Int { return a + b }", [2, 3] ) - - assert(result.status == Test.ResultStatus.succeeded) - assert((result.returnValue! as! Int) == 5) + + Test.expect(scriptResult, Test.beSucceeded()) + + let sum = scriptResult.returnValue! as! Int + Test.assertEqual(5, sum) } ``` -Above test-script can be run with the CLI as follows, and the test results will be printed on the console. +The above test-script can be run with the CLI as follows, and the test results will be printed on the console. ```shell -> flow test test_script.cdc - -Running tests... +$ flow test test_script.cdc Test results: "test_script.cdc" -- PASS: testSimpleScript +- PASS: testSumOfTwo ``` -To learn more about writing tests in Cadence, have a look at the [Cadence testing framework](../../cadence/testing-framework.mdx). +To learn more about writing tests in Cadence, take a look at the [Cadence testing framework](../../cadence/testing-framework.mdx). ## Flags @@ -52,21 +53,45 @@ To learn more about writing tests in Cadence, have a look at the [Cadence testin Use the `cover` flag to calculate coverage report for the code being tested. ```shell -> flow test --cover test_script.cdc - -Running tests... +$ flow test --cover test_script.cdc Test results: "test_script.cdc" -- PASS: testSimpleScript -Coverage: 100.0% of statements +- PASS: testSumOfTwo +Coverage: 96.5% of statements ``` ### Coverage Report File - Flag: `--coverprofile` -- Valid inputs: valid filename -- Default: `coverage.json` +- Valid inputs: valid filename and extension +- Default: `"coverage.json"` + +Use the `coverprofile` to specify the filename where the calculated coverage report is to be written. Supported filename extensions are `.json` and `.lcov`. +```shell +$ flow test --cover test_script.cdc + +$ cat coverage.json + +$ flow test --cover --coverprofile="coverage.lcov" test_script.cdc + +$ cat coverage.lcov +``` + +### Coverage Code Type + +- Flag: `--covercode` +- Valid inputs: `"all"`, `"contracts"` +- Default: `"all"` + +Use the `covercode` flag to calculate coverage report only for certain types of code. A value of `"contracts"` will exclude scripts and transactions from the coverage report. +```shell +$ flow test --cover --covercode="contracts" test_script.cdc + +Test results: "tests/test_script.cdc" +- PASS: testSumOfTwo +There are no statements to cover +``` -Use the `coverprofile` to specify the filename where the calculated coverage report is to be written. +Since we did not use any contracts in our sample test script, there is no coverage percentage to be reported. diff --git a/docs/tooling/nft-catalog/_category_.json b/docs/tooling/nft-catalog/_category_.json new file mode 100644 index 0000000000..894cbf0b4b --- /dev/null +++ b/docs/tooling/nft-catalog/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "NFT Catalog", +} \ No newline at end of file diff --git a/docs/tutorials/DappArchitectures.mdx b/docs/tutorials/DappArchitectures.mdx index 1709e20bf8..0d6e705af7 100644 --- a/docs/tutorials/DappArchitectures.mdx +++ b/docs/tutorials/DappArchitectures.mdx @@ -28,6 +28,7 @@ But sometimes, dapps need to submit transactions to the blockchain from their ba Several SDKs are available to interact with the Flow blockchain, including some that are community-run. The SDKs interact with the access nodes of the Flow blockchain. We recommend maintaining a queuing infrastructure within the dapp’s backend to handle the scalability surge. There are some third-party services available that make managing transactions from the dapp backend easier : +- [QuickNode](https://www.quicknode.com/chains/flow): QuickNode provides a reliable node service to access Flow blockchain. QuickNode's service is designed to optimize developer productivity by eliminating the complexities of setting up and maintaining their own nodes. By leveraging QuickNode's infrastructure, developers can focus on building and deploying decentralized applications (dApps) without the hassle of managing the underlying blockchain infrastructure. - [Alchemy](https://www.alchemy.com/flow): To get a dedicated Flow blockchain access node, Alchemy provides a managed access node service for the Flow dapp developers. Alchemy can allow dapp devs to bypass the rate limits imposed by official Flow access nodes without the operational overhead of running an access node. - [Tatum](https://apidoc.tatum.io/): Tatum provides REST APIs to let dapps perform high-level blockchain operations like creating Flow accounts, sending NFTs, or FLOW tokens to an address.