Build on Flow | Learn FCL - 16. How to Send FLOW Tokens to Another Account
Tags: javascript, tutorial, fcl, onflow
Published: 2022-08-29 09:20:00

## Overview

Fungible tokens are often used as a means of payment - for products or services. In this article we will guide you how to:

- get current balance of FLOW on a specific account
- compose FLOW transfer transaction
- sign and send it using Blocto or Lilico wallet

### Theory

FLOW token is a contract, which implements [Fungible Token Standard](https://github.com/onflow/flow-ft) interface. If you take a look in the code, you will see that on the higher level totalSupply is defined on implementing contract, but it doesn’t know how much tokens holds each individual account. Each account that would want to own tokens would need to have an instance of the [Vault](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc#L149) resource stored in their account storage. The `Vault` resource has methods that the owner and other users can call. Those methods are limited by`Provider`, `Receiver`, and `Balance` resource interfaces. These interfaces declare pre-conditions and post-conditions that restrict the execution of the functions in the Vault. 

They are separate because it gives the user the ability to share a reference to their Vault that only exposes the fields functions in one or more of the interfaces.

It also gives users the ability to make custom resources that implement these interfaces to do various things with the tokens. For example, a faucet can be implemented by conforming
to the Provider interface.

By using resources and interfaces, users of Fungible Token contracts can send and receive tokens peer-to-peer, without having to interact with a central ledger smart contract. To send tokens to another user, a user would simply withdraw the tokens from their Vault, then call the deposit function on another user's Vault to complete the transfer.

### Step 1 - Installation

Add `"@onflow/fcl": "1.0.0"` as your dependency

### Step 2 - FCL Config

Let’s create `testnet-config.js` file, so we can reuse it in later projects. It will also make our `index.js` file cleaner and allow for an easy swap to mainnet version. The content of the file will be pretty much the same as we covered in previous article:

```jsx
// Configure FCL
import { config } from "@onflow/fcl";

config({
  // Use Testnet Access Node
  "accessNode.api": "https://rest-testnet.onflow.org",
  // We will also specify the network as some of the FCL parts need it to properly do it's work
  "flow.network": "testnet",
  // This will be the title of our DApp
  "app.detail.title": "Meow DApp",
  // This is just a kitten photo, we will use for the icon
  "app.detail.icon": "https://placekitten.com/g/200/200",
  // Next two will define where Wallet Discovery is located
  "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn",
  "discovery.authn.endpoint":
    "https://fcl-discovery.onflow.org/api/testnet/authn",

  // We will also set aliases for the contracts we will use in this example
  "0xFLOW": "0x7e60df042a9c0868",
  "0xFT": "0x9a0766d93b6608b7"
});
```

If you take a look at the end of the config you can see that we’ve defined two aliases for the contracts we will import in our Cadence code:

- `0xFLOW` for `FlowToken` contract
- `0xFT` for `FungibleToken` contract

### Step 4 - Imports

Back to our `index.js` file, where we will add all the necessary imports:

```jsx
import { query, mutate, tx, reauthenticate } from "@onflow/fcl";
import "./testnet-config";
```

### Step 3 - Implement `getFlowBalance` function

Next, let’s create a function, which will check current balance of the account, defined by it’s address.

It will accept single argument `address`, which will be passed to Cadence script and return `UFix64` value, represented as string.

> 💡If you just arrived here and don’t quite know what is happening - don’t be afraid! We’ve got you covered! You can check earlier articles in this series:
- How to Execute Scripts
- How to Send Transactions
> 

```jsx
const getFlowBalance = async (address) => {
  const cadence = `
    import FlowToken from 0xFLOW
    import FungibleToken from 0xFT
    
    pub fun main(address: Address): UFix64 {
      let account = getAccount(address)

      let vaultRef = account.getCapability(/public/flowTokenBalance)
        .borrow<&FlowToken.Vault{FungibleToken.Balance}>()
        ?? panic("Could not borrow Balance reference to the Vault")

      return vaultRef.balance
    }
  `;
  const args = (arg, t) => [arg(address, t.Address)];
  const balance = await query({ cadence, args });
  console.log({ balance });
};
```

> 🧑‍🏫 If you are wondering where we’ve got the code for this transaction - you can check [Fungible Token Standart](https://github.com/onflow/flow-ft) repository on Github:
- [Get Balance Cadence script](https://github.com/onflow/flow-ft/blob/master/transactions/scripts/get_balance.cdc) 
- [Transfer Tokens Cadence Transaction](https://github.com/onflow/flow-ft/blob/master/transactions/transfer_tokens.cdc)

The “problem” is - you won’t be able to find `BalancePublicPath` field set on `FlowToken`contract deployed to [0x9a0766d93b6608b7](https://flow-view-source.com/testnet/account/0x7e60df042a9c0868/contract/FlowToken). The contract was deployed before this useful partern of storing common path became widely used. That’s why we are hard-coding `/public/flowTokenBalance` value which we sourecd from `init` method of the contract. We will also use `/public/flowTokenReceiver` defined there to get capability of the Recepient’s Vault.
> 

While Javacript code is self-explanatory, let’s cover whats is happening in Cadence script. It accepts single argument `address` of type `Address` and returns `UFix64` value:

```jsx
pub fun main(address: Address): UFix64 {
```

First we take account, we are trying to “investigate” by calling `getAccount` function, which will return us [PublicAccount struct](https://docs.onflow.org/cadence/language/accounts/#publicaccount). 

```jsx
let account = getAccount(address)
```

This struct gives us the ability to call `getCapability` method to retrieve necessary capability to FLOW Vault. We know that capability should be exposes on `/public/flowTokenBalance` public path. And we also know that it’s a limited capability `FungibleToken.Balance`, which will only alow us to read the balance of the Vault.

We can check `init` method of [FlowToken contract](https://flow-view-source.com/testnet/account/0x7e60df042a9c0868/contract/FlowToken) (line #187) to get the correct type we need to borrow:

```jsx
<&FlowToken.Vault{FungibleToken.Balance}>
```

In order to operate said capability, we need to get a reference to it with `.borrow` method. We can set the type are are expecting to borrow using angular brackets - and paste the same type as it was defined in `init` method.

```jsx
let vaultRef = account.getCapability(/public/flowTokenBalance)
        .borrow<&FlowToken.Vault{FungibleToken.Balance}>()
        ?? panic("Could not borrow Balance reference to the Vault")
```

If the reference can’t be created (for example stored Capability have different type or can’t be casted to this specific type) - transaction will stop the execution with `panic` message.

### Step 4 - Implement `sendFlow` function

Next on the list is a function, which will accept Recepient’s address and amount of FLOW tokens we want to transfer.

```jsx
const sendFlow = async (recepient, amount) => {
  const cadence = `
    import FungibleToken from 0xFT
    import FlowToken from 0xFLOW

    transaction(recepient: Address, amount: UFix64){
      prepare(signer: AuthAccount){
        let sender = signer.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)
          ?? panic("Could not borrow Provider reference to the Vault")

        let receiverAccount = getAccount(recepient)

        let receiver = receiverAccount.getCapability(/public/flowTokenReceiver)
          .borrow<&FlowToken.Vault{FungibleToken.Receiver}>()
          ?? panic("Could not borrow Receiver reference to the Vault")
 
				let tempVault <- sender.withdraw(amount: amount)
        receiver.deposit(from: <- tempVault)
      }
    }
  `;
  const args = (arg, t) => [arg(recepient, t.Address), arg(amount, t.UFix64)];
  const limit = 500;

  const txId = await mutate({ cadence, args, limit });
  
	console.log("Waiting for transaction to be sealed...");
  
	const txDetails = await tx(txId).onceSealed();
  console.log({ txDetails });
};
```

Cadence code is pretty similar to one we’ve used above to query FLOW balance.

- we are getting full reference to a Sender’s Vault
- we are geting limited `Receiver` reference to Recepient’s Vault
- we are creating temporary Vault via `withdraw` method and passing `amount` as argument
- we are depositing into Recepient’s Vault via `deposit` method and `tempVault`

Notice the syntax of full reference - we don’t specify limiting interface in curly braces and we also specify storage path `/storage/flowTokenVault` . Every account is initialized with FLOW Vault on that path, so it’s safe to assume it’s there for every signer:

```jsx
let sender = signer.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)
```

### Finally

Let's add an IIFE at the end of the file and populate it with methods we have just defined:

```jsx
(async () => {
  console.clear();
	// "reauthenticate" will ensure your session works properly
  // and present you a popup to sign in
  await reauthenticate();

  // This is an example account we've created to this exibition
  // You can replace it with one of your addresses
  const recepient = "0x3e68d80ca405bbac";

  // Check "initial" balance first
  await getFlowBalance(recepient);

  // Send some FLOW tokens to Recepient
  await sendFlow(recepient, "1.337");

  // Ensure that Recepient's balance has been changed
  await getFlowBalance(recepient);
})();
```

After a series of popups and confirmation your console should have the proof that balance of Recepient’s Vault have been changed:

```jsx
{balance: "1002.67500000"}

Waiting for transaction to be sealed... 

txDetails: {
	blockId: "b555b7ca17fac5ad170e3bfc4a85afd3325eb5d4fb56e4be49550dce9413ffad"
	status: 4
	statusString: "SEALED"
	statusCode: 0
	errorMessage: ""
	events: Array(5)
}

{balance: "1004.01200000"}
```

![https://media.giphy.com/media/1BPvv1QvbKV156jyul/giphy-downsized-large.gif](https://media.giphy.com/media/1BPvv1QvbKV156jyul/giphy-downsized-large.gif)

You know what to do next 😉

Until next time! 👋 

## Resources

- **Full Source Code** - [https://codesandbox.io/s/dev-to-16-transfer-flow-tokens-pjq98u](https://codesandbox.io/s/dev-to-16-transfer-flow-tokens-pjq98u?file=/src/testnet-config.js:776-794)
- **Fungible Token Standard** - [https://github.com/onflow/flow-ft](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc#L53)
- **FCL - `mutate`** - [https://docs.onflow.org/fcl/reference/api/#mutate](https://docs.onflow.org/fcl/reference/api/#mutate)
- **FCL - `query`** - [https://docs.onflow.org/fcl/reference/api/#query](https://docs.onflow.org/fcl/reference/api/#query)
- **Cadence - Capabilities** - [https://docs.onflow.org/cadence/language/capability-based-access-control](https://docs.onflow.org/cadence/language/capability-based-access-control/#gatsby-focus-wrapper)
- **Cadence - References** - [https://docs.onflow.org/cadence/language/references](https://docs.onflow.org/cadence/language/references/#gatsby-focus-wrapper)

Other resources you might find useful:

- **Flow Docs Site** - [https://docs.onflow.org/](https://docs.onflow.org/) - More detailed information about Flow blockchain and how to interact with it
- **Flow Portal** - [https://flow.com/](https://flow.com/) - your entry point to Flow
- **FCL JS** - [https://github.com/onflow/fcl-js](https://github.com/onflow/fcl-js) - Source code and ability to contribute to the FCL JS library
- **Cadence** - [https://docs.onflow.org/cadence/](https://docs.onflow.org/cadence/) - Introduction to Cadence
- **Codesandbox** - [https://codesandbox.io](https://codesandbox.io/) - An amazing in-browser IDE enabling quick prototyping