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 deleted using the setCode
function of 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.
Contract stay in an account's contract storage area and can only be updated or deleted by the account owner with special commands.
Contracts are declared using the contract
keyword. The keyword is followed by the name of the contract.
Contracts cannot be nested in each other.
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.
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.
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.
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 Vault
s.
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.
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.
Contracts have the implicit field let account: Account
, 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 and Updating Contracts
In order for a contract to be used in Cadence, it needs to be deployed to an account. A contract can be deployed to an account using the setCode
function of the AuthAccount
type:
-
The code
parameter is the byte representation of the source code. All additional arguments that are given are passed further to the initializer of the contract that is being deployed.
For example, assuming the following contract code should be deployed:
The contract can be deployed as follows:
Last updated