Syntax and Glossary
This comprehensive glossary provides detailed explanations and code examples for the most important syntax, symbols, operators, keywords, functions, and concepts in Cadence. Each entry includes a clear description of the feature's purpose, usage patterns, and common scenarios, helping both new and experienced developers quickly understand Cadence's unique resource-oriented programming model.
Use this guide as a complete reference to navigate Cadence's syntax, resource management, access control, and blockchain-specific features.
Comments
Comments can be used to document code. A comment is text that is not executed.
Single-line comments start with two slashes (//
). These comments can go on a line by themselves, or they can go directly after a line of code:
_10// This is a comment on a single line._10// Another comment line that is not executed._10_10let x = 1 // Here is another comment after a line of code.
Multi-line comments start with a slash and an asterisk (/*
) and end with an asterisk and a slash (*/
):
_10/* This is a comment which_10spans multiple lines. */
Comments may be nested:
_10/* /* this */ is a valid comment */
Multi-line comments are balanced:
_10/* this is a // comment up to here */ this is not part of the comment */
Documentation comments
Documentation comments (also known as doc-strings or doc-comment) are a special set of comments that can be processed by tools (e.g., to generate human-readable documentation or provide documentation in an IDE).
Doc-comments either start with three slashes (///
) on each line or are surrounded by /**
and **/
:
_10/// This is a documentation comment for `x`._10/// It spans multiple lines._10_10let x = 1
_10/**_10 This is a documentation comment_10 which also spans multiple lines._10**/
Identifiers
Identifiers can start with any upper or lowercase letter (A-Z, a-z) or an underscore (_
). This may be followed by zero or more upper and lower case letters, underscores, and numbers (0-9). Identifiers can not begin with a number:
_29// Valid: title-case_29//_29PersonID_29_29// Valid: with underscore_29//_29token_name_29_29// Valid: leading underscore and characters_29//_29_balance_29_29// Valid: leading underscore and numbers_29_8264_29_29// Valid: characters and number_29//_29account2_29_29// Invalid: leading number_29//_291something_29_29// Invalid: invalid character #_29_#1_29_29// Invalid: various invalid characters_29//_29!@#$%^&*
Reserved identifiers
The following identifiers are reserved, as they are keywords of the language:
if
,else
,while
,for
,in
,as
break
,continue
,return
true
,false
,nil
let
,var
create
,destroy
,emit
fun
,pre
,post
,auth
,access
self
,init
contract
,event
,struct
,resource
,interface
,entitlement
,enum
,mapping
,attachment
,result
transaction
,prepare
,execute
switch
,case
,default
import
,include
require
,requires
,static
,native
,pub
,priv
,try
,catch
,finally
,goto
,const
,export
,throw
,throws
,where
,final
,internal
,typealias
,repeat
,guard
,is
Conventions
By convention, variables, constants, and functions have lowercase identifiers, and types have title-case identifiers.
Symbols and operators
&
(ampersand)
The &
(ampersand) symbol creates references to values in Cadence, allowing you to access data without moving it. When used at the beginning of an expression, it creates a reference to a value, which can be either authorized (with the auth
modifier) or unauthorized. Authorized references include entitlements that specify what operations can be performed on the referenced value, while unauthorized references provide read-only access. The ampersand is also used in logical AND operations when doubled (&&
), allowing boolean expressions to be combined with short-circuit evaluation.
_10let a: String = "hello"_10let refOfA: &String = &a as &String_10let authRef: auth(X) &String = &a as auth(X) &String_10let result = true && false // logical AND
@
(at symbol)
The @
(at) symbol is a crucial resource type annotation in Cadence that indicates a type is a resource rather than a regular value. Resources in Cadence are unique, non-copyable types that must be explicitly moved between variables, functions, and storage locations. The @
symbol must appear at the beginning of the type declaration, emphasizing that the entire type acts as a resource. This annotation is required for resource instantiation, function parameters, return types, and variable declarations involving resources.
_10resource NFT {_10 access(all) var id: UInt64_10 access(all) var metadata: String_10}_10_10let myNFT: @NFT <- create NFT(id: 1, metadata: "Rare item")_10fun transfer(nft: @NFT) { /* resource handling */ }
:
(colon)
The :
(colon) symbol serves multiple purposes in Cadence syntax. It's primarily used for type annotations, allowing you to explicitly declare the type of variables, constants, function parameters, and return types. The colon also appears in ternary conditional operators to separate the then and else branches, providing a concise way to write conditional expressions. Additionally, colons are used in access modifiers and entitlement declarations to specify access control and authorization requirements.
_10let value: Int = 42 // type annotation_10fun calculate(x: Int, y: Int): Int { return x + y } // parameter and return types_10let result = condition ? value1 : value2 // ternary operator
=
(equals)
The =
(equals) symbol is the assignment operator in Cadence, used to assign values to variables and constants. For regular values (non-resources), the equals sign performs a copy assignment, creating a new copy of the value. For resources, the equals sign cannot be used directly; instead, the move operator <-
must be used to explicitly transfer ownership. The equals sign is also used in constant declarations with let
and variable declarations with var
, and it appears in comparison operations when doubled (==
) for equality testing.
_10let constant = 5 // constant declaration_10var mutable = 10 // variable declaration_10mutable = 15 // assignment_10let isEqual = a == b // equality comparison
!
(exclamation mark)
The !
(exclamation mark) symbol has two distinct uses depending on its position relative to a value. When placed before a boolean expression, it performs logical negation, inverting the truth value of the expression. When placed after an optional value, it performs force unwrapping, extracting the contained value from the optional or causing a runtime panic if the optional is nil. Force unwrapping should be used carefully as it can cause program termination, and safer alternatives like nil-coalescing (??
) or optional binding should be preferred when possible.
_10let isTrue = true_10let isFalse = !isTrue // logical negation_10let optionalValue: Int? = 42_10let unwrapped = optionalValue! // force unwrap (dangerous if nil)
/
(forward slash)
The /
(forward slash) symbol serves as both a mathematical division operator and a path separator in Cadence. In arithmetic expressions, it performs division between numeric values, returning the quotient. In path expressions, it separates the components of storage paths, which are used to access data in account storage. Paths follow the format /domain/identifier
where domain can be storage
or public
, and the identifier specifies the specific storage location or capability.
_10let quotient = 10 / 2 // arithmetic division_10let storagePath = /storage/myResource // storage path_10let publicPath = /public/myCapability // public path
<-
(move operator)
The <-
(move operator) is essential for resource management in Cadence, explicitly indicating when a resource is being transferred from one location to another. Unlike regular values that are copied, resources must be moved using this operator to maintain their uniqueness and prevent accidental duplication. The move operator is required when creating resources, assigning them to variables, passing them as function arguments, returning them from functions, or storing them in account storage. This explicit movement ensures that resources follow Cadence's linear type system and prevents resource leaks or double-spending scenarios.
_10resource Token {_10 access(all) var amount: UInt64_10}_10_10let token <- create Token(amount: 100) // resource creation_10let newOwner <- token // resource transfer_10fun mint(): @Token { return <- create Token(amount: 50) } // resource return
<-!
(force-assignment move operator)
The <-!
(force-assignment move operator) is a specialized move operator that moves a resource into an optional variable, but only if the variable is currently nil. If the target variable already contains a resource, the operation will abort the program execution. This operator is useful for ensuring that optional resource variables are only assigned once, providing a safety mechanism against accidental overwrites. It's commonly used in initialization patterns where you want to guarantee that a resource is only moved into an empty optional container.
_10resource NFT {_10 access(all) var id: UInt64_10}_10_10var myNFT: @NFT? <- nil_10myNFT <-! create NFT(id: 1) // succeeds because myNFT is nil_10// myNFT <-! create NFT(id: 2) // would abort because myNFT is not nil
<->
(swap operator)
The <->
(swap operator) exchanges two resources between variables without requiring a temporary variable. This operator is particularly useful for resource management scenarios where you need to swap ownership of two resources atomically. The swap operation is guaranteed to be atomic and cannot fail, making it ideal for scenarios where you need to exchange resources in a single operation. This operator is commonly used in trading scenarios, resource reallocation, or any situation where two parties need to exchange resources simultaneously.
_10resource Coin {_10 access(all) var value: UInt64_10}_10_10let coinA: @Coin <- create Coin(value: 10)_10let coinB: @Coin <- create Coin(value: 20)_10coinA <-> coinB // now coinA has value 20, coinB has value 10
+
, -
, *
, %
(arithmetic operators)
The arithmetic operators +
, -
, *
, and %
perform standard mathematical operations on numeric types in Cadence. The plus operator (+
) adds two values, the minus operator (-
) subtracts the right operand from the left, the asterisk operator (*
) multiplies two values, and the percentage sign (%
) returns the remainder of division. These operators work with all numeric types including Int
, UInt
, Int8
, UInt8
, and so on, and follow standard operator precedence rules. Cadence also supports compound assignment operators like +=
, -=
, *=
, and %=
for more concise code. Cadence does not support the increment/decrement operators ++
, --
.
_10let sum = 5 + 3 // addition_10let difference = 10 - 4 // subtraction_10let product = 6 * 7 // multiplication_10let remainder = 17 % 5 // modulo_10var value = 10_10value += 5 // compound assignment
?
(question mark)
The ?
(question mark) symbol has multiple uses in Cadence, primarily for optional types and conditional operations. When following a type, it creates an optional type that can either contain a value or be nil, providing a safe way to handle potentially missing values. In ternary conditional expressions, the question mark separates the condition from the then branch. The question mark is also used in the nil-coalescing operator (??
) to provide a default value when an optional is nil, and in optional chaining to safely access properties or call methods on optional values.
_10let optionalInt: Int? = nil // optional type_10let result = condition ? value1 : value2 // ternary operator_10let safeValue = optionalInt ?? 0 // nil-coalescing_10let length = optionalString?.length // optional chaining
_
(underscore)
The _
(underscore) symbol serves multiple purposes in Cadence syntax. It can be used in identifiers and variable names to improve readability, particularly for separating words in compound names. In numeric literals, underscores can be used as separators to make large numbers more readable without affecting their value. When used as an argument label in function declarations, the underscore indicates that no argument label is required when calling the function, allowing for more natural function calls. The underscore is also used in pattern matching to ignore specific values or in unused variable declarations.
_10let user_name = "Alice" // identifier separator_10let large_number = 1_000_000 // numeric separator_10fun double(_ x: Int): Int { return x * 2 } // no argument label_10let result = double(5) // no label needed
;
(semicolon)
The ;
(semicolon) symbol is used as a separator between declarations and statements. A semicolon can be placed after any declaration and statement, but can be omitted between declarations if only one statement appears on the line.
_11// Declare a constant, without a semicolon._11//_11let a = 1_11_11// Declare a variable, with a semicolon._11//_11var b = 2;_11_11// Declare a constant and a variable on a single line, separated by semicolons._11//_11let d = 1; var e = 2
Punctuation marks
.
(dot/period)
The .
(dot) symbol serves multiple purposes in Cadence syntax. It's primarily used for member access, allowing you to access properties, methods, and nested types of objects and types. The dot operator is used to call functions on objects, access struct and resource fields, and navigate through nested structures. Dots are also used in decimal numbers to separate the integer and fractional parts, and in qualified type names to specify the namespace or module where a type is defined.
_10let length = "hello".length // member access_10let balance = token.balance // property access_10token.transfer(amount: 10) // method call_10let decimal = 3.14 // decimal number_10let nft: MyContract.NFT // qualified type name
,
(comma)
The ,
(comma) symbol is used to separate multiple items in lists, function parameters, type parameters, and other multi-item contexts in Cadence. Commas separate function arguments, array elements, dictionary key-value pairs, and type parameters in generic declarations. They're also used to separate multiple variable declarations in a single statement and to separate multiple return values in tuple types. Proper comma usage is essential for clear, readable code structure.
_10fun add(a: Int, b: Int, c: Int): Int { return a + b + c } // function parameters_10let array = [1, 2, 3, 4, 5] // array elements_10let dict = {"key1": "value1", "key2": "value2"} // dictionary pairs_10let a, b, c = 1, 2, 3 // multiple declarations_10let tuple: (Int, String, Bool) // tuple type
()
(parentheses)
The ()
(parentheses) symbol has multiple uses in Cadence syntax. They're used to group expressions and control operator precedence in mathematical and logical expressions. Parentheses are required around function parameters in function calls. They also serve to group conditions in control flow statements and to create type annotations for function types. Parentheses are essential for disambiguating complex expressions and ensuring proper evaluation order.
_10let result = (a + b) * c // expression grouping_10fun calculate(x: Int, y: Int): Int { return x + y } // function parameters_10let functionType: (Int, Int) -> Int // function type_10if (condition1 && condition2) { /* code */ } // grouped condition
<>
(angle brackets)
Angle brackets (<>
) are not used for generics like in many other languages — Cadence doesn't have traditional generic functions or structs — but they are used in a few specific syntactic contexts related to type parameters and type instantiation. Specifically, angle brackets are used to specify type parameters for certain built-in or standard library types that are type constructors. Angle brackets are also used to specify the borrow type when working with capabilities and when specifying the authorized type with some Cadence APIs. You can also use angle brackets to define explicit element types for collections.
_26// FungibleToken.Vault is a generic composite type in the standard interface._26// <ExampleToken.Vault> tells Cadence the concrete vault type to use:_26_26let vault: FungibleToken.Vault<ExampleToken.Vault>_26_26// The Capability<...> is a generic capability type:_26let cap: Capability<&ExampleToken.Vault{FungibleToken.Receiver}>_26_26// Inside <...>, you define the type that will be borrowed when_26// using the capability. For example:_26let receiverCap: Capability<&ExampleToken.Vault{FungibleToken.Receiver}>_26 = account.getCapability<&ExampleToken.Vault{FungibleToken.Receiver}>(/public/receiver)_26_26// No < > = Cadence infers; With < > = you're explicitly_26// telling it the type:_26let vaultRef = account_26 .getCapability<&ExampleToken.Vault{FungibleToken.Receiver}>(/public/receiver)_26 .borrow()_26let numbers: [Int] = []_26let moreNumbers = [] as [Int]_26_26// The type annotation uses square brackets for collections,_26// but when inside other parameterized types, < > is used:_26let dict: {String: Int} = {}_26let capDict: {String: Capability<&ExampleToken.Vault>} = {}_26// Here, the < > is within Capability<...> inside the dictionary value type.
{}
(curly brackets)
The {}
(curly brackets) symbol is used to define code blocks, scopes, and composite data structures in Cadence. They're used to group statements in functions, control flow statements, and resource/struct definitions. Curly brackets are also used to create dictionary literals and to define the body of functions, initializers, and methods. They establish the scope for variable declarations and control the lifetime of local variables and borrowed references.
_15fun example() {_15 let localVar = 42 // code block_15 if condition {_15 // nested block_15 }_15}_15_15resource NFT {_15 access(all) var id: UInt64 // resource definition_15 init(id: UInt64) {_15 self.id = id // initializer block_15 }_15}_15_15let dict = {"key": "value"} // dictionary literal
[]
(square brackets)
The []
(square brackets) symbol is used for array operations and type annotations in Cadence. They're used to create array literals, access array elements by index, and specify array types in type annotations. Square brackets are also used in dictionary key access and to specify the size of fixed-size arrays. They're essential for working with collections and implementing array-based data structures and algorithms.
_10let array = [1, 2, 3, 4, 5] // array literal_10let firstElement = array[0] // array access_10let arrayType: [String] // array type annotation_10let fixedArray: [Int; 5] // fixed-size array_10let dict = {"key": "value"}_10let value = dict["key"] // dictionary access
`
(backtick)
The `
(backtick) symbol is not used and has no syntactic meaning at all in Cadence syntax.
When working with string declarations, use double quotes (" "
) instead:
_10let s = `hello` // Error: use double quotes for strings_10let s = "hello"
Whitespace
Whitespace has no semantic meaning in Cadence syntax. It is used only to separate tokens.
Keywords and access control
access
The access
keyword is fundamental to Cadence's access control system, specifying who can access and modify declarations like variables, functions, and types. Access modifiers include access(all)
for public access, access(contract)
for contract-scoped access, access(account)
for account-scoped access, and access(self)
for private access. The access keyword can also be used with entitlements to create fine-grained authorization systems, allowing specific operations only when the caller has the required entitlements. This system ensures that resources and sensitive data are protected according to the principle of least privilege.
_10access(all) var publicVariable: String_10access(contract) fun contractOnlyFunction() { }_10access(account) resource PrivateResource { }_10access(E) fun authorizedFunction() { } // requires entitlement E
let
The let
keyword declares immutable constants in Cadence, creating values that cannot be modified after initialization. Constants declared with let
must be initialized with a value when declared, and their type can be explicitly specified or inferred from the initial value. For resources, let
constants still require the move operator (<-
) for assignment, and the resource cannot be moved out of the constant once assigned. The let
keyword is preferred over var
when a value doesn't need to change, as it provides compile-time guarantees about immutability and can enable compiler optimizations.
_10let constantValue = 42 // immutable constant_10let typedConstant: String = "Hello" // explicit type_10let resourceConstant: @NFT <- create NFT(id: 1) // immutable resource
var
The var
keyword declares mutable variables in Cadence, allowing values to be modified after initialization. Variables declared with var
can be reassigned new values of the same type, and for resources, they can be moved in and out using the move operators. The var
keyword is essential for maintaining state in contracts and resources, allowing data to be updated as the program executes. Like let
, the type can be explicitly specified or inferred, and access modifiers can be applied to control who can read or modify the variable.
_10var mutableValue = 10 // mutable variable_10mutableValue = 20 // can be reassigned_10var resourceVariable: @Token? <- nil // mutable resource variable_10resourceVariable <- create Token(amount: 100) // can be assigned
fun
The fun
keyword declares functions in Cadence, which are reusable blocks of code that can accept parameters and return values. Functions can be declared at the top level, within contracts, resources, or structs, and their access level determines who can call them. Functions can accept both regular values and resources as parameters, and they can return values, resources, or nothing (void). The function signature includes parameter types, return type, and access modifiers, and functions can be overloaded based on parameter types and labels.
_10access(all) fun add(a: Int, b: Int): Int {_10 return a + b_10}_10_10access(contract) fun transfer(token: @Token, to: Address) {_10 // resource transfer logic_10}
resource
The resource
keyword declares resource types in Cadence, which are unique, non-copyable types that represent digital assets or scarce resources. Resources must be explicitly created, moved, and destroyed, and they cannot be duplicated or lost accidentally. Resources can contain both regular values and other resources, and they can define functions (methods) that operate on the resource's data. The resource keyword is central to Cadence's resource-oriented programming model, ensuring that digital assets follow the same rules as physical assets in terms of ownership and transfer.
_13resource NFT {_13 access(all) var id: UInt64_13 access(all) var owner: Address_13_13 init(id: UInt64, owner: Address) {_13 self.id = id_13 self.owner = owner_13 }_13_13 access(all) fun transfer(to: Address) {_13 self.owner = to_13 }_13}
struct
The struct
keyword declares structure types in Cadence, which are composite types that group related data together. Unlike resources, structs are copyable and follow value semantics, meaning they are duplicated when assigned or passed as parameters. Structs can contain fields of various types, including other structs, and they can define functions that operate on the struct's data. Structs are commonly used for organizing data that doesn't represent unique assets, such as metadata, configuration, or temporary data structures.
_11struct Metadata {_11 access(all) var name: String_11 access(all) var description: String_11 access(all) var tags: [String]_11_11 init(name: String, description: String, tags: [String]) {_11 self.name = name_11 self.description = description_11 self.tags = tags_11 }_11}
contract
The contract
keyword declares smart contracts in Cadence, which are the primary unit of deployment and organization for blockchain code. Contracts can contain resources, structs, functions, and other declarations, and they provide a namespace for organizing related functionality. Contracts are deployed to specific accounts and can interact with each other through interfaces and capabilities. The contract keyword is essential for creating reusable, composable blockchain applications that can be deployed and upgraded independently.
_10access(all) contract MyContract {_10 access(all) resource NFT {_10 access(all) var id: UInt64_10 init(id: UInt64) { self.id = id }_10 }_10_10 access(all) fun mintNFT(id: UInt64): @NFT {_10 return <- create NFT(id: id)_10 }_10}
interface
The interface
keyword declares interface types in Cadence, which define a contract for what methods and properties a type must implement. Interfaces enable polymorphism and allow different types to be used interchangeably as long as they implement the required interface. Interfaces can declare function signatures, property requirements, and resource requirements, and they can be used as types for parameters, return values, and variables. The interface keyword is crucial for creating flexible, reusable code that can work with multiple implementations.
_12access(all) interface Transferable {_12 access(all) fun transfer(to: Address)_12 access(all) var owner: Address_12}_12_12access(all) resource NFT: Transferable {_12 access(all) var owner: Address_12_12 access(all) fun transfer(to: Address) {_12 self.owner = to_12 }_12}
attachment
The attachment
keyword declares attachment types in Cadence, which allow developers to extend struct or resource types (even ones they did not create) with new functionality without requiring the original author to plan for the intended behavior. Attachments are declared using the syntax attachment <Name> for <Type>: <Conformances> { ... }
and can only be declared with all
access. The attachment's kind (struct or resource) is automatically determined by the type it extends. Attachments are not first-class values and cannot exist independently of their base value, but they can be created using attach
expressions, accessed via type indexing, and removed using remove
statements.
_16access(all) resource R {_16 access(all) let x: Int_16 init(x: Int) { self.x = x }_16}_16_16access(all) attachment A for R {_16 access(all) let derivedX: Int_16 init(scalar: Int) {_16 self.derivedX = base.x * scalar_16 }_16}_16_16// Creating and using attachments_16let r <- create R(x: 5)_16let r2 <- attach A(scalar: 3) to <-r_16let attachmentRef = r2[A] // access attachment via type indexing
enum
The enum
keyword declares enumeration types in Cadence, which define a set of named constant values. Enums can contain simple cases, and they provide type safety by ensuring only valid enum values can be used. Enums are commonly used for representing states, types, or categories in a program. The enum keyword helps create more readable and maintainable code by replacing magic numbers or strings with meaningful named constants.
_13access(all) enum Status: UInt8 {_13_13 access(all)_13 case pending_13_13 access(all)_13 case active_13_13 access(all)_13 case completed_13}_13_13let status: Status = Status.active
Resource management functions
create
The create
keyword is used to instantiate new resources in Cadence, calling the resource's initializer to set up the new instance. The create keyword must be used with the move operator (<-
) to assign the newly created resource to a variable or return it from a function. Resources can only be created within the contract that defines them or through authorized functions, ensuring that resource creation is controlled and auditable. The create keyword is essential for minting new digital assets, creating new instances of resources, and initializing resource hierarchies.
_10resource Token {_10 access(all) var amount: UInt64_10 init(amount: UInt64) { self.amount = amount }_10}_10_10let newToken <- create Token(amount: 100) // resource creation_10fun mint(): @Token { return <- create Token(amount: 50) } // creation in function
destroy
The destroy
keyword is used to explicitly destroy resources in Cadence, permanently removing them from the system and freeing up any associated storage. The destroy keyword must be used with the move operator (<-
) to consume the resource being destroyed. Destroying a resource is irreversible and should be done carefully, typically only when the resource is no longer needed or when implementing burning mechanisms for digital assets. The destroy keyword ensures that resources follow a complete lifecycle from creation to destruction, preventing resource leaks.
_10resource Token {_10 access(all) var amount: UInt64_10 init(amount: UInt64) { self.amount = amount }_10}_10_10let token: @Token <- create Token(amount: 100)_10destroy token // permanently removes the resource
.borrow
The .borrow
function provides temporary access to a resource without moving it, returning a reference that can be used to read or modify the resource's properties and call its functions. The borrow function is essential for resource management when you need to access a resource's data without transferring ownership. Borrowed references can be either authorized or unauthorized, depending on the access requirements, and they automatically become invalid when the borrowing scope ends. The borrow function is commonly used for reading resource state, calling resource methods, and implementing complex resource interactions.
_13resource NFT {_13 access(all) var id: UInt64_13 access(all) var metadata: String_13_13 access(all) fun updateMetadata(newMetadata: String) {_13 self.metadata = newMetadata_13 }_13}_13_13let nft: @NFT <- create NFT(id: 1, metadata: "Original")_13let ref = &nft as &NFT_13ref.updateMetadata("Updated") // borrow and modify_13let id = ref.id // borrow and read
.link
The .link
function creates a capability that provides controlled access to a resource or function, allowing other accounts to interact with it through the capability system. The link function specifies the target path, the type of access being granted, and the restrictions on that access. Capabilities can be linked to either public or private storage paths, and they can include entitlements that define what operations are allowed. The link function is fundamental to Cadence's capability-based security model, enabling secure cross-account interactions while maintaining access control.
_10resource NFT {_10 access(all) var id: UInt64_10 access(all) fun transfer(to: Address) { /* transfer logic */ }_10}_10_10let nft: @NFT <- create NFT(id: 1)_10account.storage.save(<- nft, to: /storage/myNFT)_10account.link<&NFT>(/public/myNFTCap, target: /storage/myNFT) // create capability
.unlink
The .unlink
function removes a capability from account storage, revoking the access that was previously granted through the capability. The unlink function takes the path where the capability was stored and removes it, making the linked resource or function no longer accessible through that capability. This function is important for access control management, allowing accounts to revoke permissions when they're no longer needed or when security requirements change. The unlink function is commonly used in permission management systems and when cleaning up temporary access grants.
_10// Remove a previously linked capability_10account.unlink(/public/myNFTCap)
.getCapability
The .getCapability
function retrieves a capability from account storage, allowing you to access the capability's target resource or function. The getCapability function returns an optional capability, which will be nil if no capability exists at the specified path. This function is essential for capability-based programming, allowing accounts to access resources and functions that have been shared with them through the capability system. The getCapability function is commonly used in cross-account interactions and when implementing permission-based access patterns.
_10let capability = account.getCapability<&NFT>(/public/myNFTCap)_10if let nftRef = capability.borrow() {_10 // Use the borrowed reference_10 nftRef.transfer(to: newOwner)_10}
Storage and account functions
account.storage.save
The account.storage.save
function stores a value or resource in account storage at a specified path. This function is essential for persisting data on the blockchain, allowing resources and values to be stored permanently in an account's storage space. The save function requires the move operator (<-
) for resources and can store both regular values and resources. The storage path must be unique within the account, and the function will overwrite any existing value at that path. This function is commonly used for storing NFTs, tokens, and other digital assets in user accounts.
_10resource NFT {_10 access(all) var id: UInt64_10 init(id: UInt64) { self.id = id }_10}_10_10let nft: @NFT <- create NFT(id: 1)_10account.storage.save(<- nft, to: /storage/myNFT) // save resource_10account.storage.save("metadata", to: /storage/metadata) // save value
account.storage.load
The account.storage.load
function retrieves a value or resource from account storage at a specified path. This function returns an optional value, which will be nil if no value exists at the specified path or if the type doesn't match. For resources, the load function requires the move operator (<-
) to transfer ownership from storage to the variable. The load function is essential for accessing stored data and is commonly used in conjunction with save to implement persistent storage patterns.
_10let nft <- account.storage.load<@NFT>(from: /storage/myNFT)_10let metadata = account.storage.load<String>(from: /storage/metadata)
account.storage.borrow
The account.storage.borrow
function provides temporary access to a stored resource without moving it from storage. This function returns a reference to the resource that can be used to read or modify the resource's properties and call its functions. The borrow function is useful when you need to access a resource's data without removing it from storage, and it's commonly used for reading resource state or calling resource methods. The borrowed reference becomes invalid when the borrowing scope ends.
_10let nftRef = account.storage.borrow<&NFT>(from: /storage/myNFT)_10if let ref = nftRef {_10 let id = ref.id // read property_10 ref.updateMetadata("New metadata") // call method_10}
Type system keywords
AnyStruct
The AnyStruct
type is a top type in Cadence that can hold any struct value, providing maximum flexibility when you need to work with different struct types. AnyStruct is commonly used in generic containers, event parameters, and situations where you need to store or pass around different types of structs. When using AnyStruct, you typically need to perform type checking or type casting to access the specific properties or methods of the underlying struct. This type is essential for creating flexible, reusable code that can work with various struct types.
_10let anyValue: AnyStruct = "Hello" // can hold any struct_10let anotherValue: AnyStruct = 42 // can hold different types
AnyResource
The AnyResource
type is a top type in Cadence that can hold any resource value, allowing you to work with different resource types in a generic way. AnyResource is commonly used in generic containers, capability systems, and situations where you need to store or pass around different types of resources. When using AnyResource, you typically need to perform type checking or type casting to access the specific properties or methods of the underlying resource. This type is essential for creating flexible resource management systems.
_10let anyResource: AnyResource <- create SomeResource()_10let anotherResource: AnyResource <- create AnotherResource()
Void
The Void
type represents the absence of a value in Cadence, used when a function doesn't return anything or when you need to explicitly indicate that no value is expected. Functions that don't have a return statement or explicitly return Void are said to return nothing. The Void type is commonly used in function signatures, event definitions, and situations where you need to explicitly indicate that no value is being returned or expected. This type helps make code intentions clear and provides type safety.
_10fun doSomething(): Void {_10 // function that doesn't return a value_10}_10_10fun anotherFunction() { // implicitly returns Void_10 // function body_10}
Never
The Never
type represents a function that never returns normally, typically because it always throws an error or aborts execution. The Never type is used in function signatures to indicate that the function will not complete successfully and return a value. This type is commonly used in error handling functions, assertion functions, and functions that perform critical operations that must succeed or fail completely. The Never type helps make error handling explicit and provides compile-time guarantees about function behavior.
_10fun assert(condition: Bool): Never {_10 if !condition {_10 panic("Assertion failed")_10 }_10}
Control flow keywords
if
The if
keyword provides conditional execution in Cadence, allowing code to be executed only when a specified condition is true. If statements can include optional else clauses to handle the case when the condition is false, and they can be chained with else if clauses for multiple conditions. The condition in an if statement must evaluate to a boolean value, and the code blocks can contain any valid Cadence code including variable declarations, function calls, and resource operations. If statements are fundamental to implementing business logic and conditional behavior in smart contracts.
_10if condition {_10 // execute when condition is true_10} else if anotherCondition {_10 // execute when anotherCondition is true_10} else {_10 // execute when no conditions are true_10}
while
The while
keyword creates loops that execute a block of code repeatedly as long as a specified condition remains true. The condition is evaluated before each iteration, and the loop continues until the condition becomes false. While loops are useful for iterating over data structures, implementing retry logic, and performing operations that need to continue until a certain state is reached. Care must be taken to ensure that while loops eventually terminate to prevent infinite loops that could consume excessive gas.
_10var counter = 0_10while counter < 10 {_10 // execute while counter is less than 10_10 counter = counter + 1_10}
for
The for
keyword creates loops for iterating over collections like arrays, dictionaries, and ranges in Cadence. For loops can iterate over the elements of a collection, providing access to each element in sequence. The for keyword is commonly used with the in
keyword to specify the collection being iterated over, and the loop variable can be used to access the current element. For loops are essential for processing collections of data, implementing batch operations, and performing operations on multiple items.
_10let numbers = [1, 2, 3, 4, 5]_10for number in numbers {_10 // process each number_10}_10_10for i in 0...5 {_10 // iterate over range_10}
return
The return
keyword exits a function and optionally provides a value to be returned to the caller. The return keyword can be used with or without a value, depending on the function's return type. When used with a value, the value must match the function's declared return type. The return keyword immediately terminates function execution, making it useful for early exits and conditional returns. For functions that return resources, the return keyword must be used with the move operator (<-
) to transfer ownership of the resource.
_10fun add(a: Int, b: Int): Int {_10 return a + b // return with value_10}_10_10fun earlyExit(condition: Bool) {_10 if condition {_10 return // early exit without value_10 }_10 // continue execution_10}
Error handling
panic
The panic
function immediately aborts the execution of the current transaction with an optional error message. The panic function is used for critical errors that cannot be recovered from, such as assertion failures, invalid state conditions, or security violations. When panic is called, the entire transaction is rolled back, and any changes made during the transaction are discarded. The panic function is commonly used in assertion functions, input validation, and error conditions that indicate a fundamental problem with the program's logic or state.
_12fun assert(condition: Bool, message: String) {_12 if !condition {_12 panic(message) // abort with error message_12 }_12}_12_12fun divide(a: Int, b: Int): Int {_12 if b == 0 {_12 panic("Division by zero") // critical error_12 }_12 return a / b_12}
pre
and post
The pre
and post
keywords are used for function pre-conditions and post-conditions in Cadence, providing a way to specify requirements and guarantees about function behavior. Pre-conditions (pre
) specify conditions that must be true before a function is called, while post-conditions (post
) specify conditions that must be true after the function completes. These conditions are checked at runtime and will cause a panic if they are not satisfied. Pre and post conditions help ensure function correctness and provide documentation about function requirements and guarantees.
_10fun transfer(amount: UInt64): UInt64 {_10 pre {_10 amount > 0: "Amount must be positive"_10 }_10 post {_10 result > 0: "Result must be positive"_10 }_10 return amount_10}
Events and logging
event
The event
keyword declares event types in Cadence, which are used to emit structured data that can be indexed and queried by blockchain clients. Events are essential for creating transparent, auditable blockchain applications that can communicate state changes and important occurrences to external systems. Events can contain various data types including structs, resources, and primitive types, and they are emitted using the emit
keyword. Events are commonly used for tracking transactions, state changes, and important business events in smart contracts.
_10access(all) event TransferEvent(_10 from: Address,_10 to: Address,_10 amount: UInt64_10)_10_10fun transfer(to: Address, amount: UInt64) {_10 // transfer logic_10 emit TransferEvent(from: self.owner, to: to, amount: amount)_10}
emit
The emit
keyword is used to emit events in Cadence, broadcasting structured data to the blockchain network for indexing and querying by external systems. The emit keyword is followed by an event instance and any parameters that the event requires. Emitted events are permanently recorded on the blockchain and can be used for auditing, analytics, and triggering external processes. The emit keyword is commonly used in conjunction with the event keyword to create transparent, auditable blockchain applications.
_10access(all) event NFTMinted(id: UInt64, owner: Address)_10_10fun mintNFT(id: UInt64): @NFT {_10 let nft <- create NFT(id: id)_10 emit NFTMinted(id: id, owner: self.owner) // emit event_10 return <- nft_10}
Composite type keywords
init
The init
keyword declares initializer functions in Cadence, which are special functions that set up new instances of types when they are created. Initializers are called automatically when creating new instances using the create
keyword for resources or when declaring structs and other types. The init function can accept parameters to configure the new instance, and it's responsible for setting up the initial state of the object. Initializers are essential for ensuring that objects are properly initialized with valid state.
_10resource NFT {_10 access(all) var id: UInt64_10 access(all) var owner: Address_10_10 init(id: UInt64, owner: Address) {_10 self.id = id_10 self.owner = owner_10 }_10}
self
The self
keyword refers to the current instance of a type within its methods and initializers. The self keyword is used to access the current object's properties and methods, distinguishing them from local variables or parameters with the same names. In resource and struct methods, self is used to modify the object's state, access its properties, and call other methods on the same object. The self keyword is essential for object-oriented programming patterns in Cadence.
_11resource Token {_11 access(all) var balance: UInt64_11_11 access(all) fun transfer(amount: UInt64) {_11 self.balance = self.balance - amount // access own property_11 }_11_11 access(all) fun getBalance(): UInt64 {_11 return self.balance // return own property_11 }_11}