Accounts
Every account can be accessed through two types, PublicAccount
and AuthAccount
.
PublicAccount
Public Account objects have the type PublicAccount
,
which represents the publicly available portion of an account.
_81pub struct PublicAccount {_81_81 /// The address of the account._81 pub let address: Address_81_81 /// The FLOW balance of the default vault of this account._81 pub let balance: UFix64_81_81 /// The FLOW balance of the default vault of this account that is available to be moved._81 pub let availableBalance: UFix64_81_81 /// The current amount of storage used by the account in bytes._81 pub let storageUsed: UInt64_81_81 /// The storage capacity of the account in bytes._81 pub let storageCapacity: UInt64_81_81 /// The contracts deployed to the account._81 pub let contracts: PublicAccount.Contracts_81_81 /// The keys assigned to the account._81 pub let keys: PublicAccount.Keys_81_81 /// All public paths of this account._81 pub let publicPaths: [PublicPath]_81_81 /// Returns the capability at the given public path._81 pub fun getCapability<T: &Any>(_ path: PublicPath): Capability<T>_81_81 /// Returns the target path of the capability at the given public or private path,_81 /// or nil if there exists no capability at the given path._81 pub fun getLinkTarget(_ path: CapabilityPath): Path?_81_81 /// Iterate over all the public paths of an account._81 /// passing each path and type in turn to the provided callback function._81 ///_81 /// The callback function takes two arguments:_81 /// 1. The path of the stored object_81 /// 2. The runtime type of that object_81 ///_81 /// Iteration is stopped early if the callback function returns `false`._81 ///_81 /// The order of iteration, as well as the behavior of adding or removing objects from storage during iteration,_81 /// is undefined._81 pub fun forEachPublic(_ function: ((PublicPath, Type): Bool))_81_81 pub struct Contracts {_81_81 /// The names of all contracts deployed in the account._81 pub let names: [String]_81_81 /// Returns the deployed contract for the contract/contract interface with the given name in the account, if any._81 ///_81 /// Returns nil if no contract/contract interface with the given name exists in the account._81 pub fun get(name: String): DeployedContract?_81_81 /// Returns a reference of the given type to the contract with the given name in the account, if any._81 ///_81 /// Returns nil if no contract with the given name exists in the account,_81 /// or if the contract does not conform to the given type._81 pub fun borrow<T: &Any>(name: String): T?_81 }_81_81 pub struct Keys {_81_81 /// Returns the key at the given index, if it exists, or nil otherwise._81 ///_81 /// Revoked keys are always returned, but they have `isRevoked` field set to true._81 pub fun get(keyIndex: Int): AccountKey?_81_81 /// Iterate over all unrevoked keys in this account,_81 /// passing each key in turn to the provided function._81 ///_81 /// Iteration is stopped early if the function returns `false`._81 /// The order of iteration is undefined._81 pub fun forEach(_ function: ((AccountKey): Bool))_81_81 /// The total number of unrevoked keys in this account._81 pub let count: UInt64_81 }_81}
Any code can get the PublicAccount
for an account address
using the built-in getAccount
function:
_10fun getAccount(_ address: Address): PublicAccount
AuthAccount
Authorized Account object have the type AuthAccount
,
which represents the authorized portion of an account.
Access to an AuthAccount
means having full access to its storage,
public keys, and code.
Only signed transactions can get the AuthAccount
for an account.
For each signer of the transaction that signs as an authorizer, the corresponding AuthAccount
object is passed
to the prepare
phase of the transaction.
_296pub struct AuthAccount {_296_296 /// The address of the account._296 pub let address: Address_296_296 /// The FLOW balance of the default vault of this account._296 pub let balance: UFix64_296_296 /// The FLOW balance of the default vault of this account that is available to be moved._296 pub let availableBalance: UFix64_296_296 /// The current amount of storage used by the account in bytes._296 pub let storageUsed: UInt64_296_296 /// The storage capacity of the account in bytes._296 pub let storageCapacity: UInt64_296_296 /// The contracts deployed to the account._296 pub let contracts: AuthAccount.Contracts_296_296 /// The keys assigned to the account._296 pub let keys: AuthAccount.Keys_296_296 /// The inbox allows bootstrapping (sending and receiving) capabilities._296 pub let inbox: AuthAccount.Inbox_296_296 /// All public paths of this account._296 pub let publicPaths: [PublicPath]_296_296 /// All private paths of this account._296 pub let privatePaths: [PrivatePath]_296_296 /// All storage paths of this account._296 pub let storagePaths: [StoragePath]_296_296 /// **DEPRECATED**: Use `keys.add` instead._296 ///_296 /// Adds a public key to the account._296 ///_296 /// The public key must be encoded together with their signature algorithm, hashing algorithm and weight._296 pub fun addPublicKey(_ publicKey: [UInt8])_296_296 /// **DEPRECATED**: Use `keys.revoke` instead._296 ///_296 /// Revokes the key at the given index._296 pub fun removePublicKey(_ index: Int)_296_296 /// Saves the given object into the account's storage at the given path._296 ///_296 /// Resources are moved into storage, and structures are copied._296 ///_296 /// If there is already an object stored under the given path, the program aborts._296 ///_296 /// The path must be a storage path, i.e., only the domain `storage` is allowed._296 pub fun save<T: Storable>(_ value: T, to: StoragePath)_296_296 /// Reads the type of an object from the account's storage which is stored under the given path,_296 /// or nil if no object is stored under the given path._296 ///_296 /// If there is an object stored, the type of the object is returned without modifying the stored object._296 ///_296 /// The path must be a storage path, i.e., only the domain `storage` is allowed._296 pub fun type(at: StoragePath): Type?_296_296 /// Loads an object from the account's storage which is stored under the given path,_296 /// or nil if no object is stored under the given path._296 ///_296 /// If there is an object stored,_296 /// the stored resource or structure is moved out of storage and returned as an optional._296 ///_296 /// When the function returns, the storage no longer contains an object under the given path._296 ///_296 /// The given type must be a supertype of the type of the loaded object._296 /// If it is not, the function panics._296 ///_296 /// The given type must not necessarily be exactly the same as the type of the loaded object._296 ///_296 /// The path must be a storage path, i.e., only the domain `storage` is allowed._296 pub fun load<T: Storable>(from: StoragePath): T?_296_296 /// Returns a copy of a structure stored in account storage under the given path,_296 /// without removing it from storage,_296 /// or nil if no object is stored under the given path._296 ///_296 /// If there is a structure stored, it is copied._296 /// The structure stays stored in storage after the function returns._296 ///_296 /// The given type must be a supertype of the type of the copied structure._296 /// If it is not, the function panics._296 ///_296 /// The given type must not necessarily be exactly the same as the type of the copied structure._296 ///_296 /// The path must be a storage path, i.e., only the domain `storage` is allowed._296 pub fun copy<T: AnyStruct>(from: StoragePath): T?_296_296 /// Returns a reference to an object in storage without removing it from storage._296 ///_296 /// If no object is stored under the given path, the function returns nil._296 /// If there is an object stored, a reference is returned as an optional,_296 /// provided it can be borrowed using the given type._296 /// If the stored object cannot be borrowed using the given type, the function panics._296 ///_296 /// The given type must not necessarily be exactly the same as the type of the borrowed object._296 ///_296 /// The path must be a storage path, i.e., only the domain `storage` is allowed_296 pub fun borrow<T: &Any>(from: StoragePath): T?_296_296 /// Creates a capability at the given public or private path,_296 /// which targets the given public, private, or storage path._296 ///_296 /// The target path leads to the object that will provide the functionality defined by this capability._296 ///_296 /// The given type defines how the capability can be borrowed, i.e., how the stored value can be accessed._296 ///_296 /// Returns nil if a link for the given capability path already exists, or the newly created capability if not._296 ///_296 /// It is not necessary for the target path to lead to a valid object; the target path could be empty,_296 /// or could lead to an object which does not provide the necessary type interface:_296 /// The link function does **not** check if the target path is valid/exists at the time the capability is created_296 /// and does **not** check if the target value conforms to the given type._296 ///_296 /// The link is latent._296 ///_296 /// The target value might be stored after the link is created,_296 /// and the target value might be moved out after the link has been created._296 pub fun link<T: &Any>(_ newCapabilityPath: CapabilityPath, target: Path): Capability<T>?_296_296 /// Creates a capability at the given public or private path which targets this account._296 ///_296 /// Returns nil if a link for the given capability path already exists, or the newly created capability if not._296 pub fun linkAccount(_ newCapabilityPath: PrivatePath): Capability<&AuthAccount>?_296_296 /// Returns the capability at the given private or public path._296 pub fun getCapability<T: &Any>(_ path: CapabilityPath): Capability<T>_296_296 /// Returns the target path of the capability at the given public or private path,_296 /// or nil if there exists no capability at the given path._296 pub fun getLinkTarget(_ path: CapabilityPath): Path?_296_296 /// Removes the capability at the given public or private path._296 pub fun unlink(_ path: CapabilityPath)_296_296 /// Iterate over all the public paths of an account._296 /// passing each path and type in turn to the provided callback function._296 ///_296 /// The callback function takes two arguments:_296 /// 1. The path of the stored object_296 /// 2. The runtime type of that object_296 ///_296 /// Iteration is stopped early if the callback function returns `false`._296 ///_296 /// The order of iteration, as well as the behavior of adding or removing objects from storage during iteration,_296 /// is undefined._296 pub fun forEachPublic(_ function: ((PublicPath, Type): Bool))_296_296 /// Iterate over all the private paths of an account._296 /// passing each path and type in turn to the provided callback function._296 ///_296 /// The callback function takes two arguments:_296 /// 1. The path of the stored object_296 /// 2. The runtime type of that object_296 ///_296 /// Iteration is stopped early if the callback function returns `false`._296 ///_296 /// The order of iteration, as well as the behavior of adding or removing objects from storage during iteration,_296 /// is undefined._296 pub fun forEachPrivate(_ function: ((PrivatePath, Type): Bool))_296_296 /// Iterate over all the stored paths of an account._296 /// passing each path and type in turn to the provided callback function._296 ///_296 /// The callback function takes two arguments:_296 /// 1. The path of the stored object_296 /// 2. The runtime type of that object_296 ///_296 /// Iteration is stopped early if the callback function returns `false`._296 ///_296 /// The order of iteration, as well as the behavior of adding or removing objects from storage during iteration,_296 /// is undefined._296 pub fun forEachStored(_ function: ((StoragePath, Type): Bool))_296_296 pub struct Contracts {_296_296 /// The names of all contracts deployed in the account._296 pub let names: [String]_296_296 /// Adds the given contract to the account._296 ///_296 /// The `code` parameter is the UTF-8 encoded representation of the source code._296 /// The code must contain exactly one contract or contract interface,_296 /// which must have the same name as the `name` parameter._296 ///_296 /// All additional arguments that are given are passed further to the initializer_296 /// of the contract that is being deployed._296 ///_296 /// The function fails if a contract/contract interface with the given name already exists in the account,_296 /// if the given code does not declare exactly one contract or contract interface,_296 /// or if the given name does not match the name of the contract/contract interface declaration in the code._296 ///_296 /// Returns the deployed contract._296 pub fun add(_296 name: String,_296 code: [UInt8]_296 ): DeployedContract_296_296 /// **Experimental**_296 ///_296 /// Updates the code for the contract/contract interface in the account._296 ///_296 /// The `code` parameter is the UTF-8 encoded representation of the source code._296 /// The code must contain exactly one contract or contract interface,_296 /// which must have the same name as the `name` parameter._296 ///_296 /// Does **not** run the initializer of the contract/contract interface again._296 /// The contract instance in the world state stays as is._296 ///_296 /// Fails if no contract/contract interface with the given name exists in the account,_296 /// if the given code does not declare exactly one contract or contract interface,_296 /// or if the given name does not match the name of the contract/contract interface declaration in the code._296 ///_296 /// Returns the deployed contract for the updated contract._296 pub fun update__experimental(name: String, code: [UInt8]): DeployedContract_296_296 /// Returns the deployed contract for the contract/contract interface with the given name in the account, if any._296 ///_296 /// Returns nil if no contract/contract interface with the given name exists in the account._296 pub fun get(name: String): DeployedContract?_296_296 /// Removes the contract/contract interface from the account which has the given name, if any._296 ///_296 /// Returns the removed deployed contract, if any._296 ///_296 /// Returns nil if no contract/contract interface with the given name exists in the account._296 pub fun remove(name: String): DeployedContract?_296_296 /// Returns a reference of the given type to the contract with the given name in the account, if any._296 ///_296 /// Returns nil if no contract with the given name exists in the account,_296 /// or if the contract does not conform to the given type._296 pub fun borrow<T: &Any>(name: String): T?_296 }_296_296 pub struct Keys {_296_296 /// Adds a new key with the given hashing algorithm and a weight._296 ///_296 /// Returns the added key._296 pub fun add(_296 publicKey: PublicKey,_296 hashAlgorithm: HashAlgorithm,_296 weight: UFix64_296 ): AccountKey_296_296 /// Returns the key at the given index, if it exists, or nil otherwise._296 ///_296 /// Revoked keys are always returned, but they have `isRevoked` field set to true._296 pub fun get(keyIndex: Int): AccountKey?_296_296 /// Marks the key at the given index revoked, but does not delete it._296 ///_296 /// Returns the revoked key if it exists, or nil otherwise._296 pub fun revoke(keyIndex: Int): AccountKey?_296_296 /// Iterate over all unrevoked keys in this account,_296 /// passing each key in turn to the provided function._296 ///_296 /// Iteration is stopped early if the function returns `false`._296 /// The order of iteration is undefined._296 pub fun forEach(_ function: ((AccountKey): Bool))_296_296 /// The total number of unrevoked keys in this account._296 pub let count: UInt64_296 }_296_296 pub struct Inbox {_296_296 /// Publishes a new Capability under the given name,_296 /// to be claimed by the specified recipient._296 pub fun publish(_ value: Capability, name: String, recipient: Address)_296_296 /// Unpublishes a Capability previously published by this account._296 ///_296 /// Returns `nil` if no Capability is published under the given name._296 ///_296 /// Errors if the Capability under that name does not match the provided type._296 pub fun unpublish<T: &Any>(_ name: String): Capability<T>?_296_296 /// Claims a Capability previously published by the specified provider._296 ///_296 /// Returns `nil` if no Capability is published under the given name,_296 /// or if this account is not its intended recipient._296 ///_296 /// Errors if the Capability under that name does not match the provided type._296 pub fun claim<T: &Any>(_ name: String, provider: Address): Capability<T>?_296 }_296}
A script can get the AuthAccount
for an account address using the built-in getAuthAccount
function:
_10fun getAuthAccount(_ address: Address): AuthAccount
This AuthAccount
object can perform all operations associated with authorized accounts,
and as such this function is only available in scripts,
which discard their changes upon completion.
Attempting to use this function outside of a script will cause a type error.
Account Creation
Accounts can be created by calling the AuthAccount
constructor
and passing the account that should pay for the account creation for the payer
parameter.
The payer
must have enough funds to be able to create an account.
If the account does not have the required funds, the program aborts.
_10transaction() {_10 prepare(signer: AuthAccount) {_10 let account = AuthAccount(payer: signer)_10 }_10}
Account Keys
An account (both PublicAccount
and AuthAccount
) has keys associated with it.
An account key has the following structure.
_10struct AccountKey {_10 let keyIndex: Int_10 let publicKey: PublicKey_10 let hashAlgorithm: HashAlgorithm_10 let weight: UFix64_10 let isRevoked: Bool_10}
Refer to the PublicKey
section for more details on the creation and validity of public keys.
Account Key API
Account key API provides a set of functions to manage account keys.
Add Account Keys
To authorize access to the account, keys can be added using the add()
function.
Keys can only be added to an AuthAccount
.
For example, to create an account and have the signer of the transaction pay for the account creation, and authorize one key to access the account:
_16transaction(publicKey: [UInt8]) {_16 prepare(signer: AuthAccount) {_16 let key = PublicKey(_16 publicKey: publicKey,_16 signatureAlgorithm: SignatureAlgorithm.ECDSA_P256_16 )_16_16 let account = AuthAccount(payer: signer)_16_16 account.keys.add(_16 publicKey: key,_16 hashAlgorithm: HashAlgorithm.SHA3_256,_16 weight: 10.0_16 )_16 }_16}
To add a public key to an existing account, which signed the transaction:
_14transaction(publicKey: [UInt8]) {_14 prepare(signer: AuthAccount) {_14 let key = PublicKey(_14 publicKey: publicKey,_14 signatureAlgorithm: SignatureAlgorithm.ECDSA_P256_14 )_14_14 signer.keys.add(_14 publicKey: key,_14 hashAlgorithm: HashAlgorithm.SHA3_256,_14 weight: 10.0_14 )_14 }_14}
⚠️ Note: Keys can also be added using the addPublicKey
function.
However, this method is currently deprecated and is available only for the backward compatibility.
The addPublicKey
method accepts the public key encoded together with their signature algorithm,
hashing algorithm and weight.
_10transaction(key: [UInt8]) {_10 prepare(signer: AuthAccount) {_10 let account = AuthAccount(payer: signer)_10 account.addPublicKey(key)_10 }_10}
Get Account Keys
Keys that are added to an account can be retrieved using get()
function, using the index of the key.
Revoked keys are always returned, but they have isRevoked
field set to true.
Returns nil
if there is no key available at the given index.
Keys can be retrieved from both PublicAccout
and AuthAccount
.
_10transaction() {_10 prepare(signer: AuthAccount) {_10 // Get a key from an auth account._10 let keyA = signer.keys.get(keyIndex: 2)_10_10 // Get a key from the public aacount._10 let publicAccount = getAccount(0x42)_10 let keyB = publicAccount.keys.get(keyIndex: 2)_10 }_10}
Revoke Account Keys
Keys that have been added to an account can be revoked using revoke()
function.
Revoke function only marks the key at the given index as revoked, but never deletes it.
Keys can only be revoked from an AuthAccount
.
_10transaction() {_10 prepare(signer: AuthAccount) {_10 // Get a key from an auth account._10 let keyA = signer.keys.revoke(keyIndex: 2)_10 }_10}
⚠️ Note: Keys can also be removed using the removePublicKey
function.
However, this method is deprecated and is available only for the backward compatibility.
Account Inbox
Accounts also possess an Inbox
that can be used to make Capabilities available to specific accounts.
The functions in this Inbox
provide a convenient means to "bootstrap" Capabilities,
setting up an initial connection between two accounts that will later allow them to transfer data or permissions through a Capability.
Publishing a Capability
An account (the provider) that would like to provide a Capability to another account (the recipient) can do so using the publish
function:
_10fun publish(_ value: Capability, name: String, recipient: Address)
This publishes the specified Capability using the provided string as an identifier, to be later claimed by the recipient. Note, however, that until the recipient does claim this Capability, it is stored on the provider's account, and contributes towards their Account Storage total.
Calling this function emits an event, InboxValuePublished
,
that includes the address of both the provider and the recipient, as well as the name and the type of the published Capability.
Refer to the Core Events
section for more details on this event.
Claiming a Capability
The intended recipient of a Capability can claim that Capability from the provider using the claim
function:
_10fun claim<T: &Any>(_ name: String, provider: Address): Capability<T>?
This looks up the specified name in the provider's inbox, returning it to the recipient if it is present,
conforms to the provided type argument, and is intended for the calling recipient.
If the provider has no Capability stored under the provided name,
or if the calling recipient is not the intended recipient of the Capability, the function returns nil
.
If the borrow type of the Capability is not a subtype of the provided type argument, the function will error at runtime.
Upon successful completion of the claim
function, the claimed Capability is removed from the provider's inbox.
Note that this means a given Capability can only be claimed once.
Calling this function emits an event, InboxValueClaimed
,
that includes the address of both the provider and the recipient, as well as the name of the claimed Capability.
Refer to the Core Events
section for more details on this event.
Unpublishing a Capability
If the provider of a Capability no longer wishes for it to be published for some reason (e.g. they no longer wish to pay for its storage costs),
they can unpublish it using the unpublish
function:
_10fun unpublish<T: &Any>(_ name: String): Capability<T>?
This looks up the specified name in the provider's inbox, returning it to the provider if it is present and conforms to the provided type argument.
If the provider has no Capability stored under the provided name, the function returns nil
.
If the borrow type of the Capability is not a subtype of the provided type argument, the function will error at runtime.
Upon successful completion of the unpublish
function, the unpublished Capability is removed from the provider's inbox.
Calling this function emits an event, InboxValueUnpublished
,
that includes the address of the provider, and the name of the claimed Capability.
Refer to the Core Events
section for more details on this event.
Account Storage
All accounts have storage. Both resources and structures can be stored in account storage.
Paths
Objects are stored under paths. Paths consist of a domain and an identifier.
Paths start with the character /
, followed by the domain, the path separator /
,
and finally the identifier.
For example, the path /storage/test
has the domain storage
and the identifier test
.
There are only three valid domains: storage
, private
, and public
.
Objects in storage are always stored in the storage
domain.
Paths in the storage domain have type StoragePath
,
in the private domain PrivatePath
,
and in the public domain PublicPath
.
PrivatePath
and PublicPath
are subtypes of CapabilityPath
.
Both StoragePath
and CapabilityPath
are subtypes of Path
.
Path | |||
CapabilityPath | StoragePath | ||
PrivatePath | PublicPath |
Path Functions
_10fun toString(): String
Returns the string representation of the path.
_10let storagePath = /storage/path_10_10storagePath.toString() // is "/storage/path"
There are also utilities to produce paths from strings:
_10fun PublicPath(identifier: string): PublicPath?_10fun PrivatePath(identifier: string): PrivatePath?_10fun StoragePath(identifier: string): StoragePath?
Each of these functions take an identifier and produce a path of the appropriate domain:
_10let pathID = "foo"_10let path = PublicPath(identifier: pathID) // is /public/foo
Account Storage API
Account storage is accessed through the following functions of AuthAccount
.
This means that any code that has access to the authorized account has access
to all its stored objects.
_10fun save<T>(_ value: T, to: StoragePath)
Saves an object to account storage. Resources are moved into storage, and structures are copied.
T
is the type parameter for the object type.
It can be inferred from the argument's type.
If there is already an object stored under the given path, the program aborts.
The path must be a storage path, i.e., only the domain storage
is allowed.
_10fun type(at: StoragePath): Type?
Reads the type of an object from the account's storage which is stored under the given path, or nil if no object is stored under the given path.
If there is an object stored, the type of the object is returned without modifying the stored object.
The path must be a storage path, i.e., only the domain storage
is allowed
_10fun load<T>(from: StoragePath): T?
Loads an object from account storage.
If no object is stored under the given path, the function returns nil
.
If there is an object stored, the stored resource or structure is moved
out of storage and returned as an optional.
When the function returns, the storage no longer contains an object
under the given path.
T
is the type parameter for the object type.
A type argument for the parameter must be provided explicitly.
The type T
must be a supertype of the type of the loaded object.
If it is not, execution will abort with an error.
The given type does not necessarily need to be exactly the same as the type of the loaded object.
The path must be a storage path, i.e., only the domain storage
is allowed.
_10fun copy<T: AnyStruct>(from: StoragePath): T?
Returns a copy of a structure stored in account storage, without removing it from storage.
If no structure is stored under the given path, the function returns nil
.
If there is a structure stored, it is copied.
The structure stays stored in storage after the function returns.
T
is the type parameter for the structure type.
A type argument for the parameter must be provided explicitly.
The type T
must be a supertype of the type of the copied structure.
If it is not, execution will abort with an error.
The given type does not necessarily need to be exactly the same as
the type of the copied structure.
The path must be a storage path, i.e., only the domain storage
is allowed.
_80// Declare a resource named `Counter`._80//_80resource Counter {_80 pub var count: Int_80_80 pub init(count: Int) {_80 self.count = count_80 }_80}_80_80// In this example an authorized account is available through the constant `authAccount`._80_80// Create a new instance of the resource type `Counter`_80// and save it in the storage of the account._80//_80// The path `/storage/counter` is used to refer to the stored value._80// Its identifier `counter` was chosen freely and could be something else._80//_80authAccount.save(<-create Counter(count: 42), to: /storage/counter)_80_80// Run-time error: Storage already contains an object under path `/storage/counter`_80//_80authAccount.save(<-create Counter(count: 123), to: /storage/counter)_80_80// Load the `Counter` resource from storage path `/storage/counter`._80//_80// The new constant `counter` has the type `Counter?`, i.e., it is an optional,_80// and its value is the counter resource, that was saved at the beginning_80// of the example._80//_80let counter <- authAccount.load<@Counter>(from: /storage/counter)_80_80// The storage is now empty, there is no longer an object stored_80// under the path `/storage/counter`._80_80// Load the `Counter` resource again from storage path `/storage/counter`._80//_80// The new constant `counter2` has the type `Counter?` and is `nil`,_80// as nothing is stored under the path `/storage/counter` anymore,_80// because the previous load moved the counter out of storage._80//_80let counter2 <- authAccount.load<@Counter>(from: /storage/counter)_80_80// Create another new instance of the resource type `Counter`_80// and save it in the storage of the account._80//_80// The path `/storage/otherCounter` is used to refer to the stored value._80//_80authAccount.save(<-create Counter(count: 123), to: /storage/otherCounter)_80_80// Load the `Vault` resource from storage path `/storage/otherCounter`._80//_80// The new constant `vault` has the type `Vault?` and its value is `nil`,_80// as there is a resource with type `Counter` stored under the path,_80// which is not a subtype of the requested type `Vault`._80//_80let vault <- authAccount.load<@Vault>(from: /storage/otherCounter)_80_80// The storage still stores a `Counter` resource under the path `/storage/otherCounter`._80_80// Save the string "Hello, World" in storage_80// under the path `/storage/helloWorldMessage`._80_80authAccount.save("Hello, world!", to: /storage/helloWorldMessage)_80_80// Copy the stored message from storage._80//_80// After the copy, the storage still stores the string under the path._80// Unlike `load`, `copy` does not remove the object from storage._80//_80let message = authAccount.copy<String>(from: /storage/helloWorldMessage)_80_80// Create a new instance of the resource type `Vault`_80// and save it in the storage of the account._80//_80authAccount.save(<-createEmptyVault(), to: /storage/vault)_80_80// Invalid: Cannot copy a resource, as this would allow arbitrary duplication._80//_80let vault <- authAccount.copy<@Vault>(from: /storage/vault)
As it is convenient to work with objects in storage
without having to move them out of storage,
as it is necessary for resources,
it is also possible to create references to objects in storage:
This is possible using the borrow
function of an AuthAccount
:
_10fun borrow<T: &Any>(from: StoragePath): T?
Returns a reference to an object in storage without removing it from storage.
If no object is stored under the given path, the function returns nil
.
If there is an object stored, a reference is returned as an optional.
T
is the type parameter for the object type.
A type argument for the parameter must be provided explicitly.
The type argument must be a reference to any type (&Any
; Any
is the supertype of all types).
It must be possible to create the given reference type T
for the stored / borrowed object.
If it is not, execution will abort with an error.
The given type does not necessarily need to be exactly the same as the type of the borrowed object.
The path must be a storage path, i.e., only the domain storage
is allowed.
_63// Declare a resource interface named `HasCount`, that has a field `count`_63//_63resource interface HasCount {_63 count: Int_63}_63_63// Declare a resource named `Counter` that conforms to `HasCount`_63//_63resource Counter: HasCount {_63 pub var count: Int_63_63 pub init(count: Int) {_63 self.count = count_63 }_63}_63_63// In this example an authorized account is available through the constant `authAccount`._63_63// Create a new instance of the resource type `Counter`_63// and save it in the storage of the account._63//_63// The path `/storage/counter` is used to refer to the stored value._63// Its identifier `counter` was chosen freely and could be something else._63//_63authAccount.save(<-create Counter(count: 42), to: /storage/counter)_63_63// Create a reference to the object stored under path `/storage/counter`,_63// typed as `&Counter`._63//_63// `counterRef` has type `&Counter?` and is a valid reference, i.e. non-`nil`,_63// because the borrow succeeded:_63//_63// There is an object stored under path `/storage/counter`_63// and it has type `Counter`, so it can be borrowed as `&Counter`_63//_63let counterRef = authAccount.borrow<&Counter>(from: /storage/counter)_63_63counterRef?.count // is `42`_63_63// Create a reference to the object stored under path `/storage/counter`,_63// typed as `&{HasCount}`._63//_63// `hasCountRef` is non-`nil`, as there is an object stored under path `/storage/counter`,_63// and the stored value of type `Counter` conforms to the requested type `{HasCount}`:_63// the type `Counter` implements the restricted type's restriction `HasCount`_63_63let hasCountRef = authAccount.borrow<&{HasCount}>(from: /storage/counter)_63_63// Create a reference to the object stored under path `/storage/counter`,_63// typed as `&{SomethingElse}`._63//_63// `otherRef` is `nil`, as there is an object stored under path `/storage/counter`,_63// but the stored value of type `Counter` does not conform to the requested type `{Other}`:_63// the type `Counter` does not implement the restricted type's restriction `Other`_63_63let otherRef = authAccount.borrow<&{Other}>(from: /storage/counter)_63_63// Create a reference to the object stored under path `/storage/nonExistent`,_63// typed as `&{HasCount}`._63//_63// `nonExistentRef` is `nil`, as there is nothing stored under path `/storage/nonExistent`_63//_63let nonExistentRef = authAccount.borrow<&{HasCount}>(from: /storage/nonExistent)
Storage Iteration
It is possible to iterate over an account's storage using the following iteration functions:
_10fun forEachPublic(_ function: ((PublicPath, Type): Bool))_10fun forEachPrivate(_ function: ((PrivatePath, Type): Bool))_10fun forEachStored(_ function: ((StoragePath, Type): Bool))
Each of these iterates over every element in the specified domain (public, private, and storage),
applying the function argument to each.
The first argument of the function is the path of the element, and the second is its runtime type.
In the case of the private
and public
path iteration functions,
this is the runtime type of the capability linked at that path.
The Bool
return value determines whether iteration continues;
true
will proceed to the next stored element,
while false
will terminate iteration.
The specific order in which the objects are iterated over is undefined,
as is the behavior when a path is added or removed from storage.
The order of iteration is undefined. Do not rely on any particular behaviour.
Saving to or removing from storage during iteration can cause the order in which values are stored to change arbitrarily.
Continuing to iterate after such an operation will cause Cadence to panic and abort execution.
In order to avoid such errors, we recommend not modifying storage during iteration.
If you do, return false
from the iteration callback to cause iteration to end after the mutation like so:
_13account.save(1, to: /storage/foo1)_13account.save(2, to: /storage/foo2)_13account.save(3, to: /storage/foo3)_13account.save("qux", to: /storage/foo4)_13_13account.forEachStored(fun (path: StoragePath, type: Type): Bool {_13 if type == Type<String>() {_13 account.save("bar", to: /storage/foo5)_13 // returning false here ends iteration after storage is modified, preventing a panic_13 return false_13 }_13 return true_13})
The iteration will skip any broken elements in the storage.
An element could be broken due to invalid types associated with the stored value.
e.g: A value belongs to type T
of a contract with syntax/semantic errors.
Storage limit
An account's storage is limited by its storage capacity.
An account's storage used is the sum of the size of all the data that is stored in an account (in MB). An account's storage capacity is a value that is calculated from the amount of FLOW that is stored in the account's main FLOW token vault.
At the end of every transaction, the storage used is compared to the storage capacity. For all accounts involved in the transaction, if the account's storage used is greater than its storage capacity, the transaction will fail.
An account's storage used and storage capacity can be checked using the storageUsed
and storageCapacity
fields.
The fields represent current values of storage which means this would be true:
_10let storageUsedBefore = authAccount.storageUsed_10authAccount.save(<-create Counter(count: 123), to: /storage/counter)_10let storageUsedAfter = authAccount.storageUsed_10_10let storageUsedChanged = storageUsedBefore != storageUsedAfter // is true