Skip to main content
Version: Next

Contracts

A contract in Cadence is a collection of type definitions of interfaces, structs, resources, data (its state), and code (its functions) that lives in the contract storage area of an account in Flow.

Contracts are where all composite types like structs, resources, events, and interfaces for these types in Cadence have to be defined. Therefore, an object of one of these types cannot exist without having been defined in a deployed Cadence contract.

Contracts can be created, updated, and removed using the contracts object of authorized accounts. This functionality is covered in the next section

Contracts are types. They are similar to composite types, but are stored differently than structs or resources and cannot be used as values, copied, or moved like resources or structs.

Contracts stay in an account's contract storage area and can only be added, updated, or removed by the account owner with special commands.

Contracts are declared using the contract keyword. The keyword is followed by the name of the contract.


_10
access(all) contract SomeContract {
_10
// ...
_10
}

Contracts cannot be nested in each other.


_10
access(all) contract Invalid {
_10
_10
// Invalid: Contracts cannot be nested in any other type.
_10
//
_10
access(all) contract Nested {
_10
// ...
_10
}
_10
}

One of the simplest forms of a contract would just be one with a state field, a function, and an init function that initializes the field:


_17
access(all) contract HelloWorld {
_17
_17
// Declare a stored state field in HelloWorld
_17
//
_17
access(all) let greeting: String
_17
_17
// Declare a function that can be called by anyone
_17
// who imports the contract
_17
//
_17
access(all) fun hello(): String {
_17
return self.greeting
_17
}
_17
_17
init() {
_17
self.greeting = "Hello World!"
_17
}
_17
}

This contract could be deployed to an account and live permanently in the contract storage. Transactions and other contracts can interact with contracts by importing them at the beginning of a transaction or contract definition.

Anyone could call the above contract's hello function by importing the contract from the account it was deployed to and using the imported object to call the hello function.


_18
import HelloWorld from 0x42
_18
_18
// Invalid: The contract does not know where hello comes from
_18
//
_18
log(hello()) // Error
_18
_18
// Valid: Using the imported contract object to call the hello
_18
// function
_18
//
_18
log(HelloWorld.hello()) // prints "Hello World!"
_18
_18
// Valid: Using the imported contract object to read the greeting
_18
// field.
_18
log(HelloWorld.greeting) // prints "Hello World!"
_18
_18
// Invalid: Cannot call the init function after the contract has been created.
_18
//
_18
HelloWorld.init() // Error

There can be any number of contracts per account and they can include an arbitrary amount of data. This means that a contract can have any number of fields, functions, and type definitions, but they have to be in the contract and not another top-level definition.


_10
// Invalid: Top-level declarations are restricted to only be contracts
_10
// or contract interfaces. Therefore, all of these would be invalid
_10
// if they were deployed to the account contract storage and
_10
// the deployment would be rejected.
_10
//
_10
access(all) resource Vault {}
_10
access(all) struct Hat {}
_10
access(all) fun helloWorld(): String {}
_10
let num: Int

Another important feature of contracts is that instances of resources and events that are declared in contracts can only be created/emitted within functions or types that are declared in the same contract.

It is not possible create instances of resources and events outside the contract.

The contract below defines a resource interface Receiver and a resource Vault that implements that interface. The way this example is written, there is no way to create this resource, so it would not be usable.


_44
// Valid
_44
access(all) contract FungibleToken {
_44
_44
access(all) resource interface Receiver {
_44
_44
access(all) balance: Int
_44
_44
access(all) fun deposit(from: @{Receiver}) {
_44
pre {
_44
from.balance > 0:
_44
"Deposit balance needs to be positive!"
_44
}
_44
post {
_44
self.balance == before(self.balance) + before(from.balance):
_44
"Incorrect amount removed"
_44
}
_44
}
_44
}
_44
_44
access(all) resource Vault: Receiver {
_44
_44
// keeps track of the total balance of the accounts tokens
_44
access(all) var balance: Int
_44
_44
init(balance: Int) {
_44
self.balance = balance
_44
}
_44
_44
// withdraw subtracts amount from the vaults balance and
_44
// returns a vault object with the subtracted balance
_44
access(all) fun withdraw(amount: Int): @Vault {
_44
self.balance = self.balance - amount
_44
return <-create Vault(balance: amount)
_44
}
_44
_44
// deposit takes a vault object as a parameter and adds
_44
// its balance to the balance of the Account's vault, then
_44
// destroys the sent vault because its balance has been consumed
_44
access(all) fun deposit(from: @{Receiver}) {
_44
self.balance = self.balance + from.balance
_44
destroy from
_44
}
_44
}
_44
}

If a user tried to run a transaction that created an instance of the Vault type, the type checker would not allow it because only code in the FungibleToken contract can create new Vaults.


_10
import FungibleToken from 0x42
_10
_10
// Invalid: Cannot create an instance of the `Vault` type outside
_10
// of the contract that defines `Vault`
_10
//
_10
let newVault <- create FungibleToken.Vault(balance: 10)

The contract would have to either define a function that creates new Vault instances or use its init function to create an instance and store it in the owner's account storage.

This brings up another key feature of contracts in Cadence. Contracts can interact with its account's storage and published objects to store resources, structs, and references. They do so by using the special self.account object that is only accessible within the contract.

Imagine that these were declared in the above FungibleToken contract.


_10
_10
access(all) fun createVault(initialBalance: Int): @Vault {
_10
return <-create Vault(balance: initialBalance)
_10
}
_10
_10
init(balance: Int) {
_10
let vault <- create Vault(balance: 1000)
_10
self.account.save(<-vault, to: /storage/initialVault)
_10
}

Now, any account could call the createVault function declared in the contract to create a Vault object. Or the owner could call the withdraw function on their own Vault to send new vaults to others.


_10
import FungibleToken from 0x42
_10
_10
// Valid: Create an instance of the `Vault` type by calling the contract's
_10
// `createVault` function.
_10
//
_10
let newVault <- create FungibleToken.createVault(initialBalance: 10)

Account access

Contracts have the implicit field let account: AuthAccount, which is the account in which the contract is deployed too. This gives the contract the ability to e.g. read and write to the account's storage.

Deploying, Updating, and Removing Contracts

In order for a contract to be used in Cadence, it needs to be deployed to an account. The deployed contracts of an account can be accessed through the contracts object.

Deployed Contracts

Accounts store "deployed contracts", that is, the code of the contract:


_23
access(all) struct DeployedContract {
_23
/// The address of the account where the contract is deployed at.
_23
access(all) let address: Address
_23
_23
/// The name of the contract.
_23
access(all) let name: String
_23
_23
/// The code of the contract.
_23
access(all) let code: [UInt8]
_23
_23
/// Returns an array of `Type` objects representing all the public type declarations in this contract
_23
/// (e.g. structs, resources, enums).
_23
///
_23
/// For example, given a contract
_23
/// ```
_23
/// contract Foo {
_23
/// access(all) struct Bar {...}
_23
/// access(all) resource Qux {...}
_23
/// }
_23
/// ```
_23
/// then `.publicTypes()` will return an array equivalent to the expression `[Type<Bar>(), Type<Qux>()]`
_23
access(all) fun publicTypes(): [Type]
_23
}

Note that this is not the contract instance that can be acquired by importing it.

Deploying a New Contract

A new contract can be deployed to an account using the add function:


_10
fun add(
_10
name: String,
_10
code: [UInt8],
_10
... contractInitializerArguments
_10
): DeployedContract

Adds the given contract to the account.

The code parameter is the UTF-8 encoded representation of the source code. The code must contain exactly one contract or contract interface, which must have the same name as the name parameter.

All additional arguments that are given are passed further to the initializer of the contract that is being deployed.

Fails if a contract/contract interface with the given name already exists in the account, if the given code does not declare exactly one contract or contract interface, or if the given name does not match the name of the contract/contract interface declaration in the code.

Returns the deployed contract.

For example, assuming the following contract code should be deployed:


_10
access(all) contract Test {
_10
access(all) let message: String
_10
_10
init(message: String) {
_10
self.message = message
_10
}
_10
}

The contract can be deployed as follows:


_15
// Decode the hex-encoded source code into a byte array
_15
// using the built-in function `decodeHex`.
_15
//
_15
// (The ellipsis ... indicates the remainder of the string)
_15
//
_15
let code = "70756220636f6e...".decodeHex()
_15
_15
// `code` has type `[UInt8]`
_15
_15
let signer: AuthAccount = ...
_15
signer.contracts.add(
_15
name: "Test",
_15
code: code,
_15
message: "I'm a new contract in an existing account"
_15
)

Updating a Deployed Contract

info

🚧 Status: Updating contracts is experimental.

Updating contracts is currently limited to maintain data consistency. Certain restrictions are imposed.

A deployed contract can be updated using the update__experimental function:


_10
fun update__experimental(name: String, code: [UInt8]): DeployedContract

Updates the code for the contract/contract interface in the account.

The code parameter is the UTF-8 encoded representation of the source code. The code must contain exactly one contract or contract interface, which must have the same name as the name parameter.

Does not run the initializer of the contract/contract interface again. The contract instance in the world state stays as is.

Fails if no contract/contract interface with the given name exists in the account, if the given code does not declare exactly one contract or contract interface, or if the given name does not match the name of the contract/contract interface declaration in the code.

Returns the deployed contract for the updated contract.

For example, assuming that a contract named Test is already deployed to the account and it should be updated with the following contract code:


_10
access(all) contract Test {
_10
access(all) let message: String
_10
_10
init(message: String) {
_10
self.message = message
_10
}
_10
}

The contract can be updated as follows:


_11
// Decode the hex-encoded source code into a byte array
_11
// using the built-in function `decodeHex`.
_11
//
_11
// (The ellipsis ... indicates the remainder of the string)
_11
//
_11
let code = "70756220636f6e...".decodeHex()
_11
_11
// `code` has type `[UInt8]`
_11
_11
let signer: AuthAccount = ...
_11
signer.contracts.update__experimental(name: "Test", code: code)

Updating a contract does not currently change any existing stored data. Only the code of the contract is updated.

Getting a Deployed Contract

A deployed contract can be gotten from an account using the get function:


_10
fun get(name: String): DeployedContract?

Returns the deployed contract for the contract/contract interface with the given name in the account, if any.

Returns nil if no contract/contract interface with the given name exists in the account.

For example, assuming that a contract named Test is deployed to an account, the contract can be retrieved as follows:


_10
let signer: AuthAccount = ...
_10
let contract = signer.contracts.get(name: "Test")

Borrowing a Deployed Contract

In contrast to a static contract import import T from 0x1, which will always perform an import of a type, contracts can be "borrowed" to effectively perform a dynamic import dependent on a specific execution path.

A reference to a deployed contract contract can obtained using the borrow function:


_10
fun borrow<T: &Any>(name: String): T?

This returns a reference to the contract value stored with that name on the account, if it exists, and if it has the provided type T.

Returns nil if no contract/contract interface with the given name exists in the account.

For example, assuming that a contract named Test which conforms to the TestInterface interface is deployed to an account, the contract can be retrieved as follows:


_10
let signer: AuthAccount = ...
_10
let contract: &TestInterface = signer.contracts.borrow<&TestInterface>(name: "Test")

Removing a Deployed Contract

A deployed contract can be removed from an account using the remove function:


_10
fun remove(name: String): DeployedContract?

Removes the contract/contract interface from the account which has the given name, if any.

Returns the removed deployed contract, if any.

Returns nil if no contract/contract interface with the given name exist in the account.

For example, assuming that a contract named Test is deployed to an account, the contract can be removed as follows:


_10
let signer: AuthAccount = ...
_10
let contract = signer.contracts.remove(name: "Test")

Contract Interfaces

Like composite types, contracts can have interfaces that specify rules about their behavior, their types, and the behavior of their types.

Contract interfaces have to be declared globally. Declarations cannot be nested in other types.

If a contract interface declares a concrete type, implementations of it must also declare the same concrete type conforming to the type requirement.

If a contract interface declares an interface type, the implementing contract does not have to also define that interface. They can refer to that nested interface by saying {ContractInterfaceName}.{NestedInterfaceName}


_26
// Declare a contract interface that declares an interface and a resource
_26
// that needs to implement that interface in the contract implementation.
_26
//
_26
access(all) contract interface InterfaceExample {
_26
_26
// Implementations do not need to declare this
_26
// They refer to it as InterfaceExample.NestedInterface
_26
//
_26
access(all) resource interface NestedInterface {}
_26
_26
// Implementations must declare this type
_26
//
_26
access(all) resource Composite: NestedInterface {}
_26
}
_26
_26
access(all) contract ExampleContract: InterfaceExample {
_26
_26
// The contract doesn't need to redeclare the `NestedInterface` interface
_26
// because it is already declared in the contract interface
_26
_26
// The resource has to refer to the resource interface using the name
_26
// of the contract interface to access it
_26
//
_26
access(all) resource Composite: InterfaceExample.NestedInterface {
_26
}
_26
}