Skip to main content

FLOW for Wallets & Custodians

Creating an Account

A user needs a Flow account in order to receive, hold and send FLOW tokens. The accounts & keys documentation provides a detailed overview of how accounts work on Flow.

You can create an account using templates and helper code from one of the Flow SDKs:

Receiving FLOW Deposits

Every Flow account supports the FLOW token by default. Once an account is created, it is already provisioned to receive FLOW deposits from other users.

FLOW, like any other FungibleToken on Flow, is stored in a special resource called a FungibleToken.Vault. Every new account is created with an empty FLOW vault stored at the /storage/flowTokenVault storage path.


_10
let vault = account.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)

Conceptually, a vault is like a mailbox with a lock. Anybody can deposit tokens but only the account holder can withdraw them. This functionality is made possible by resource capabilities in Cadence. Each account publishes a FungibleToken.Receiver interface that points to its FLOW vault. The receiver is the mail slot; it allows others to deposit FLOW into a vault without stealing what's inside.

Here's how you deposit FLOW into an account:


_10
let receiver = account
_10
.getCapability(/public/flowTokenReceiver)
_10
.borrow<&{FungibleToken.Receiver}>()
_10
?? panic("Could not borrow FungibleToken.Receiver reference")
_10
_10
receiver.deposit(from: <-senderVault)

Detecting Deposits

The FlowToken contract emits a FlowToken.TokensDeposited event whenever tokens move between accounts.


_10
pub event TokensDeposited(amount: UFix64, to: Address?)

You can query for this event to detect when tokens are deposited into a user's account.

TODO: Link to event querying docs

Receiving FLOW from an ICO

A portion of the initial FLOW token supply will be distributed directly to new and existing backers who participate in the initial coin offering (ICO) of FLOW. Tokens distributed through an ICO are subject to a lockup period, meaning they can't be sold, transferred or traded until sufficient time has passed.

Although locked tokens can't be liquidated, they can still be used for staking. Any staking rewards accrued from locked tokens are deposited into the rewardee's account as unlocked tokens.

FLOW.ICO vs FLOW

It is the responsibility of the custodian to ensure that FLOW received from an ICO event (FLOW.ICO) is not liquidated before the legal lockup period has passed. In order to ensure that this does not happen, it is important to store FLOW.ICO tokens separately from unlocked FLOW tokens.

To achieve this separation, a custodian should provision a new token vault that follows this standard:

FLOW.ICO Token Vault

  • Type: FlowToken.Vault
  • Location: /storage/lockedFlowTokenVault

Creating the FLOW.ICO Vault

The following Cadence transaction creates an empty FLOW token vault and stores it at the standard FLOW.ICO storage path. This transaction assumes that the account has already been created.


_23
import FungibleToken from 0xFUNGIBLE_TOKEN_ADDRESS
_23
import FlowToken from 0xFLOW_TOKEN_ADDRESS
_23
_23
transaction {
_23
prepare(signer: AuthAccount) {
_23
// Create an empty FlowToken Vault and store it
_23
signer.save(<-FlowToken.createEmptyVault(), to: /storage/lockedFlowTokenVault)
_23
_23
// Create a public capability to the Vault that only exposes
_23
// the deposit function through the Receiver interface
_23
signer.link<&FlowToken.Vault{FungibleToken.Receiver}>(
_23
/public/lockedFlowTokenReceiver,
_23
target: /storage/lockedFlowTokenVault
_23
)
_23
_23
// Create a public capability to the Vault that only exposes
_23
// the balance field through the Balance interface
_23
signer.link<&FlowToken.Vault{FungibleToken.Balance}>(
_23
/public/lockedFlowTokenBalance,
_23
target: /storage/lockedFlowTokenVault
_23
)
_23
}
_23
}

Below is a variation of the above transaction that provisions the FLOW.ICO vault at the time of account creation.


_20
import FungibleToken from 0xFUNGIBLE_TOKEN_ADDRESS
_20
import FlowToken from 0xFLOW_TOKEN_ADDRESS
_20
_20
transaction {
_20
prepare(signer: AuthAccount) {
_20
let newAccount = AuthAccount(payer: signer)
_20
_20
newAccount.save(<-FlowToken.createEmptyVault(), to: /storage/lockedFlowTokenVault)
_20
_20
newAccount.link<&FlowToken.Vault{FungibleToken.Receiver}>(
_20
/public/lockedFlowTokenReceiver,
_20
target: /storage/lockedFlowTokenVault
_20
)
_20
_20
newAccount.link<&FlowToken.Vault{FungibleToken.Balance}>(
_20
/public/lockedFlowTokenBalance,
_20
target: /storage/lockedFlowTokenVault
_20
)
_20
}
_20
}

Receiving a FLOW.ICO Deposit

All FLOW tokens deposited from an ICO event will be automatically routed to the FLOW.ICO vault stored at the /storage/lockedFlowTokenVault storage path. If an account does not contain a vault at this path, it cannot receive ICO deposits.

Getting the FLOW.ICO Balance

See the next section for an example of how to query the balance of a FlowToken.Vault instance.

Getting the Balance of an Account

From Cadence

Similar to the token receiver, each account publishes a FungibleToken.Balance capability that allows anybody to read the balance of an account. This allows Cadence programs to fetch the balance of an account directly in code.


_10
let balanceRef = account
_10
.getCapability(/public/flowTokenBalance)
_10
.borrow<&FlowToken.Vault{FungibleToken.Balance}>()
_10
?? panic("Could not borrow FungibleToken.Balance reference")
_10
_10
log(balanceRef.balance)

The above code can be executed as part of a read-only Cadence script.

From the Access API

The FLOW Access API makes it easy to query an account's balance without writing any Cadence code.

The GetAccount RPC method includes a balance field, which holds the FLOW token balance for the requested account.


_12
import (
_12
"github.com/onflow/flow-go-sdk"
_12
"github.com/onflow/flow-go-sdk/client"
_12
)
_12
_12
func main() {
_12
flowClient, _ := client.New(accessAPIHost)
_12
_12
account, _ := flowClient.GetAccount(ctx, address)
_12
_12
fmt.Println(account.Balance)
_12
}

Sending FLOW

Below is an example of a transaction that transfers FLOW from one account to another.


_32
import FungibleToken from 0xFUNGIBLE_TOKEN_ADDRESS
_32
import FlowToken from 0xFLOW_TOKEN_ADDRESS
_32
_32
transaction(amount: UFix64, to: Address) {
_32
_32
// The FungibleToken.Vault resource that holds the tokens to be transferred
_32
let sentVault: @FungibleToken.Vault
_32
_32
prepare(sender: AuthAccount) {
_32
// Get a reference to the sender's stored vault
_32
let vault = sender.
_32
borrow<&ExampleToken.Vault>(from: /storage/flowTokenVault)
_32
?? panic("Could not borrow reference to the owner's Vault!")
_32
_32
// Withdraw tokens from the sender's stored vault
_32
self.sentVault <- vault.withdraw(amount: amount)
_32
}
_32
_32
execute {
_32
// Get the recipient's public account object
_32
let recipient = getAccount(to)
_32
_32
// Get a reference to the recipient's FungibleToken.Receiver
_32
let receiver = recipient
_32
.getCapability(/public/flowTokenReceiver)
_32
.borrow<&{FungibleToken.Receiver}>()
_32
?? panic("Could not borrow receiver reference to the recipient's Vault")
_32
_32
// Deposit the withdrawn tokens in the recipient's receiver
_32
receiver.deposit(from: <-self.sentVault)
_32
}
_32
}

This transaction template is available for use in our SDKs:

Staking FLOW

The FLOW staking documentation outlines the steps a custodian can take to support staking through a trusted node operator.