Skip to main content
Version: Next

Contracts

Accounts store contracts. A contract can also just be an interface.

An account exposes its inbox through the contracts field, which has the type Account.Contracts.

Account.Contracts


_71
access(all)
_71
struct Contracts {
_71
_71
/// The names of all contracts deployed in the account.
_71
access(all)
_71
let names: [String]
_71
_71
/// Returns the deployed contract for the contract/contract interface with the given name in the account, if any.
_71
///
_71
/// Returns nil if no contract/contract interface with the given name exists in the account.
_71
access(all)
_71
view fun get(name: String): DeployedContract?
_71
_71
/// Returns a reference of the given type to the contract with the given name in the account, if any.
_71
///
_71
/// Returns nil if no contract with the given name exists in the account,
_71
/// or if the contract does not conform to the given type.
_71
access(all)
_71
view fun borrow<T: &Any>(name: String): T?
_71
_71
/// Adds the given contract to the account.
_71
///
_71
/// The `code` parameter is the UTF-8 encoded representation of the source code.
_71
/// The code must contain exactly one contract or contract interface,
_71
/// which must have the same name as the `name` parameter.
_71
///
_71
/// All additional arguments that are given are passed further to the initializer
_71
/// of the contract that is being deployed.
_71
///
_71
/// The function fails if a contract/contract interface with the given name already exists in the account,
_71
/// if the given code does not declare exactly one contract or contract interface,
_71
/// or if the given name does not match the name of the contract/contract interface declaration in the code.
_71
///
_71
/// Returns the deployed contract.
_71
access(Contracts | AddContract)
_71
fun add(
_71
name: String,
_71
code: [UInt8]
_71
): DeployedContract
_71
_71
/// Updates the code for the contract/contract interface in the account.
_71
///
_71
/// The `code` parameter is the UTF-8 encoded representation of the source code.
_71
/// The code must contain exactly one contract or contract interface,
_71
/// which must have the same name as the `name` parameter.
_71
///
_71
/// Does **not** run the initializer of the contract/contract interface again.
_71
/// The contract instance in the world state stays as is.
_71
///
_71
/// Fails if no contract/contract interface with the given name exists in the account,
_71
/// if the given code does not declare exactly one contract or contract interface,
_71
/// or if the given name does not match the name of the contract/contract interface declaration in the code.
_71
///
_71
/// Returns the deployed contract for the updated contract.
_71
access(Contracts | UpdateContract)
_71
fun update(name: String, code: [UInt8]): DeployedContract
_71
_71
/// Removes the contract/contract interface from the account which has the given name, if any.
_71
///
_71
/// Returns the removed deployed contract, if any.
_71
///
_71
/// Returns nil if no contract/contract interface with the given name exists in the account.
_71
access(Contracts | RemoveContract)
_71
fun remove(name: String): DeployedContract?
_71
}
_71
_71
entitlement Contracts
_71
_71
entitlement AddContract
_71
entitlement UpdateContract
_71
entitlement RemoveContract

Deployed contract

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


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

Note that this is type only provides information about a deployed contract, it is not the contract instance, the result of importing a contract.

Getting a deployed contract

The function contracts.get retrieves a deployed contract:


_10
access(all)
_10
view fun get(name: String): DeployedContract?

The function returns the deployed contract with the given name, if any. If no contract with the given name exists in the account, the function returns nil.

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


_10
let account = getAccount(0x1)
_10
let contract = account.contracts.get(name: "Test")

Borrowing a deployed contract

Contracts can be "borrowed" to effectively perform a dynamic import dependent on a specific execution path.

This is in contrast to a typical import statement, for example import T from 0x1, which statically imports a contract.

The contracts.borrow function obtains a reference to a contract instance:


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

The functions returns a reference to the contract instance stored with that name on the account, if it exists, and if it has the provided type T. If no contract with the given name exists in the account, the function returns nil.

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


_10
let account = getAccount(0x1)
_10
let contract: &TestInterface = account.contracts.borrow<&TestInterface>(name: "Test")

This is similar to the import statement


_10
import Test from 0x1

Deploying a new contract

The contracts.add function deploys a new contract to an account:


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

Calling the add function requires access to an account via a reference which is authorized with the coarse-grained Contracts entitlement (auth(Contracts) &Account), or the fine-grained AddContract entitlement (auth(AddContract) &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.

The add function passes all extra arguments of the call (contractInitializerArguments) to the initializer of the contract.

If a contract 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 declaration in the code, then the function aborts the program.

When the deployment succeeded, the function returns the deployed contract.

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


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

The contract can be deployed as follows:


_10
transaction(code: String) {
_10
prepare(signer: auth(AddContract) &Account) {
_10
signer.contracts.add(
_10
name: "Test",
_10
code: code.utf8,
_10
message: "I'm a new contract in an existing account"
_10
)
_10
}
_10
}

Updating a deployed contract

The contracts.update function updates the code of an existing contract:


_10
access(Contracts | UpdateContract)
_10
fun update(name: String, code: [UInt8]): DeployedContract

Calling the update function requires access to an account via a reference which is authorized with the coarse-grained Contracts entitlement (auth(Contracts) &Account), or the fine-grained UpdateContract entitlement (auth(UpdateContract) &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.

If no contract 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 declaration in the code, then the function aborts the program.

When the update succeeded, the function returns the deployed contract.

info

The update function does not run the initializer of the contract again.

Updating a contract does not change the contract instance and its existing stored data. A contract update only changes the code a contract.

Is only possible to update contracts in ways that keep data consistency. Certain restrictions apply.

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:


_10
transaction(code: String) {
_10
prepare(signer: auth(UpdateContract) &Account) {
_10
signer.contracts.update(
_10
name: "Test",
_10
code: code
_10
)
_10
}
_10
}

Removing a deployed contract

The contracts.remove function removes a deployed contract from an account:


_10
access(Contracts | RemoveContract)
_10
fun remove(name: String): DeployedContract?

Calling the remove function requires access to an account via a reference which is authorized with the coarse-grained Contracts entitlement (auth(Contracts) &Account), or the fine-grained RemoveContract entitlement (auth(RemoveContract) &Account).

The function removes the contract from the account which has the given name and returns it. If no contract with the given name exists in the account, the function returns nil.

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


_10
transaction(code: String) {
_10
prepare(signer: auth(RemoveContract) &Account) {
_10
signer.contracts.remove(name: "Test",)
_10
}
_10
}