NEAR zero to hero: Minting Fungible Tokens
This is the third tutorial of NEAR Nigeria zero to hero series. The goal of this series is to transform a programmer with no experience in developing decentralized applications to a skilled NEAR developer. Learn more about this series here.
In this tutorial, you’ll learn how to easily create your own Fungible Token (FT) using the NEAR SDK and external Rust crates. You’ll learn how to mint FT and view them in your Wallet.
Introduction
FT has been the leading force in blockchain adoption since the inception of Bitcoin. Completing this tutorial will give you an understanding of how FT are implemented on NEAR Protocol. You will also have a feel of how transactions are processed on NEAR Protocol.
The de facto fungible token standard on NEAR is NEP141. NEP141 allows asynchronous action of the fungible smart contract.
Prerequisites
To complete this tutorial successfully, you will need:
- Rust toolchain
- A NEAR account
- NEAR command-line interface (near-cli)
- Working knowledge of Rust
#note: check the previous tutorial to set-up the first three requirements.
Getting started
To get started, you will create a smart contract only project.
Go to your terminal and run:
cargo new ft-z2H — lib && cd ft-z2H
Ensure a cargo.toml and src/lib.rs were created for you, and open your project in the code editor of your choice.
Editing Cargo.toml
The next step is to configure your cargo.toml file.
Open Cargo.toml in the code editor of your choice. Cargo.toml is in the Tom’s Obvious, Minimal Language(TOML) format and is similar to a package.json file of node.js
Modify your cargo.toml like so:
Using external libraries
Let us begin by “importing” external crates that will be used to build your FT contract.
Open src/lib.rs in your code editor, and add delete the default code.
Add the following lines of code to use near_contract_standards and near_sdk in your contract.
Initializing contract struct
Recall that when writing smart contracts, the pattern is to have a struct with an associated impl where you write the core logic into functions.
Copy the code below to your src/lib.rs
This creates a Contract struct that contains member variable token of type FungibleToken. It also contains member variable metadata of type LazyOption<FungibleTokenMetadata>.
FungibleToken has a number of properties that make your token fungible. It allows for its use in near_contract_standard, which does the heavy lifting of accounting, safe transfer, and interaction with external contracts at different levels of abstraction.
FungibleTokenMetadata is the standard data structure by which FT store and access token specific data. It contains the name, decimal, symbol, and image of the FT.
LazyOption<FungibleTokenMetadata> enables on-demand evaluation and storage of metadata to blockchain storage.
Adding contract logic
Now, you will add functions to create a new FT, set its name, symbol, total supply, and image.
Copy the code below to src/lib.rs
This creates a corresponding Contract impl that contains these functions: new_default_meta(), new(), on_account_closed(), and on_token_burned().
new() Initializes the contract with the given total supply which is owned by the given `owner_id` along with the given metadata.
new_default_meta() set the initial metadata of your fungible token with the default metadata and can be called once.
#note: notice how new() was called from new_default_meta() with the supplied metadata.
on_account_closed(), and on_token_burned() are trigger functions that are used to initialize boilerplate macros
Adding boilerplate
Add the code below to src/lib.rs.
near_contract_standards::impl_fungible_token_core! implements the core functionalities of a fungible token. These functionalities include accounting, safe transfer, and interaction with external contracts at different levels of abstraction. All of the functions implemented by the impl_fungible_token_core! can be called directly from your smart contract.
impl_fungible_token_storage! ensures that the cost of storage on the blockchain is covered by the caller of the who initiates the storage.
Adding test
Add the test suite below to src/lib.rs
The block of code above does the following:
- It create a mock blockchain virtual machine and get transaction signers with get_context
- Test that your fungible token was initialized with test_new
- Test that transfer from impl_fungible_token_core! was called successfully with test_transfer
Test & compile
Test the code
To test that everything works as expected in our contract, open your terminal and run the command below in your project directory:
cargo test — nocapture
You will have an output like so:
Compile the code
Assuming that all the tests passed ok, you can go ahead and compile the smart contract by running the command below:
cargo build — target wasm32-unknown-unknown — release
You will have an output like so:
Deploying the smart contract 🚀
With the compiled .wasm file ready, you can go ahead and deploy the smart contract. To deploy it, you will use near-cli and your testnet NEAR account.
Login with near-cli
Go to your project directory in a terminal and run:
near login
A link will be shown after you execute this command. Open the link into your web browser.
Follow the instructions in NEAR Wallet to authenticate your account, then head back to your terminal to complete the final step confirming the account name.
#note: you may be automatically directed to the NEAR web wallet and have your account name confirmed after you successfully connect your wallet.
To make this tutorial easier to copy/paste, you are going to set an environment variable for your account ID like so:
export ID=YOUR_ACCOUNT_NAME
#note: replace YOUR_ACCOUNT_NAME with the account name you just logged in with including the .testnet)
Now that your login keys have been saved to the home directory, you can use near-cli to deploy the compiled contract to NEAR.
Deploying the contract
Finally, use near-cli to deploy the smart contract to NEAR test network:
near deploy — near deploy — wasmFile target/wasm32-unknown-unknown/release/ft_z2H.wasm — accountId $ID
#note: you may have an error stating you have insufficient gas for deployment. A simple hack is to send more testnet NEAR token to $ID
Minting your FT
Now that you have successfully deployed your FT to the testnet, the next step is to initialize the contract before some else does.
To initialize your contract run the command below in your terminal:
near call $ID new ‘{“owner_id”: “‘$ID’”, “total_supply”: “1000000000000000”, “metadata”: { “spec”: “ft-1.0.0”, “name”: “Zero To Hero”, “symbol”: “z2H”, “decimals”: 18 }}’ — accountId $ID
Next, check the your balance by running the command below in your terminal:
near view $ID ft_balance_of '{"account_id": "'$ID'"}'
You will have an output like so:
Congratulations! Your fungible token is alive on the blockchain!!!
Next steps
This tutorial introduced you to NEAR fungible token standard NEP141 and introduced how you can use external crates in your smart contract
You are encouraged to modify the source code as much as possible and modify or automate as much as possible. You can go one step further to implement a frontend interface for your smart contract.
Now that you have been introduced to building fungible tokens, a natural next step is to learn how to build more complex smart contracts. In the next series you will learn how to build an interactive smart contract as well as more essential pieces of NEAR that makes it a simple, and fast blockchain protocol.
Versioning for this article
At the time of this writing, this example works with the following versions:
- cargo 1.62.0 (a748cf5a3 2022–06–08)
- rustc 1.62.0 (a8314ef7d 2022–06–27)
- near-cli: 3.4.0