Fungible Tokens (FT)
Besides the native NEAR token, NEAR accounts have access to a multitude of 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. 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. The FT Tool is a token factory, you can interact with it through graphical interface, or by making calls to its contract.
- ⚛️ Component
- 🌐 WebApp
- 🖥️ CLI
const args = {
args: {
owner_id: "bob.near",
total_supply: "1000000000",
metadata: {
spec: "ft-1.0.0",
name: "Test Token",
symbol: "test",
icon: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
decimals: 18,
},
},
account_id: "bob.near",
};
Near.call("tkn.primitives.near", "create_token", args, 300000000000000, "2234830000000000000000000");
import { Wallet } from './near-wallet';
const wallet = new Wallet({});
const args = {
args: {
owner_id: "bob.near",
total_supply: "1000000000",
metadata: {
spec: "ft-1.0.0",
name: "Test Token",
symbol: "test",
icon: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
decimals: 18,
},
},
account_id: "bob.near",
};
await wallet.callMethod({
method: 'create_token',
args,
contractId: "tkn.primitives.near",
gas: 300000000000000,
deposit: "2234830000000000000000000"
});
The Wallet
object comes from our quickstart template
near call tkn.primitives.near create_token '{"args":{"owner_id": "bob.near","total_supply": "1000000000","metadata":{"spec": "ft-1.0.0","name": "Test Token","symbol": "TTTEST","icon": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7","decimals": 18}},"account_id": "bob.near"}' --gas 300000000000000 --depositYocto 2234830000000000000000000 --accountId bob.near
The FT you create will live in the account <your_token_symbol>.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.
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.
cargo near deploy <account-id> with-init-call new json-args '{"owner_id": "<owner-account>", "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
Check the Contract Wizard to create a personalized FT contract!.
Querying Metadata
You can query the FT's metadata by calling the ft_metadata
.
- ⚛️ Component
- 🌐 WebApp
- 🖥️ CLI
const tokenContract = "token.v2.ref-finance.near";
const tokenMetadata = Near.view(tokenContract, "ft_metadata", {});
Example response
{
"spec": "ft-1.0.0",
"name": "Ref Finance Token",
"symbol": "REF",
"icon": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='16 24 248 248' style='background: %23000'%3E%3Cpath d='M164,164v52h52Zm-45-45,20.4,20.4,20.6-20.6V81H119Zm0,18.39V216h41V137.19l-20.6,20.6ZM166.5,81H164v33.81l26.16-26.17A40.29,40.29,0,0,0,166.5,81ZM72,153.19V216h43V133.4l-11.6-11.61Zm0-18.38,31.4-31.4L115,115V81H72ZM207,121.5h0a40.29,40.29,0,0,0-7.64-23.66L164,133.19V162h2.5A40.5,40.5,0,0,0,207,121.5Z' fill='%23fff'/%3E%3Cpath d='M189 72l27 27V72h-27z' fill='%2300c08b'/%3E%3C/svg%3E%0A",
"reference": null,
"reference_hash": null,
"decimals": 18
}
import { Wallet } from './near-wallet';
const TOKEN_CONTRACT_ADDRESS = "token.v2.ref-finance.near";
const wallet = new Wallet({ createAccessKeyFor: TOKEN_CONTRACT_ADDRESS });
await wallet.viewMethod({
method: 'ft_metadata',
args: {},
contractId: TOKEN_CONTRACT_ADDRESS
});
Example response
{
"spec": "ft-1.0.0",
"name": "Ref Finance Token",
"symbol": "REF",
"icon": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='16 24 248 248' style='background: %23000'%3E%3Cpath d='M164,164v52h52Zm-45-45,20.4,20.4,20.6-20.6V81H119Zm0,18.39V216h41V137.19l-20.6,20.6ZM166.5,81H164v33.81l26.16-26.17A40.29,40.29,0,0,0,166.5,81ZM72,153.19V216h43V133.4l-11.6-11.61Zm0-18.38,31.4-31.4L115,115V81H72ZM207,121.5h0a40.29,40.29,0,0,0-7.64-23.66L164,133.19V162h2.5A40.5,40.5,0,0,0,207,121.5Z' fill='%23fff'/%3E%3Cpath d='M189 72l27 27V72h-27z' fill='%2300c08b'/%3E%3C/svg%3E%0A",
"reference": null,
"reference_hash": null,
"decimals": 18
}
The Wallet
object comes from our quickstart template
near view token.v2.ref-finance.near ft_metadata
Example response
{
spec: "ft-1.0.0",
name: "Ref Finance Token",
symbol: "REF",
icon: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='16 24 248 248' style='background: %23000'%3E%3Cpath d='M164,164v52h52Zm-45-45,20.4,20.4,20.6-20.6V81H119Zm0,18.39V216h41V137.19l-20.6,20.6ZM166.5,81H164v33.81l26.16-26.17A40.29,40.29,0,0,0,166.5,81ZM72,153.19V216h43V133.4l-11.6-11.61Zm0-18.38,31.4-31.4L115,115V81H72ZM207,121.5h0a40.29,40.29,0,0,0-7.64-23.66L164,133.19V162h2.5A40.5,40.5,0,0,0,207,121.5Z' fill='%23fff'/%3E%3Cpath d='M189 72l27 27V72h-27z' fill='%2300c08b'/%3E%3C/svg%3E%0A",
reference: null,
reference_hash: null,
decimals: 18
}
Checking Balance
To know how many coins a user has you will need to query the method ft_balance_of
.
- ⚛️ Component
- 🌐 WebApp
- 🖥️ CLI
Remember about fungible token precision. You may need this value to show a response of balance requests in an understandable-to-user way in your app. How to get precision value (decimals) you may find above.
const tokenContract = "token.v2.ref-finance.near";
const userTokenBalance = Near.view(tokenContract, "ft_balance_of", {
account_id: "bob.near",
});
Example response
"3479615037675962643842"
Remember about fungible token precision. You may need this value to show a response of balance requests in an understandable-to-user way in your app. How to get precision value (decimals) you may find above.
import { Wallet } from './near-wallet';
const TOKEN_CONTRACT_ADDRESS = "token.v2.ref-finance.near";
const wallet = new Wallet({ createAccessKeyFor: TOKEN_CONTRACT_ADDRESS });
await wallet.viewMethod({
method: 'ft_balance_of',
args: {
account_id: 'bob.near'
},
contractId: TOKEN_CONTRACT_ADDRESS
});
Example response
"3479615037675962643842"