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.
_10let 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:
_10let receiver = account_10 .getCapability(/public/flowTokenReceiver)_10 .borrow<&{FungibleToken.Receiver}>()_10 ?? panic("Could not borrow FungibleToken.Receiver reference")_10_10receiver.deposit(from: <-senderVault)
Detecting Deposits
The FlowToken
contract emits a FlowToken.TokensDeposited
event whenever tokens
move between accounts.
_10pub 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.
_23import FungibleToken from 0xFUNGIBLE_TOKEN_ADDRESS_23import FlowToken from 0xFLOW_TOKEN_ADDRESS_23_23transaction {_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.
_20import FungibleToken from 0xFUNGIBLE_TOKEN_ADDRESS_20import FlowToken from 0xFLOW_TOKEN_ADDRESS_20_20transaction {_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.
_10let balanceRef = account_10 .getCapability(/public/flowTokenBalance)_10 .borrow<&FlowToken.Vault{FungibleToken.Balance}>()_10 ?? panic("Could not borrow FungibleToken.Balance reference")_10_10log(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.
_12import (_12 "github.com/onflow/flow-go-sdk"_12 "github.com/onflow/flow-go-sdk/client"_12)_12_12func 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.
_32import FungibleToken from 0xFUNGIBLE_TOKEN_ADDRESS_32import FlowToken from 0xFLOW_TOKEN_ADDRESS_32_32transaction(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:
- Transfer Tokens with the FCL (Flow Client Library)
- Coming soon: Transfer Tokens with the Go SDK
Staking FLOW
The FLOW staking documentation outlines the steps a custodian can take to support staking through a trusted node operator.