---
id: ft
title: Fungible Tokens (FT)
hide_table_of_contents: false
---
import {FeatureList, Column, Feature} from "@site/src/components/featurelist"
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import BOSGetMetadata from "./ft/bos/get-metadata.md"
import BOSCheckBalance from "./ft/bos/check-balance.md"
import BOSSendToken from "./ft/bos/send.md"
import BOSRegister from "./ft/bos/register.md"
import BOSAttachTokenToCall from "./ft/bos/attach-to-call.md"
import BOSCreateToken from "./ft/bos/create.md"
import WebAppGetMetadata from "./ft/web-app/get-metadata.md"
import WebAppCheckBalance from "./ft/web-app/check-balance.md"
import WebAppSendToken from "./ft/web-app/send.md"
import WebAppRegister from "./ft/web-app/register.md"
import WebAppAttachTokenToCall from "./ft/web-app/attach-to-call.md"
import WebAppCreateToken from "./ft/web-app/create.md"
import CLIGetMetadata from "./ft/near-cli/get-metadata.md"
import CLICheckBalance from "./ft/near-cli/check-balance.md"
import CLISendToken from "./ft/near-cli/send.md"
import CLIRegister from "./ft/near-cli/register.md"
import CLIAttachTokenToCall from "./ft/near-cli/attach-to-call.md"
import CLICreateToken from "./ft/near-cli/create.md"
import SmartContractSendToken from "./ft/smart-contract/send.md"
import SmartContractAttachTokenToCall from "./ft/smart-contract/attach-to-call.md"
Besides the native NEAR token, NEAR accounts have access to a [multitude of tokens](https://guide.ref.finance/developers-1/cli-trading#query-whitelisted-tokens) to use throughout the ecosystem. Moreover, it is even possible for users to create their own fungible tokens.
In contrast with the NEAR native token, fungible token (FT) are **not stored** in the user's account. In fact, each FT lives in **their own contract** which is in charge of doing **bookkeeping**. This is, the contract keeps track of how many tokens each user has, and handles transfers internally.

In order for a contract to be considered a FT-contract it has to follow the [**NEP-141 and NEP-148 standards**](https://nomicon.io/Standards/FungibleToken/). The **NEP-141** & **NEP-148** standards explain the **minimum interface** required to be implemented, as well as the expected functionality.
---
## Token Factory Tool
You can create an FT using the toolbox on [Dev Portal](https://dev.near.org/tools). The FT Tool is a token factory, you can interact with it through graphical interface, or by making calls to its contract.
The FT you create will live in the account `.tkn.primitives.near` (e.g. `test.tkn.primitives.near`).
---
## Deploying Your Own Contract
You can also create a fungible token by deploying and initializing a [canonical FT contract](https://github.com/near-examples/FT).
On initialization you will define the token's metadata such as its name (e.g. Ethereum), symbol (e.g. ETH) and total supply (e.g. 10M). You will also define an `owner`, which will own the tokens **total supply**.
To initialize a FT contract you will need to deploy it and then call the `new` method defining the token's metadata.
```bash
cargo near deploy with-init-call new json-args '{"owner_id": "", "total_supply": "1000000000000000", "metadata": { "spec": "ft-1.0.0", "name": "Example Token Name", "symbol": "EXLT", "decimals": 8 }}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' network-config testnet sign-with-keychain send
```
:::tip
Check the [Contract Wizard](https://dev.near.org/contractwizard.near/widget/ContractWizardUI) to create a personalized FT contract!.
:::
---
## Querying Metadata
You can query the FT's metadata by calling the `ft_metadata`.
---
## Checking Balance
To know how many coins a user has you will need to query the method `ft_balance_of`.
---
## Registering a User
In order for an user to own and transfer tokens they need to first **register** in the contract. This is done by calling `storage_deposit` and attaching 0.00125Ⓝ.
By calling this `storage_deposit` the user can register themselves or **register other users**.
:::info
You can make sure a user is registered by calling `storage_balance_of`.
:::
:::tip
After a user calls the `storage_deposit` the FT will appear in their Wallets.
:::
---
## Transferring Tokens
To send FT to another account you will use the `ft_transfer` method, indicating the receiver and the amount of FT you want to send.
---
## Attaching FTs to a Call
Natively, only NEAR tokens (Ⓝ) can be attached to a function calls. However, the FT standard enables to attach fungible tokens in a call by using the FT-contract as intermediary. This means that, instead of you attaching tokens directly to the call, you ask the FT-contract to do both a transfer and a function call in your name.
Let's assume that you need to deposit FTs on Ref Finance.
How it works:
1. You call ft_transfer_call in the FT contract passing: the receiver, a message, and the amount.
2. The FT contract transfers the amount to the receiver.
3. The FT contract calls receiver.ft_on_transfer(sender, msg, amount)
4. The FT contract handles errors in the ft_resolve_transfer callback.
5. The FT contract returns you how much of the attached amount was actually used.
---
## Handling Deposits (Contract Only)
If you want your contract to handle deposit in FTs you have to implement the `ft_on_transfer` method. When executed, such method will know:
- Which FT was transferred, since it is the predecessor account.
- Who is sending the FT, since it is a parameter
- How many FT were transferred, since it is a parameter
- If there are any parameters encoded as a message
The `ft_on_transfer` must return how many FT tokens have to **be refunded**, so the FT contract gives them back to the sender.
```rust
// Implement the contract structure
#[near(contract_state)]
impl Contract {}
#[near]
impl FungibleTokenReceiver for Contract {
// Callback on receiving tokens by this contract.
// `msg` format is either "" for deposit or `TokenReceiverMessage`.
fn ft_on_transfer(
&mut self,
sender_id: AccountId,
amount: U128,
msg: String,
) -> PromiseOrValue {
let token_in = env::predecessor_account_id();
assert!(token_in == self.ft_contract, "{}", "The token is not supported");
assert!(amount >= self.price, "{}", "The attached amount is not enough");
env::log_str(format!("Sender id: {:?}", sender_id).as_str());
if msg.is_empty() {
// Your internal logic here
PromiseOrValue::Value(U128(0))
} else {
let message =
serde_json::from_str::(&msg).expect("WRONG_MSG_FORMAT");
match message {
TokenReceiverMessage::Action {
buyer_id,
} => {
let buyer_id = buyer_id.map(|x| x.to_string());
env::log_str(format!("Target buyer id: {:?}", buyer_id).as_str());
// Your internal business logic
PromiseOrValue::Value(U128(0))
}
}
}
}
}
```
---
## Additional Resources
1. [NEP-141 and NEP-148 standards](https://nomicon.io/Standards/Tokens/FungibleToken/)
2. [FT Event Standards](https://nomicon.io/Standards/Tokens/FungibleToken/Event)
3. [FT reference implementation](https://github.com/near-examples/FT)
4. [Fungible Tokens 101](../../3.tutorials/fts/0-intro.md) - a set of tutorials that cover how to create a FT contract using Rust.