Handle NEP141 Transfer Calls and Track the Target Contract's Balance
Learn to use ft_transfer_call function calls. This method needs a bit of Rust logic to make it work with the target contract.
Register the target address, transfer the minimum NEAR balance and make your dApp accept fungible token transfers to create engaging games with real money 🤑
Getting Started
Follow the Project Setup instructions to start the project in your local machine and try the recipes yourself. You can also clone or navigate the repo to get just what you need.
For a NEAR wallet to receive NEP141 payments, for example USDT usdt.tether-token.near
transfers, a simple ft_transfer
call will suffice. If the source wallet has the necessary balance, the money will be transferred. But what if you want to notify another contract about this balance transfer and act upon it?
This is what we do in Prompt Wars. When a user submits a prompt, they are actually transferring their fungible token balance to the game contract, the game contract is "notified" and registers the player's prompt to list them in the game.
IMPORTANT
New contracts that should receive NEP141 fungible token transfers need to be registered.
The ft_receiver contract
Part of the Prompt Wars suite of methods, is the ft_on_transfer
method. This method will be called after a successful ft_transfer_call
call on the receiving NEP141 funginble token contract.
Read through NEAR's Fungible Token docs to learn more about this pattern.
The important part here is the msg
String parameter.
Note that the NEP141 callback will strictly call ft_on_transfer
on the receiver contract. This method should be publicly available on your contract.
The ft_on_transfer
msg
Payload
ft_on_transfer
msg
PayloadThe pattern above expects a String
as the msg
parameter, this String
is formatted by JSON.stringify
and sent via the cross-contract call to be unwrapped by this line:
Rust does the work of checking the Payload
structure and then passes it to the match
block:
Where self.create_outcome_token(sender_id, amount, payload)
is part of the game's private contract methods.
Note that "private" here is actually NEAR's private, but not Rust private. Meaning that the method can be called across Rust files, but not called from the NEAR CLI or NEAR API.
Calling ft_transfer_call
from the client-side
ft_transfer_call
from the client-sideThis whole pattern is used from the client-side when a user's wallet is connected. Notice how we format the msg
parameter expected by ft_transfer_call
:
Unwrapping ft_on_transfer result
If the NEP141 transfer succeeds, then there should be a new balance registered for the target contract, in this case our game.
To check for a successful transfer, remember that create_outcome_token
returns an amount. This amount should be greater than 0 and should match the amount we are charging to play the game:
This amount
is unwrapped on ftTransferCall
.
Note that the response of wallet.signAndSendTransaction needs to be parsed because it is formatted as hex. Check this unwrapping function helper here.
Displaying the game contract's balance
This client-side step is the easiest. Just call ft_balance_of
to check the balance of a target accountId
on any NEP141 fungible token:
Formatting NEP141 Fungible Token balances
Each fungible token has its own decimals
value definition. For USDT for example, it is decimals: 6
.
Remember that smart-contracts use fixed-point decimals (no .
symbol to distinguish cents as in 1.0
). For example:
With decimals being 6, an amount of USDT 1.0 would be represented as:
But this would be confusing for your users, since they are used to the dot notation.
Fixed-point decimal amount format helpers
Luckily for you, Prompt Wars needed to display formatted amounts and we developed some helpers that may suit your dApp as well:
Last updated