diff --git a/docusaurus.config.js b/docusaurus.config.js index ff003d5..5cc3108 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -49,9 +49,6 @@ const config = { current: { label: "1.0", }, - 0.42: { - label: "0.42", - }, }, beforeDefaultRemarkPlugins: [ [ @@ -197,12 +194,12 @@ const config = { contextualSearch: true, }, }), - scripts: [ - { - src: '/hotjar.js', - async: true, - }, - ], + scripts: [ + { + src: '/hotjar.js', + async: true, + }, + ], }; module.exports = config; diff --git a/versioned_docs/version-0.42/_category_.yml b/versioned_docs/version-0.42/_category_.yml deleted file mode 100644 index d303479..0000000 --- a/versioned_docs/version-0.42/_category_.yml +++ /dev/null @@ -1,2 +0,0 @@ -label: Cadence -position: 5 diff --git a/versioned_docs/version-0.42/anti-patterns.md b/versioned_docs/version-0.42/anti-patterns.md deleted file mode 100644 index 4c92162..0000000 --- a/versioned_docs/version-0.42/anti-patterns.md +++ /dev/null @@ -1,382 +0,0 @@ ---- -title: Cadence Anti-Patterns -sidebar_position: 7 -sidebar_label: Anti-Patterns ---- - -This is an opinionated list of issues that can be improved if they are found in Cadence code intended for production. - -# Security and Robustness - -## Avoid using `AuthAccount` as a function parameter - -### Problem - -Some may choose to authenticate or perform operations for their users by using the users' account addresses. -In order to do this, a commonly seen case would be to pass the user's `AuthAccount` object -as a parameter to a contract function to use for querying the account or storing objects directly. -This is problematic, as the `AuthAccount` object allows access to ALL private areas of the account, -for example, all of the user's storage, authorized keys, etc., -which provides the opportunity for bad actors to take advantage of. - -### Example: - -```cadence -... -// BAD CODE -// DO NOT COPY - -// Imagine this code is in a contract that uses AuthAccount to authenticate users -// To transfer NFTs - -// They could deploy the contract with an Ethereum-style access control list functionality - -pub fun transferNFT(id: UInt64, owner: AuthAccount) { - assert(owner(id) == owner.address) - - transfer(id) -} - -// But they could upgrade the function to have the same signature -// so it looks like it is doing the same thing, but they could also drain a little bit -// of FLOW from the user's vault, a totally separate piece of the account that -// should not be accessible in this function -// BAD - -pub fun transferNFT(id: UInt64, owner: AuthAccount) { - assert(owner(id) == owner.address) - - transfer(id) - - // Sneakily borrow a reference to the user's Flow Token Vault - // and withdraw a bit of FLOW - // BAD - let vaultRef = owner.borrow<&FlowToken.Vault>(/storage/flowTokenVault)! - let stolenTokens <- vaultRef.withdraw(amount: 0.1) - - // deposit the stolen funds in the contract owners vault - // BAD - contractVault.deposit(from: <-stolenTokens) -} -... -``` - -### Solution - -Projects should find other ways to authenticate users, such as using resources and capabilities as authentication objects. -They should also expect to perform most storage and linking operations within transaction bodies -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.md) 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 - -Public functions in a contract can be called by anyone, e.g. any other contract or any transaction. -If that function creates a resource, and that resource has functions that emit events, -that means any account can create an instance of that resource and emit those events. -If those events are meant to indicate actions taken using a single instance of that resource -(eg. admin object, registry), or instances created through a particular workflow, -it's possible that events from other instances may be mixed in with the ones you're querying for - -making the event log search and management more cumbersome. - -### Solution - -To fix this, if there should be only a single instance of the resource, -it should be created and `link()`ed to a public path in an admin account's storage -during the contracts's initializer. - -# Access Control - -## Public functions and fields should be avoided - -### Problem - -Be sure to keep track of access modifiers when structuring your code, and make public only what should be public. -Accidentally exposed fields can be a security hole. - -### Solution - -When writing your smart contract, look at every field and function and make sure -that they are all `access(self)`, `access(contract)`, or `access(account)`, unless otherwise needed. - -## Capability-Typed public fields are a security hole - -This is a specific case of "Public Functions And Fields Should Be Avoided", above. - -### Problem - -The values of public fields can be copied. Capabilities are value types, -so if they are used as a public field, anyone can copy it from the field -and call the functions that it exposes. -This almost certainly is not what you want if a capability -has been stored as a field on a contract or resource in this way. - -### Solution - -For public access to a capability, place it in an accounts public area so this expectation is explicit. - -## Array or dictionary fields should be private - -:::tip - -This anti-pattern has been addressed with [FLIP #703](https://github.com/onflow/flips/blob/main/cadence/20211129-cadence-mutability-restrictions.md) - -::: - -### Problem - -This is a specific case of "Public Functions And Fields Should Be Avoided", above. -Public array or dictionary fields are not directly over-writable, -but their members can be accessed and overwritten if the field is public. -This could potentially result in security vulnerabilities for the contract -if these fields are mistakenly made public. - -Ex: - -```cadence -pub contract Array { - // array is intended to be initialized to something constant - pub let shouldBeConstantArray: [Int] -} -``` - -Anyone could use a transaction like this to modify it: - -```cadence -import Array from 0x01 - -transaction { - execute { - Array.shouldbeConstantArray[0] = 1000 - } -} -``` - -### Solution - -Make sure that any array or dictionary fields in contracts, structs, or resources -are `access(contract)` or `access(self)` unless they need to be intentionally made public. - -```cadence -pub contract Array { - // array is inteded to be initialized to something constant - access(self) let shouldBeConstantArray: [Int] -} -``` - -## Public admin resource creation functions are unsafe - -This is a specific case of "Public Functions And Fields Should Be Avoided", above. - -### Problem - -A public function on a contract that creates a resource can be called by any account. -If that resource provides access to admin functions then the creation function should not be public. - -### Solution - -To fix this, a single instance of that resource should be created in the contract's `init()` method, -and then a new creation function can be potentially included within the admin resource, if necessary. -The admin resource can then be `link()`ed to a private path in an admin's account storage during the contract's initializer. - -### Example - -```cadence -// Pseudo-code - -// BAD -pub contract Currency { - pub resource Admin { - pub fun mintTokens() - } - - // Anyone in the network can call this function - // And use the Admin resource to mint tokens - pub fun createAdmin(): @Admin { - return <-create Admin() - } -} - -// 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() - - // Only an admin can create new Admins - pub fun createAdmin(): @Admin { - return <-create Admin() - } - } - - init() { - // Create a single admin resource - let firstAdmin <- create Admin() - - // Store it in private account storage in `init` so only the admin can use it - self.account.save(<-firstAdmin, to: /storage/currencyAdmin) - } -} -``` - -## Do not modify smart contract state or emit events in public struct initializers - -This is another example of the risks of having publicly accessible parts to your smart contract. - -### Problem - -Data structure definitions in Cadence currently must be declared as public so that they can be used by anyone. -Structs do not have the same restrictions that resources have on them, -which means that anyone can create a new instance of a struct without going through any authorization. - -### Solution - -Any contract state-modifying operations related to the creation of structs -should be contained in restricted resources instead of the initializers of structs. - -### Example - -This used to be a bug in the NBA Top Shot smart contract, so we'll use that as an example. -Before, when it created a new play, -[it would initialize the play record with a struct,](https://github.com/dapperlabs/nba-smart-contracts/blob/55645478594858a6830e4ab095034068ef9753e9/contracts/TopShot.cdc#L155-L158) -which increments the number that tracks the play IDs and emits an event: - -```cadence -// Simplified Code -// BAD -// -pub contract TopShot { - - // The Record that is used to track every unique play ID - pub var nextPlayID: UInt32 - - pub struct Play { - - pub let playID: UInt32 - - init() { - - self.playID = TopShot.nextPlayID - - // Increment the ID so that it isn't used again - TopShot.nextPlayID = TopShot.nextPlayID + 1 - - emit PlayCreated(id: self.playID, metadata: metadata) - } - } -} -``` - -This is a risk because anyone can create the `Play` struct as many times as they want, -which could increment the `nextPlayID` field to the max `UInt32` value, -effectively preventing new plays from being created. It also would emit bogus events. - -This bug was fixed by -[instead updating the contract state in the admin function](https://github.com/dapperlabs/nba-smart-contracts/blob/master/contracts/TopShot.cdc#L682-L685) -that creates the plays. - - -```cadence -// Update contract state in admin resource functions -// GOOD -// -pub contract TopShot { - - // The Record that is used to track every unique play ID - pub var nextPlayID: UInt32 - - pub struct Play { - - pub let playID: UInt32 - - init() { - self.playID = TopShot.nextPlayID - } - } - - pub resource Admin { - - // Protected within the private admin resource - pub fun createPlay() { - // Create the new Play - var newPlay = Play() - - // Increment the ID so that it isn't used again - TopShot.nextPlayID = TopShot.nextPlayID + UInt32(1) - - emit PlayCreated(id: newPlay.playID, metadata: metadata) - - // Store it in the contract storage - TopShot.playDatas[newPlay.playID] = newPlay - } - } -} -``` diff --git a/versioned_docs/version-0.42/cadence-migration-guide b/versioned_docs/version-0.42/cadence-migration-guide deleted file mode 120000 index c29e019..0000000 --- a/versioned_docs/version-0.42/cadence-migration-guide +++ /dev/null @@ -1 +0,0 @@ -../versioned_docs/version-1.0/cadence-migration-guide \ No newline at end of file diff --git a/versioned_docs/version-0.42/contract-upgrades.md b/versioned_docs/version-0.42/contract-upgrades.md deleted file mode 100644 index 172f69d..0000000 --- a/versioned_docs/version-0.42/contract-upgrades.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Contract Upgrades with Incompatible Changes ---- - -### Problem - -I have an incompatible upgrade for a contract. How can I deploy this? - -### Solution - -Please don't perform incompatible upgrades between contract versions in the same account. -There is too much that can go wrong. - -You can make [compatible upgrades](./language/contract-updatability.md) and then run a post-upgrade function on the new contract code if needed. - -If you must replace your contract rather than update it, -the simplest solution is to add or increase a suffix on any named paths in the contract code -(e.g. `/public/MyProjectVault` becomes `/public/MyProjectVault002`) in addition to making the incompatible changes, -then create a new account and deploy the updated contract there. - -⚠️ Flow identifies types relative to addresses, so you will also need to provide _upgrade transactions_ to exchange the old contract's resources for the new contract's ones. Make sure to inform users as soon as possible when and how they will need to perform this task. - -If you absolutely must keep the old address when making an incompatible upgrade, then you do so at your own risk. Make sure you perform the following actions in this exact order: - -1. Delete any resources used in the contract account, e.g. an Admin resource. -2. Delete the contract from the account. -3. Deploy the new contract to the account. - -⚠️ Note that if any user accounts contain `structs` or `resources` from the _old_ version of the contract that have been replaced with incompatible versions in the new one, **they will not load and will cause transactions that attempt to access them to crash**. For this reason, once any users have received `structs` or `resources` from the contract, this method of making an incompatible upgrade should not be attempted! diff --git a/versioned_docs/version-0.42/design-patterns.md b/versioned_docs/version-0.42/design-patterns.md deleted file mode 100644 index 25d7a06..0000000 --- a/versioned_docs/version-0.42/design-patterns.md +++ /dev/null @@ -1,492 +0,0 @@ ---- -title: Cadence Design Patterns -sidebar_position: 6 -sidebar_label: Design Patterns ---- - -This is a selection of software design patterns developed by core Flow developers -while writing Cadence code for deployment to Flow Mainnet. - -Many of these design patters apply to most other programming languages, but some are specific to Cadence. - -[Design patterns](https://en.wikipedia.org/wiki/Software_design_pattern) are building blocks for software development. -They may provide a solution to a problem that you encounter when writing smart contracts in Cadence. -If they do not clearly fit, these patterns may not be the right solution for a given situation or problem. -They are not meant to be rules to be followed strictly, especially where a better solution presents itself. - -# General - -These are general patterns to follow when writing smart contracts. - -## Use named value fields for constants instead of hard-coding - -### Problem - -Your contracts, resources, and scripts all have to refer to the same value. -A number, a string, a storage path, etc. -Entering these values manually in transactions and scripts is a potential source of error. -See [Wikipedia's page on magic numbers](https://en.wikipedia.org/wiki/Magic_number_(programming)) - -### Solution - -Add a public (`pub`), 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. - -Example Snippet: - -```cadence - -// BAD Practice: Do not hard code storage paths -pub contract NamedFields { - pub resource Test {} - - init() { - // BAD: Hard-coded storage path - self.account.save(<-create Test(), to: /storage/testStorage) - } -} - -// GOOD practice: Instead, use a field -// -pub contract NamedFields { - pub resource Test {} - - // GOOD: field storage path - pub let TestStoragePath: StoragePath - - init() { - // assign and access the field here and in transactions - self.TestStoragePath = /storage/testStorage - self.account.save(<-create Test(), to: self.TestStoragePath) - } -} - -``` - -[Example Code](https://github.com/onflow/flow-core-contracts/blob/master/contracts/LockedTokens.cdc#L718) - -## Script-Accessible public field/function - -Data availability is important in a blockchain environment. -It is useful to publicize information about your smart contract and the assets it controls -so other smart contracts and apps can easily query it. - -### Problem - -Your contract, resource or struct has a field or resource that will need to be read and used on or off-chain, often in bulk. - -### Solution - -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. - -Be careful not to expose any data or functionality that should be kept private when doing so. - -Example: - -```cadence -// BAD: Field is private, so it cannot be read by the public -access(self) let totalSupply: UFix64 - -// GOOD: Field is public, so it can be read and used by anyone -pub let totalSupply: UFix64 -``` - -## Script-Accessible report - -### Problem - -Your contract has a resource that you wish to access fields of. -Resources are often stored in private places and are hard to access. -Additionally, scripts cannot return resources to the external context, -so a struct must be used to hold the data. - -### Solution - -Return a reference to a resource if the data from a single resource is all that is needed. -Otherwise, declare a struct to hold the data that you wish to return from the script. -Write a function that fills out the fields of this struct with the data -from the resource that you wish to access. -Then call this on the resource that you wish to access the fields of in a script, -and return the struct from the script. - -See [Script-Accessible public field/function](#script-accessible-public-fieldfunction), above, for how best to expose this capability. - -### Example Code - -```cadence -pub contract AContract { - pub let BResourceStoragePath: StoragePath - pub let BResourcePublicPath: PublicPath - - init() { - self.BResourceStoragePath = /storage/BResource - self.BResourcePublicPath = /public/BResource - } - - // Resource definition - pub resource BResource { - pub var c: UInt64 - pub 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 { - return BReportStruct(c: self.c, d: self.d) - } - - init(c: UInt64, d: String) { - self.c = c - self.d = d - } - } - - // Define a struct with the same fields as the resource - pub struct BReportStruct { - pub var c: UInt64 - pub var d: String - - init(c: UInt64, d: String) { - self.c = c - self.d = d - } - - } -} -... -// Transaction -import AContract from 0xAContract - -transaction { - prepare(acct: AuthAccount) { - //... - acct.link<&AContract.BResource>(AContract.BResourcePublicPath, target: AContract.BResourceStoragePath) - } -} -// Script -import AContract from 0xAContract - -// Return the struct with a script -pub fun main(account: Address): AContract.BReportStruct { - // borrow the resource - let b = getAccount(account) - .getCapability(AContract.BResourcePublicPath) - .borrow<&AContract.BResource>() - // return the struct - return b.generateReport() -} -``` - -## Init Singleton - -### Problem - -An admin resource must be created and delivered to a specified account. -There should not be a function to do this, as that would allow anyone to create an admin resource. - -### Solution - -Create any one-off resources in the contract's `init()` function -and deliver them to an address or `AuthAccount` specified as an argument. - -See how this is done in the LockedTokens contract init function: - -[LockedTokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/LockedTokens.cdc#L718) - -and in the transaction that is used to deploy it: - -[admin_deploy_contract.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/lockedTokens/admin/admin_deploy_contract.cdc) - - -## Use descriptive names for fields, paths, functions and variables - -### Problem - -Smart contracts often are vitally important pieces of a project and often have many other -smart contracts and applications that rely on them. -Therefore, they need to be clearly written and easy to understand. - -### Solution - -All fields, functions, types, variables, etc., need to have names that clearly describe what they are used for. - -`account` / `accounts` is better than `array` / `element`. - -`providerAccount` / `tokenRecipientAccount` is better than `acct1` / `acct2`. - -`/storage/bestPracticesDocsCollectionPath` is better than `/storage/collection` - -### Example -```cadence -// BAD: Unclear naming -// -pub contract Tax { - // Do not use abbreviations unless absolutely necessary - pub var pcnt: UFix64 - - // Not clear what the function is calculating or what the parameter should be - pub fun calculate(num: UFix64): UFix64 { - // What total is this referring to? - let total = num + (num * self.pcnt) - - return total - } -} - -// GOOD: Clear naming -// -pub contract TaxUtilities { - // Clearly states what the field is for - pub var taxPercentage: UFix64 - - // Clearly states that this function calculates the - // total cost after tax - pub fun calculateTotalCostPlusTax(preTaxCost: UFix64): UFix64 { - let postTaxCost = preTaxCost + (preTaxCost * self.taxPercentage) - - return postTaxCost - } -} -``` - -## Include concrete types in type constraints, especially "Any" types - -### Problem - -When specifying type constraints for capabilities or borrows, concrete types often do not get specified, -making it unclear if the developer actually intended it to be unspecified or not. -Paths also use a shared namespace between contracts, so an account may have stored a different object -in a path that you would expect to be used for something else. -Therefore, it is important to be explicit when getting objects or references to resources. - - -### 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, -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. - -This signals that the field or variable is not scalar. -It also makes it easier to use the singular form for a variable name during iteration. - -## Use transaction post-conditions when applicable - -### Problem - -Transactions can contain any amount of valid Cadence code and access many contracts and accounts. -The power of resources and capabilities means that there may be some behaviors of programs that are not expected. - -### Solution - -It is usually safe to include post-conditions in transactions to verify the intended outcome. - -### Example - -This could be used when purchasing an NFT to verify that the NFT was deposited in your account's collection. - -```cadence -// Psuedo-code - -transaction { - - pub let buyerCollectionRef: &NonFungibleToken.Collection - - prepare(acct: AuthAccount) { - - // Get tokens to buy and a collection to deposit the bought NFT to - let temporaryVault <- vaultRef.withdraw(amount: 10.0) - let self.buyerCollectionRef = acct.borrow(from: /storage/Collection) - - // purchase, supplying the buyers collection reference - saleRef.purchase(tokenID: 1, recipient: self.buyerCollectionRef, buyTokens: <-temporaryVault) - - } - post { - // verify that the buyer now owns the NFT - self.buyerCollectionRef.idExists(1) == true: "Bought NFT ID was not deposited into the buyers collection" - } -} -``` - -## Avoid excessive load and save storage operations (prefer in-place mutations) - -### Problem - -When modifying data in account storage, `load()` and `save()` are costly operations. -This can quickly cause your transaction to reach the gas limit or slow down the network. - -This also applies to contract objects and their fields (which are implicitly stored in storage, i.e. read from/written to), -or nested resources. Loading them from their fields just to modify them and save them back -is just as costly. - -For example, a collection contains a dictionary of NFTs. There is no need to move the whole dictionary out of the field, -update the dictionary on the stack (e.g. adding or removing an NFT), -and then move the whole dictionary back to the field, it can be updated in-place. -The same goes for a more complex data structure like a dictionary of nested resources: -Each resource can be updated in-place by taking a reference to the nested object instead of loading and saving. - -### Solution - -For making modifications to values in storage or accessing stored objects, -`borrow()` should always be used to access them instead of `load` or `save` unless absolutely necessary. -`borrow()` returns a reference to the object at the storage path instead of having to load the entire object. -This reference can be assigned to or can be used to access fields or call methods on stored objects. - -### Example - -```cadence -// BAD: Loads and stores a resource to use it -// -transaction { - - prepare(acct: AuthAccount) { - - // Removes the vault from storage, a costly operation - let vault <- acct.load<@ExampleToken.Vault>(from: /storage/exampleToken) - - // Withdraws tokens - let burnVault <- vault.withdraw(amount: 10) - - destroy burnVault - - // Saves the used vault back to storage, another costly operation - acct.save(to: /storage/exampleToken) - - } -} - -// GOOD: Uses borrow instead to avoid costly operations -// -transaction { - - prepare(acct: AuthAccount) { - - // Borrows a reference to the stored vault, much less costly operation - let vault <- acct.borrow<&ExampleToken.Vault>(from: /storage/exampleToken) - - let burnVault <- vault.withdraw(amount: 10) - - destroy burnVault - - // No `save` required because we only used a reference - } -} -``` - -# Capabilities - -## Capability Bootstrapping - -### Problem - -An account must be given a [capability](./language/capabilities.md) -to a resource or contract in another account. To create, i.e. link the capability, -the transaction must be signed by a key which has access to the target account. - -To transfer / deliver the capability to the other account, the transaction also needs write access to that one. -It is not as easy to produce a single transaction which is authorized by two accounts -as it is to produce a typical transaction which is authorized by one account. - -This prevents a single transaction from fetching the capability -from one account and delivering it to the other. - -### Solution - -The solution to the bootstrapping problem in Cadence is provided by the [Inbox API](./language/accounts.mdx#account-inbox) - -Account A (which we will call the provider) creates the capability they wish to send to B (which we will call the recipient), -and stores this capability on their account in a place where the recipient can access it using the `Inbox.publish` function on their account. -They choose a name for the capability that the recipient can later use to identify it, and specify the recipient's address when calling `publish`. -This call to `publish` will emit an `InboxValuePublished` event that the recipient can listen for off-chain to know that the Capability is ready for them to claim. - -The recipient then later can use the `Inbox.claim` function to securely grab the capability from the provider's account. -They must provide the name and type with which the capability was published, as well as the address of the provider's account -(all of this information is available in the `InboxValuePublished` event emitted on `publish`). -This will remove the capability from the provider's account and emit an `InboxValueClaimed` event that the provider can listen for off-chain. - -One important caveat to this is that the published capability is stored on the provider's account until the recipient claims it, -so the provider can also use the `Inbox.unpublish` function to remove the capability from their account if they no longer wish to pay for storage for it. -This also requires the name and type which the capability was published, -and emits an `InboxValueUnpublished` event that the recipient can listen for off-chain. - -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 -that the provider is willing to allow them to copy. - -## Capability Revocation - -### Problem - -A capability provided by one account to a second account must able to be revoked -by the first account without the co-operation of the second. - -See the [Capability Controller FLIP](https://github.com/onflow/flow/pull/798) for a proposal to improve this in the future. - -### Solution - -The first account should create the capability as a link to a capability in `/private/`, -which then links to a resource in `/storage/`. That second-order link is then handed -to the second account as the capability for them to use. - -**Account 1:** `/private/capability` → `/storage/resource` - -`/private/revokableLink` -> `/private/capability` - -**Account 2:** `/storage/capability -> (Capability(→Account 1: /private/revokableLink))` - -If the first account wants to revoke access to the resource in storage, -they should delete the `/private/` link that the second account's capability refers to. -Capabilities use paths rather than resource identifiers, so this will break the capability. - -The first account should be careful not to create another link at the same location -in its private storage once the capability has been revoked, -otherwise this will restore the second account's capability. - - -## Check for existing links before creating new ones - -When linking a capability, the link might be already present. -In that case, Cadence will not panic with a runtime error but the link function will return nil. -The documentation states that: The link function does not check if the target path is valid/exists -at the time the capability is created and does not check if the target value conforms to the given type. -In that sense, it is a good practice to check if the link does already exist with `AuthAccount.getLinkTarget` -before creating it with `AuthAccount.link()`. -`AuthAccount.getLinkTarget` will return nil if the link does not exist. - -### Example - -```cadence -transaction { - prepare(signer: AuthAccount) { - // Create a public capability to the Vault that only exposes - // the deposit function through the Receiver interface - // - // Check to see if there is a link already and unlink it if there is - - if signer.getLinkTarget(/public/exampleTokenReceiver) != nil { - signer.unlink(/public/exampleTokenReceiver) - } - - signer.link<&ExampleToken.Vault{FungibleToken.Receiver}>( - /public/exampleTokenReceiver, - target: /storage/exampleTokenVault - ) - } -} -``` diff --git a/versioned_docs/version-0.42/index.md b/versioned_docs/version-0.42/index.md deleted file mode 100644 index 144eec7..0000000 --- a/versioned_docs/version-0.42/index.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -title: Introduction to Cadence -sidebar_position: 1 -sidebar_label: Introduction ---- - -In a blockchain environment like Flow, programs that are stored on-chain in accounts are commonly referred to as smart contracts. -A smart contract is a program that verifies and executes the performance of a contract without the need for a trusted third party. -Programs that run on blockchains are commonly referred to as smart contracts because they mediate important functionality (such as currency) -without having to rely on a central authority (like a bank). - -## A New Programming Language - ---- - -Cadence is a resource-oriented programming language that introduces new features to smart contract programming -that help developers ensure that their code is safe, secure, clear, and approachable. Some of these features are: - -- Type safety and a strong static type system. -- Resource-oriented programming, a new paradigm that pairs linear types with object capabilities -to create a secure and declarative model for digital ownership by ensuring that resources (which are used to represent scarce digital assets) -can only exist in one location at a time, cannot be copied, and cannot be accidentally lost or deleted. -- Built-in pre-conditions and post-conditions for functions and transactions. -- The utilization of capability-based security, which enforces that access to objects -is restricted to only the owner of the object and those who have a valid reference to it. -This is Cadence's main form of access control. - -Cadence’s syntax is inspired by popular modern general-purpose programming languages -like [Swift](https://developer.apple.com/swift/), [Kotlin](https://kotlinlang.org/), and [Rust](https://www.rust-lang.org/). -Its use of resource types maps well to that of [Move](https://medium.com/coinmonks/overview-of-move-programming-language-a860ffd8f55d), -the programming language being developed by the Diem team. - -## Cadence's Programming Language Pillars - ---- - -Cadence, a new high-level programming language, observes the following requirements: - -- **Safety and Security:** Safety is the underlying reliability of any smart contract (i.e., it’s bug-free and performs its function). -Security is the prevention of attacks on the network or smart contracts (i.e., unauthorized actions by malicious actors). -Safety and security are critical in smart contracts because of the immutable nature of blockchains, -and because they often deal with high-value assets. While auditing and reviewing code will be a crucial part of smart contract development, -Cadence maximizes efficiency while maintaining the highest levels of safety and security at its foundation. -It accomplishes this via a strong static type system, design by contract, and ownership primitives inspired by linear types (which are useful when dealing with assets). -- **Clarity:** Code needs to be easy to read, and its meaning should be as unambiguous as possible. -It should also be suited for verification so that tooling can help with ensuring safety and security guarantees. -These guarantees can be achieved by making the code declarative and allowing the developer to express their intentions directly. -We make those intentions explicit by design, which, along with readability, make auditing and reviewing more efficient, at a small cost to verbosity. -- **Approachability:** Writing code and creating programs should be as approachable as possible. -Incorporating features from languages like Swift and Rust, developers should find Cadence’s syntax and semantics familiar. -Practical tooling, documentation, and examples enable developers to start creating programs quickly and effectively. -- **Developer Experience:** The developer should be supported throughout the entire development lifecycle, from initial application logic to on-chain bugfixes. -- **Intuiting Ownership with Resources:** Resources are a composite data type, similar to a struct, that expresses direct ownership of assets. -Cadence’s strong static type system ensures that resources can only exist in one location at a time and cannot be copied or lost because of a coding mistake. -Most smart contract languages currently use a ledger-style approach to record ownership, -where an asset like a fungible token is stored in the smart contract as an entry in a central ledger. -Cadence’s resources directly tie an asset’s ownership to the account that owns it by saving the resource in the account’s storage. -As a result, ownership isn’t centralized in a smart contract’s storage. Each account owns its assets, -and the assets can be transferred freely between accounts without the need for arbitration by a central smart contract. - -## Addressing Challenges with Existing Languages - ---- - -Other languages pioneered smart contract development, but they lack in areas that affect the long-term viability of next-generation applications. - -### Safety - -Safety is the reliability of a smart contract to perform its function as intended. -It is heavily influenced by the unchangeable-once-deployed nature of smart contracts: -Developers must take certain precautions in order to avoid introducing any potentially catastrophic vulnerabilities -prior to publishing a smart contract on the blockchain. -It is standard across many blockchains that modifying or updating a smart contract, even to fix a vulnerability, is not allowed. -Thus, any bugs that are present in the smart contract will exist forever. - -For example, in 2016, an overlooked vulnerability in an Ethereum DAO smart contract (Decentralized Autonomous Organization) -saw millions of dollars siphoned from a smart contract, -eventually leading to a fork in Ethereum and two separate active blockchains (Ethereum and Ethereum Classic). - -Bug fixes are only possible if a smart contract is designed to support changes, -a feature that introduces complexity and security issues. -Lengthy auditing and review processes can ensure a bug-free smart contract. -Still, they add substantial time to the already time-consuming task of getting the smart contract’s core logic working correctly. - -Overlooked mistakes cause the most damaging scenarios. -It is easy to lose or duplicate monetary value or assets in existing languages because they don’t check relevant invariants -or make it harder to express them. -For example, a plain number represents a transferred amount that can be accidentally (or maliciously) multiplied or ignored. - -Some languages also express behaviors that developers tend to forget about. -For example, a fixed-range type might express monetary value, without considerations for a potential overflow or underflow. -In Solidity, Ethereum's smart contract language, an overflow causes the value to wrap around, as shown [here](https://ethfiddle.com/CAp-kQrDUP). -Solidity also allows contracts to declare variables without initializing them. -If the developer forgets to add an initialization somewhere, -and then tries to read the variable somewhere else in the code expecting it to be a specific value, issues will occur. - -Cadence is type safe and has a strong static type system, -which prevents important classes of erroneous or undesirable program behavior at compile-time (i.e., before the program is run on-chain). -Types are checked statically and are not implicitly converted. Cadence also improves the safety of programs by preventing arithmetic underflow and overflow, -introduces optionals to make nil-cases explicit, and always requires variables to be initialized. -This helps ensure the behavior of these smart contracts is apparent and not dependent on context. - -### Security - -Security, in combination with safety, ensures the successful execution of a smart contract over time -by preventing unsanctioned access and guaranteeing that only authorized actions can be performed in the protocol. -In some languages, functions are public by default, creating vulnerabilities that allow malicious users to find attack vectors. -Cadence utilizes capability-based security, which allows the type system to enforce access control based on rules that users and developers have control over. - -Security is a consideration when interacting with other smart contracts. Any external call potentially allows malicious code to be executed. -For example, in Solidity, when the called function signature does not match any of the available ones, it triggers Solidity’s fallback functions. -These functions can be used in malicious ways. Language features such as multiple inheritances and overloading or dispatch can also make it difficult -to determine which code is invoked. - -In Cadence, the safety and security of programs are enhanced by **Design By Contract** and **Ownership Primitives.** -Design by contract allows developers to state pre-conditions and post-conditions for functions and interfaces in a declarative manner -so that callers can be certain about the behavior of called code. Ownership primitives are inspired by linear types and increase safety when working with assets. -They ensure that valuable assets are, for example, not accidentally or maliciously lost or duplicated. - -### Clarity and Approachability - -Implicitness, context-dependability, and expressiveness are language-based challenges that developers often encounter. -They affect the clarity (i.e. the readability of code and the ability to determine its intended function) -and the approachability (i.e. the ability to interpret or write code) of the language and the programs built using it. -For example, in Solidity, storage must be implemented in a low-level key-value manner, which obfuscates the developer’s intentions. -Syntax confusion is another example, with “=+” being legal syntax leading to an assignment instead of a probably-intended increment. -Solidity also has features with uncommon behaviors that can lead to unintended results. -[Multiple inheritance may lead to unexpected behaviours in the program](https://medium.com/consensys-diligence/a-case-against-inheritance-in-smart-contracts-d7f2c738f78e), -and testing and auditing the code is unlikely to identify this issue. - -The Ethereum blockchain’s code immutability showcases the need for considerations around extensibility and mechanisms that allow ad-hoc fixes. -Developers using custom-made approaches such as the 'data separation' approach to upgradability -may run into problems with the complexity of data structures, -while developers using ‘delegatecall-based proxies` may run into problems with the consistency of memory layouts. -Either way, these challenges compromise approachability and overall extensibility. -Cadence has [contract upgradability built in by default](./language/contract-updatability.md), -and contracts can be made immutable by removing all keys from an account. - -Cadence improves the clarity and extensibility of programs by utilizing interfaces to allow extensibility, code reuse, and interoperability between contracts. -Cadence modules also have configurable and transparent upgradeability built-in to enable projects to test and iterate before making their code immutable. - -Cadence allows the use of argument labels to describe the meaning of function arguments. -It also provides a rich standard library with useful data structures (e.g., dictionaries, sets) and data types for common use cases, -like fixed-point arithmetic, which helps when working with currencies. - -## Intuiting Ownership with Resources - -Most smart contract languages currently use a ledger-style approach to record ownership, -where an asset is stored in the smart contract as an entry in a central ledger, and this ledger is the source of truth around asset ownership. -There are many disadvantages to this design, especially when it comes to tracking the ownership of multiple assets belonging to a single account. -To find out all of the assets that an account owns, you would have to enumerate all the possible smart contracts that could potentially include this account -and search to see if the account owns these assets. - -In a resource-oriented language like Cadence, resources directly tie an asset to the account that owns it -by saving the resource in the account’s storage. As a result, ownership isn’t centralized in a single, central smart contract’s storage. -Instead, each account owns and stores its own assets, and the assets can be transferred freely between accounts without the need for arbitration by a central smart contract. - -Resources are inspired by linear types and increase safety when working with assets, which often have real, intrinsic value. -Resources, as enforced by Cadence’s type system, ensure that assets are correctly manipulated and not abused. - -- Every resource has exactly one owner. If a resource is used as a function parameter, an initial value for a variable, or something similar, the object is not copied. -Instead, it is moved to the new location, and the old location is immediately invalidated. -- The language will report an error if ownership of a resource was not properly transferred, i.e., -when the program attempts to introduce multiple owners for the resource or the resource ends up in a state where it does not have an owner. -For example, a resource can only be assigned to exactly one variable and cannot be passed to functions multiple times. -- Resources cannot go out of scope. If a function or transaction removes a resource from an account’s storage, -it either needs to end the transaction in an account's storage, or it needs to be explicitly and safely deleted. There is no “garbage collection” for resources. - -The special status of Resource objects must be enforced by the runtime; if they were just a compiler abstraction it would be easy for malicious code to break the value guarantees. - -Resources change how assets are used in a programming environment to better resemble assets in the real world. -Users store their currencies and assets in their own account, in their own wallet storage, and they can do with them as they wish. -Users can define custom logic and structures for resources that give them flexibility with how they are stored. -Additionally, because everyone stores their own assets, the calculation and charging of state rent is fair and balanced across all users in the network. - -## An Interpreted Language - ---- - -Currently, Cadence is an interpreted language, as opposed to a compiled language. This means that there is no Cadence Assembly, bytecode, compiler, or Cadence VM. - -The structure of the language lends itself well to compilation (for example, static typing), -but using an interpreter for the first version allows us to refine the language features more quickly as we define them. - -## Getting Started with Cadence - ---- - -Now that you've learned about the goals and design of Cadence and Flow, you're ready to get started with the Flow emulator and tools! -Go to the [Getting Started](./tutorial/01-first-steps.md) page to work through language fundamentals and tutorials. diff --git a/versioned_docs/version-0.42/json-cadence-spec.md b/versioned_docs/version-0.42/json-cadence-spec.md deleted file mode 100644 index e26f198..0000000 --- a/versioned_docs/version-0.42/json-cadence-spec.md +++ /dev/null @@ -1,871 +0,0 @@ ---- -title: JSON-Cadence Data Interchange Format -sidebar_label: JSON-Cadence format ---- - -# JSON-Cadence Data Interchange Format - -> Version 0.3.1 - -JSON-Cadence is a data interchange format used to represent Cadence values as language-independent JSON objects. - -This format includes less type information than a complete [ABI](https://en.wikipedia.org/wiki/Application_binary_interface), and instead promotes the following tenets: - -- **Human-readability** - JSON-Cadence is easy to read and comprehend, which speeds up development and debugging. -- **Compatibility** - JSON is a common format with built-in support in most high-level programming languages, making it easy to parse on a variety of platforms. -- **Portability** - JSON-Cadence is self-describing and thus can be transported and decoded without accompanying type definitions (i.e. an ABI). - -# Values - ---- - -### Void - -```json -{ - "type": "Void" -} -``` - -#### Example - -```json -{ - "type": "Void" -} -``` - ---- - -### Optional - -```json -{ - "type": "Optional", - "value": null | -} -``` - -#### Example - -```json -// Non-nil - -{ - "type": "Optional", - "value": { - "type": "UInt8", - "value": "123" - } -} - -// Nil - -{ - "type": "Optional", - "value": null -} -``` - ---- - -### Bool - -```json -{ - "type": "Bool", - "value": true | false -} -``` - -#### Example - -```json -{ - "type": "Bool", - "value": true -} -``` - ---- - -### String - -```json -{ - "type": "String", - "value": "..." -} - -``` - -#### Example - -```json -{ - "type": "String", - "value": "Hello, world!" -} -``` - ---- - -### Address - -```json -{ - "type": "Address", - "value": "0x0" // as hex-encoded string with 0x prefix -} -``` - -#### Example - -```json -{ - "type": "Address", - "value": "0x1234" -} -``` - ---- - -### Integers - -`[U]Int`, `[U]Int8`, `[U]Int16`, `[U]Int32`,`[U]Int64`,`[U]Int128`, `[U]Int256`, `Word8`, `Word16`, `Word32`, or `Word64` - -Although JSON supports integer literals up to 64 bits, all integer types are encoded as strings for consistency. - -While the static type is not strictly required for decoding, it is provided to inform client of potential range. - -```json -{ - "type": "", - "value": "" -} -``` - -#### Example - -```json -{ - "type": "UInt8", - "value": "123" -} -``` - ---- - -### Fixed Point Numbers - -`[U]Fix64` - -Although fixed point numbers are implemented as integers, JSON-Cadence uses a decimal string representation for readability. - -```json -{ - "type": "[U]Fix64", - "value": "." -} -``` - -#### Example - -```json -{ - "type": "Fix64", - "value": "12.3" -} -``` - ---- - -### Array - -```json -{ - "type": "Array", - "value": [ - , - - // ... - ] -} -``` - -#### Example - -```json -{ - "type": "Array", - "value": [ - { - "type": "Int16", - "value": "123" - }, - { - "type": "String", - "value": "test" - }, - { - "type": "Bool", - "value": true - } - ] -} -``` - ---- - -### Dictionary - -Dictionaries are encoded as a list of key-value pairs to preserve the deterministic ordering implemented by Cadence. - -```json -{ - "type": "Dictionary", - "value": [ - { - "key": "", - "value": - }, - ... - ] -} -``` - -#### Example - -```json -{ - "type": "Dictionary", - "value": [ - { - "key": { - "type": "UInt8", - "value": "123" - }, - "value": { - "type": "String", - "value": "test" - } - } - ], - // ... -} -``` - ---- - -### Composites (Struct, Resource, Event, Contract, Enum) - -Composite fields are encoded as a list of name-value pairs in the order in which they appear in the composite type declaration. - -```json -{ - "type": "Struct" | "Resource" | "Event" | "Contract" | "Enum", - "value": { - "id": "", - "fields": [ - { - "name": "", - "value": - }, - // ... - ] - } -} -``` - -#### Example - -```json -{ - "type": "Resource", - "value": { - "id": "0x3.GreatContract.GreatNFT", - "fields": [ - { - "name": "power", - "value": {"type": "Int", "value": "1"} - } - ] - } -} -``` - ---- - -### Path - -```json -{ - "type": "Path", - "value": { - "domain": "storage" | "private" | "public", - "identifier": "..." - } -} -``` - -#### Example - -```json -{ - "type": "Path", - "value": { - "domain": "storage", - "identifier": "flowTokenVault" - } -} -``` - ---- - -### Type Value - -```json -{ - "type": "Type", - "value": { - "staticType": - } -} -``` - -#### Example - -```json -{ - "type": "Type", - "value": { - "staticType": { - "kind": "Int", - } - } -} -``` - ---- - -### Capability - -```json -{ - "type": "Capability", - "value": { - "path": , - "address": "0x0", // as hex-encoded string with 0x prefix - "borrowType": , - } -} -``` - -#### Example - -```json -{ - "type": "Capability", - "value": { - "path": { - "type": "Path", - "value": { - "domain": "public", - "identifier": "someInteger" - } - }, - "address": "0x1", - "borrowType": { - "kind": "Int" - } - } -} -``` - ---- - -### Functions - -```json -{ - "type": "Function", - "value": { - "functionType": - } -} -``` - -Function values can only be exported, they cannot be imported. - -#### Example - -```json -{ - "type": "Function", - "value": { - "functionType": { - "kind": "Function", - "typeID": "(():Void)", - "parameters": [], - "return": { - "kind": "Void" - } - } - } -} -``` - ---- - -# Types - -### Simple Types - -These are basic types like `Int`, `String`, or `StoragePath`. - -```json -{ - "kind": "Any" | "AnyStruct" | "AnyResource" | "AnyStructAttachment" | "AnyResourceAttachment" | "Type" | - "Void" | "Never" | "Bool" | "String" | "Character" | - "Bytes" | "Address" | "Number" | "SignedNumber" | - "Integer" | "SignedInteger" | "FixedPoint" | - "SignedFixedPoint" | "Int" | "Int8" | "Int16" | - "Int32" | "Int64" | "Int128" | "Int256" | "UInt" | - "UInt8" | "UInt16" | "UInt32" | "UInt64" | "UInt128" | - "UInt256" | "Word8" | "Word16" | "Word32" | "Word64" | - "Fix64" | "UFix64" | "Path" | "CapabilityPath" | "StoragePath" | - "PublicPath" | "PrivatePath" | "AuthAccount" | "PublicAccount" | - "AuthAccount.Keys" | "PublicAccount.Keys" | "AuthAccount.Contracts" | - "PublicAccount.Contracts" | "DeployedContract" | "AccountKey" | "Block" -} -``` - -#### Example - -```json -{ - "kind": "UInt8" -} -``` - ---- - -### Optional Types - -```json -{ - "kind": "Optional", - "type": -} -``` - -#### Example - -```json -{ - "kind": "Optional", - "type": { - "kind": "String" - } -} -``` - ---- - -### Variable Sized Array Types - -```json -{ - "kind": "VariableSizedArray", - "type": -} -``` - -#### Example - -```json -{ - "kind": "VariableSizedArray", - "type": { - "kind": "String" - } -} -``` - ---- - -### Constant Sized Array Types - -```json -{ - "kind": "ConstantSizedArray", - "type": , - "size": , -} -``` - -#### Example - -```json -{ - "kind": "ConstantSizedArray", - "type": { - "kind": "String" - }, - "size":3 -} -``` - ---- - -### Dictionary Types - -```json -{ - "kind": "Dictionary", - "key": , - "value": -} -``` - -#### Example - -```json -{ - "kind": "Dictionary", - "key": { - "kind": "String" - }, - "value": { - "kind": "UInt16" - }, -} -``` - ---- - -### Composite Types - -```json -{ - "kind": "Struct" | "Resource" | "Event" | "Contract" | "StructInterface" | "ResourceInterface" | "ContractInterface", - "type": "", // this field exists only to keep parity with the enum structure below; the value must be the empty string - "typeID": "", - "initializers": [ - , - - // ... - ], - "fields": [ - , - - // ... - ], -} -``` - -#### Example - -```json -{ - "kind": "Resource", - "type": "", - "typeID": "0x3.GreatContract.GreatNFT", - "initializers":[ - [ - { - "label": "foo", - "id": "bar", - "type": { - "kind": "String" - } - } - ] - ], - "fields": [ - { - "id": "foo", - "type": { - "kind": "String" - } - } - ] -} -``` - ---- - -### Field Types - -```json -{ - "id": "", - "type": -} -``` - -#### Example - -```json -{ - "id": "foo", - "type": { - "kind": "String" - } -} -``` - ---- - -### Parameter Types - -```json -{ - "label": "