Fungible tokens
Introduction
Please see the spec for the fungible token standard and an example implementation for reference details.
One notable aspect of the standard is that method names are prefixed with ft_. This will be a helpful convention when querying for transactions related to fungible tokens.
Get balance
Using the abstraction of the NEAR CLI tool, we can check the balance of a user's account with near view:
near view ft.demo.testnet ft_balance_of '{"account_id": "mike.testnet"}'
Returns:
View call: ft.demo.testnet.ft_balance_of({"account_id": "mike.testnet"})
'1000000'
Alternatively, you can call a contract function using the query RPC endpoint. Below is an example using HTTPie:
http post https://rpc.testnet.near.org jsonrpc=2.0 id=ftbalance method=query \
params:='{
"request_type": "call_function",
"finality": "final",
"account_id": "ft.demo.testnet",
"method_name": "ft_balance_of",
"args_base64": "eyJhY2NvdW50X2lkIjogIm1pa2UudGVzdG5ldCJ9"
}'
Returns:
HTTP/1.1 200 OK
Alt-Svc: clear
Via: 1.1 google
access-control-allow-origin:
content-length: 176
content-type: application/json
date: Thu, 27 May 2021 12:53:38 GMT
{
"id": "dontcare",
"jsonrpc": "2.0",
"result": {
"block_hash": "3mvNHpZAsXiJ6SuHU1mbLVB4iXCfh5i5d41pnkaSoaJ5",
"block_height": 49282350,
"logs": [],
"result": [ 34, 49, 48, 48, 48, 48, 48, 48, 34 ]
}
}
As mentioned earlier, the result is an array of bytes. There are various ways to convert bytes into a more human-readable form such as the dtool CLI.
dtool a2h '[34,49,48,48,48,48,48,48,34]' | dtool h2s
Returns:
"1000000"
Note: The fungible token balance of the account mike.testnet is 1000000 wrapped in double-quotes. This is because of an issue with JSON serialization. Amounts given in arguments and results must be serialized as Base-10 strings, e.g. "100". This is done to avoid JSON limitation of max integer value of 2**53, which can certainly happen with fungible tokens.
Get info about the FT
You can get name, decimals, icon and other parameters by calling the next function:
- using NEAR CLI:
near view <contract_account_id> ft_metadata
Result:
View call: ft.demo.testnet.ft_metadata()
{
spec: 'ft-1.0.0',
name: 'Example Token Name',
symbol: 'MOCHI',
icon: null,
reference: null,
reference_hash: null,
decimals: 24
}
- with JSON RPC call:
http post https://rpc.testnet.near.org jsonrpc=2.0 id=ftmetadata method=query \
params:='{
"request_type": "call_function",
"finality": "final",
"account_id": "<contract_account_id>",
"method_name": "ft_metadata",
"args_base64": ""
}'
Example response:
HTTP/1.1 200 OK
Alt-Svc: clear
Via: 1.1 google
access-control-allow-origin:
content-length: 604
content-type: application/json
date: Wed, 02 Jun 2021 15:51:17 GMT
{
"id": "ftmetadata",
"jsonrpc": "2.0",
"result": {
"block_hash": "B3fu3v4dmn19B6oqjHUXN3k5NhdP9EW5kkjyuFUDpa1r",
"block_height": 50061565,
"logs": [],
"result": [ 123, 34, 115, 112, 101, 99, 34, 58, 34, 102, 116, 45, 49, 46, 48, 46, 48, 34, 44, 34, 110, 97, 109, 101, 34, 58, 34, 69, 120, 97, 109, 112, 108, 101, 32, 84, 111, 107, 101, 110, 32, 78, 97, 109, 101, 34, 44, 34, 115, 121, 109, 98, 111, 108, 34, 58, 34, 77, 79, 67, 72, 73, 34, 44, 34, 105, 99, 111, 110, 34, 58, 110, 117, 108, 108, 44, 34, 114, 101, 102, 101, 114, 101, 110, 99, 101, 34, 58, 110, 117, 108, 108, 44, 34, 114, 101, 102, 101, 114, 101, 110, 99, 101, 95, 104, 97, 115, 104, 34, 58, 110, 117, 108, 108, 44, 34, 100, 101, 99, 105, 109, 97, 108, 115, 34, 58, 50, 52, 125 ]
}
}
Decoded result in this case is:
{
"spec": "ft-1.0.0",
"name": "Example Token Name",
"symbol": "MOCHI",
"icon": null,
"reference": null,
"reference_hash": null,
"decimals": 24
}
Simple transfer
To follow this guide, please check the step by step instructions on how to create a transaction first.
In order to send a fungible token to an account, the receiver must have a storage deposit. This is because each smart contract on NEAR must account for storage used, and each account on a fungible token contract is a key-value pair, taking up a small amount of storage. For more information, please see how storage works in NEAR. To check if account has deposited the storage for this FT do the following:
Get storage balance of the account. storage_balance_of function returns the amount of deposited storage or null if there is no deposit.
- using NEAR CLI:
near view <contract_account_id> storage_balance_of '{"account_id": "<user_account_id>"}'
Result:
View call: ft.demo.testnet.storage_balance_of({"account_id": "serhii.testnet"})
null
- with JSON RPC call:
http post https://rpc.testnet.near.org jsonrpc=2.0 id=storagebalanceof method=query \
params:='{
"request_type": "call_function",
"finality": "final",
"account_id": "ft.demo.testnet",
"method_name": "storage_balance_of",
"args_base64": "eyJhY2NvdW50X2lkIjogInNlcmhpaS50ZXN0bmV0In0K"
}'
Example response:
HTTP/1.1 200 OK
Alt-Svc: clear
Via: 1.1 google
access-control-allow-origin:
content-length: 173
content-type: application/json
date: Wed, 02 Jun 2021 14:22:01 GMT
{
"id": "storagebalanceof",
"jsonrpc": "2.0",
"result": {
"block_hash": "EkM2j4yxRVoQ1TCqF2KUb7J4w5G1VsWtMLiycq6k3f53",
"block_height": 50054247,
"logs": [],
"result": [ 110, 117, 108, 108 ]
}
}
Decoded result in this case is null.
Get the minimum storage required for FT. (The storage used for an account's key-value pair.)
- using NEAR CLI:
near view <contract_account_id> storage_balance_bounds`
Result:
View call: ft.demo.testnet.storage_balance_bounds()
{ min: '1250000000000000000000', max: '1250000000000000000000' }