ft_balance_of), transfer tokens (ft_transfer), and transfer tokens to another contract while calling its ft_on_transfer method (ft_transfer_call).
Please see the spec for the fungible token standard and an example implementation for reference details.
Token metadata
Theft_metadata method returns the token’s name, symbol, decimals, and optional display information such as its icon.
- NEAR CLI
- RPC
Decimals
decimals determines how to display the integer amounts in which the token is denominated.
For a token with decimals: 6, "1000000" raw units represents 1 token, and "1500000" represents 1.5 tokens. meta-pool.near uses 24 decimals, so "1000000000000000000000000" raw units represents 1 STNEAR.
Use the token’s metadata when converting amounts, but keep raw balances and transfer arguments as integer strings.
Get balance
Callft_balance_of with the account ID to get its raw token balance.
- NEAR CLI
- RPC
2^53 - 1). Decode the JSON string and use integer arithmetic for balances and transfers.
Simple transfer
Before callingft_transfer, register the receiver with the token contract so the contract can store its balance.
Storage registration
Checkstorage_balance_of for the receiver. A null result means it is unregistered; query storage_balance_bounds and attach its min amount in yoctoNEAR when calling storage_deposit. The queries below show that root.near is already registered with meta-pool.near, whose minimum is 0.00125 NEAR.
- NEAR CLI
- RPC
Transfer tokens
Callft_transfer with the receiver’s account ID and an integer-string amount in the token’s smallest unit. Attach exactly 1 yoctoNEAR. With STNEAR’s 24 decimals, the amount below transfers 1 STNEAR to root.near.
- NEAR CLI
- RPC
final_execution_status === "FINAL" and a successful token-call receipt before confirming the transfer. An insufficient token balance or an unregistered receiver causes execution failure; inspect the error before retrying.
Deposit accounting
For general deposit accounting, use an indexer to inspect NEP-300 events in successful finalized token-contract outcomes:EVENT_JSON: with standard: "nep141", version: "1.0.0", and event: "ft_transfer".
Authenticate executor_id against the approved token contract; another contract can print the same log.
Transfer and call
Theft_transfer_call method allows a user to transfer tokens to a contract while simultaneously triggering a function call on the receiving contract.
Let’s call ft_transfer_call function on ft contract (receiver) and examine successful and unsuccessful scenarios.
Successful transfer and call
Let’s send 10 raw FT units to aDEFI contract that uses only 9. These are smallest-unit amounts, not NEAR or necessarily ten displayed tokens; apply the token’s approved decimals for display.
- NEAR CLI
- RPC
- Check that
result»transaction_outcome»outcome»statushasSuccessReceiptIdas a key. If not, this transaction-processing step did not produce the expected receipt; inspect the actual failure and all available outcomes. - Take the value of the
SuccessReceiptIdkey. In the case above it’sHw6z8kJ7CSaC6SgyQzcmXzNX9gq1gaAnLS169qgyZ2Vk. - Now, under
result»receiptsloop through the array until you find a receipt where thereceipt_idmatches the value from step 2. (Note that in the receipt, underActionsthere’s an element mentioning calling themethod_name: "ft_transfer_call".) On the same level of JSON, there’s anargskey. That’s a base64-encoded value of the arguments passed to the method. When decoded it is:
- Loop through
result»receipts_outcomeuntil finding the object whereidis equal to the value from step 2. Similar to step 1, this object will also contain astatusfield that should contain the keySuccessReceiptId. For this example, followSuccessReceiptIdto the resolver. In general, inspect success/failure and receipt dependencies rather than treating the absence of this particular key as proof that no tokens moved. In the above example, this value is4Tc8MsrJZSMpNZx7u4jSqxr3WhRzqxaNHxLJFqz8tUPR. - Similar to the previous step, loop through the
result»receipts_outcomeuntil you find the object where theidmatches the value from step 4. In that object check thatoutcome»statushas theSuccessValuefield. This resolver’sSuccessValuereports how many fungible-token units were used, not the unused amount returned byft_on_transfer. Note that in the example above the value isIjki, which is the base64-encoded version of"9". In this example, 10 raw token units were sent (from step 3), 9 were used, and 1 was refunded.
result » receipts_outcome. There’s an array of receipt_ids that’s particularly interesting. In this example, receipt EB69xtJiLRh9RNzAHgBGmom8551hrK2xSRreqbjvJgu5 executes ft_on_transfer. Identify that role from the receipt’s executor and method, not its position in the array. If we loop through the result » receipts_outcome and find this as the value for the id key, we’ll see what happened in the function ft_on_transfer which takes place in the contract receiving the fungible tokens. In this object the status » SuccessValue is IjEi which is the base64-encoded value of "1".
In summary:
- A user called the fungible token contract with the method
ft_transfer_callspecifying the receiver account, how many tokens to send, and custom info. - The receiver account implemented
ft_on_transfer, returning"1"to the callback function on the fungible token contract. - The fungible token contract’s callback is
ft_resolve_transferand receives this value of"1". It attempts to refund the 1 unused unit, subject to the receiver’s remaining token balance, and subtracts the actual refund from the 10 initially transferred. It then returns to the user how many tokens were used in this back-and-forth series of cross-contract calls:"9".
A failed callback does not roll back the initial token receipt. The resolver can refund only the available balance; forwarded or spent tokens and account unregistration can change the result. Inspect finalized transfer/refund/burn effects and reconcile the final balance. Support this route only with a reviewed receiving-contract routing and callback policy.
Failed transfer and call
Let’s try to send more tokens than the account has:- NEAR CLI
- RPC
result»transaction_outcome»outcome»status»SuccessReceiptIdis83AdQ16bpAC7BEUyF7zoRsAgeNW7HHmjhZLvytEsrygo- Find the outcome whose
idmatches that receipt ID, then inspectoutcome.status.Failure. A missing outcome is pending; array position0is not a reliable receipt identifier.