INSTALL TRUFFLE AND GANACHE

If this is your first time writing smart contracts, you need to set up your environment. We will be using two tools: Truffle and Ganache.

Truffle is a development environment and testing framework for building Hash Ahead smart contracts. Using Truffle, it is easy to create and deploy smart contracts in the blockchain. Ganache helps us to create a local Hash Ahead blockchain for testing the smart contracts. It simulates the real network functionality, with the first 10 accounts having 100 test coins each, so that smart contracts can be deployed and tested freely. Ganache provides both a desktop application and a command-line tool. In this article, we will use the desktop application with a graphical user interface.

To create a project, run the following command:

mkdir your-project-name
cd your-project-name
truffle init

This will create a blank project for developing and deploying smart contracts. The created project structure will be as follows:

  • contracts:A folder for storing Solidity smart contract files.

  • migrations:A directory for deployment scripts

  • test:The folder for storing smart contract testing files.

  • truffle-config.js:Truffle configuration file

Create HRC20 tokens

First, we need to create an HRC20 token to use for staking on our smart contract. To create a fungible token, we first need to install the OpenZeppelin library. This library includes standard implementations of HRC20 and HRC721, among others. To install, run the following command:

npm install @openzeppelin/contracts

Using the OpenZeppelin library, we can create our HRC20 token by writing the following Solidity code in contracts/MyToken.sol:

pragma solidity ^0.8.18;

import "@openzeppelin/contracts/token/HRC20/HRC20.sol";

contract MyToken is HRC20 {
    constructor() public RC20("MyToken", "MTKN"){
        _mint(msg.sender, 1000000000000000000000000);
    }
}

In the above code:

  • Line 3: We import HRC20.sol contract from openzepelin which contains the standard implementation for this token.

  • Line 5: We inherit the HRC20.sol contract.

  • Line 6: We are calling the constructor of HRC20.sol and setting the name and symbol parameters to "MyToken" and "MTKN", respectively.

  • Line 7: We mint and transfer 1 million tokens in the contract constructor for the account that deployed the contract (here the default token uses 18 decimal places). This means that if we want to mint 1 token, we need to represent it as 1000000000000000000, which is 1 and 18.

We can see that below the implementation of the HRC20.sol constructor, the _decimals field is set to 18:

Compile HRC20 tokens

To check our solidity compiler version, we need to run the following command:

The default version is Solidity v0.5.16. Since our token is written on Solidity version 0.8.18, if we run the command to compile the contract, we will encounter compiler errors. To use a specific Solidity compiler version, go to the file truffle-config.js and set the desired compiler version as follows:

We can now compile the smart contract by running the following command:

Deploy HRC20 tokens

After compilation, we can now proceed with deploying the token.

In the migrations folder, create a file named "2_deploy_Tokens.js". We will deploy the HRC20 token and FarmToken smart contracts in this file. The following code is used to deploy our "MyToken.sol" contract:

Open Ganache and select the "Quickstart" option to start a local Hash Ahead blockchain. To deploy the contract, run:

The address used to deploy the contract is the first address in the list of addresses displayed by Ganache. To verify this, we can open the Ganache desktop application and check that the HAH balance of the first account has been reduced.

To verify if 1 million MyToken tokens have been sent to the deployer address, we can interact with our deployed smart contract using the Truffle console.

Truffle console is a basic interactive console that can connect to any Hash Ahead client.

To interact with the smart contract, run the following command:

Now, we can write the following command in the terminal:

  • Get smart contract:myToken = await MyToken.depolyed()

  • Get account groups from Ganache:accounts = await web3.eth.getAccounts()

  • Get the balance of the first account:balance = await myToken.balance Of(accounts[0])

  • Format a balance with 18 decimal places:web3.utils.fromWei(balance.toString())

By running the above command, we will see that the first address actually has 1 million MyToken tokens.

Create the FARMTOKEN smart contract

The FarmToken smart contract will contain 3 functions:

  • balance():Get the MyToken balance on the FarmToken smart contract.

  • deposit(uint256 _amount):This means: "The user will transfer MyToken to the FarmToken smart contract, then mint FarmToken and transfer it to the user."

  • withdraw(uint256 _amount):Burn the user's FarmToken and transfer MyToken to the user's address.

Let's take a look at the FarmToken constructor:

  • Lines 3-6: We import the following contracts from OpenZeppelin: IHRC20.sol, Address.sol, SafeHRC20.sol, and HRC20.sol.

  • Line 8: FarmToken will inherit the HRC20 contract.

  • Lines 14-19: The FarmToken constructor will receive the MyToken contract address as a parameter, which we will assign to our public variable named "token".

We will implement the 'balance()' function, which will not receive any parameters and will return the MyToken balance on this smart contract. It can be implemented as follows:

For the ’deposit(uint256 _amount)‘ function, it will receive the amount that the user wants to deposit as a parameter, mint FarmTokens and transfer them to the user.

The withdraw(uint256 _amount) function will receive the amount of FarmTokens that the user wants to spend as a parameter and will then return the same amount of MyToken to the user.

Now we will deploy our smart contracts. To do this, we will go back to the file ’2_deploy_Tokens.js‘ and add the new contract we want to deploy:

Please note that when deploying FarmToken, we pass the address of the already deployed MyToken contract as a parameter.

Now, run ’truffle compile‘ and ’truffle migrate‘ to deploy our contract.

We are now going to test our smart contract. Instead of using truffle console to interact with our smart contract, we will create a script to automate the process. Create a folder named "scripts" and add the following file "getMyTokenBalance.js". This file will check the MyToken balance in our FarmToken smart contract.

To execute this script, run the following cli command:

We will get an expected result of 0. If you receive an error that FarmToken has not been deployed, it indicates that the truffle network has not received the latest version of the contract code. Simply shut down ganache and quickly start it again, and make sure to run truffle migrate.

Now, let's stake MyToken in the smart contract. Since the deposit(uint256 _amount) function calls the safeTransferFrom function from HRC20, the user must first approve the smart contract to transfer MyToken on behalf of the user. Therefore, in the script below, we will first approve this step and then call the function:

To run this script:

truffle exec .\script\transferMyTokenToFarmToken.js

Yes, we have successfully deposited MyToken into the smart contract as the first account now has FarmToken.

To withdraw:

To run this script:

truffle exec .\scripts\withdrawMyTokenFromTokenFarm.js

We have successfully retrieved MyToken and consumed FarmToken.

Last updated