Building DeFi Application

The advent of decentralized finance within the crypto space has created a lot of traction worldwide. Defi is growing fast would be an understatement. With its introduction, it started to gain immense popularity among tech enthusiasts somewhere around mid of 2018. By 2019, Defi associated itself with over half a billion dollars market value. In today’s market, the value of Defi has now risen over $26 billion.

As Defi apps’ demands grow, learning the particular field’s implementation skill set and knowledge also increases. This article focuses on providing a step-by-step approach to develop a Defi app using Solidity. Through this Defi application, users can deposit an ERC20 token to the smart contract and it’ll mint and transfer Farm Tokens to them. When users want to withdraw their ERC20 tokens, they can burn their Farm tokens and then ERC 20 tokens are transferred back to them.

The article moves towards the description of creating a Defi app after a brief introduction about Defi applications.

  1. What are Defi apps?
  2. How to build Defi apps?

What are Defi apps?

Defi applications built on a Blockchain network provide all financial services in a decentralized, borderless manner that allows everyone to access and avail all financial services. Defi applications allow lending and borrowing funds, trade cryptocurrencies, speculate the price movements, earn interests and provides risk insurance. Transactions made through centralized intermediaries are now performed directly between participants, mediated by smart contracts.

How to build Defi apps?

 

Building DeFi Application 2

An environment setup is required to start working on the development of the application. Two tools, Truffle and Ganache, require installation.

1. Install Truffle and Ganache

Truffle is a testing and development framework for building smart contracts for Ethereum. It provides an easy way to create and deploy smart contracts to the blockchain. The other tool, Ganache, allows creating local Ethereum blockchain to test smart contracts. Ganache simulates basic network features and funds the first ten accounts with 100 test Ether. Thus, it makes the deployment of Smart contracts free and easy. It can be used as a desktop application or command-line tool. Here, a UI desktop application is used.
Project creation involves executing the following commands:

mkdir YourProjectName
cd YourProjectName
truffle init

It will create a blank project and the structure of the project will be as shown below:

  • contracts: Folder for the Solidity Smart contracts
  • migrations: Folder for the deployment scripts
  • test: Folder for testing our Smart contracts
  • truffle-config.js: Truffle configuration file

2. Create an ERC20 token

ERC20 is a fungible token that is used to stake on the smart contract. To create this token, the OpenZeppelin library is necessary to install. This library consists of implementation standards for ERC20 and ERC721. Its installation requires to run following command:

npm install @openzeppelin/contracts

Using the library OpenZeppelin, an ERC20 token called MyToken is created with implementing the following code:

pragma solidity ^0.6.2;
import @openzeppelin/contracts/token/ERC20/ERC20.sol;
contract MyToken is ERC20 {
constructor() public ERC20(MyToken, MTKN)
{
_mint(msg.sender, 1000000000000000000000000);
}
}

In this code:

  • Line 3 imports the contract ERC20.sol from the installed library.
  • Line 6 calls ERC20.sol constructor and passes for the name and symbol parameters as “MyToken” and “MTKN,” respectively.
  • Line 7 is minting and transferring 1 million tokens for the account that is deploying the smart contract.

ERC20.sol constructor implementation where the “_decimals” field is set to 18 is shown below:

string private _name;
string private _symbol;
uint8 private _decimals;
constructor (string memory name_, string memory symbol_) public {
_name = name_;
_symbol = symbol_;
_decimals = 18;
}
3. Deploy ERC20 token

Create a file named 2_deploy_Tokens.js on the migrations folder. It will deploy both the ERC20 token and the FarmToken smart contract. To deploy MyToken.sol contract:

 const MyToken = artifacts.require(MyToken) 
module.exports = async function(deployer, network, accounts) {
await deployer.deploy(MyToken)
const myToken = await MyToken.deployed()
}

Before the compilation of the Smart contract, first, check the Solidity compiler version.

 truffle version

Solidity’s default version is v0.5.16. The token here is written in version 0.6.2. If commands are executed to compile the contract, it will generate a compiler error. Therefore, it is necessary to check the version. To specify the Solidity compiler version, go to truffleconfig.js file and set the desired compiler version as shown below:

compilers: {
solc: {
version: 0.6.2,
}
}

Compile the smart contract with the following command:

truffle compile

Now, after compilation, move forward to deploy the token. Open Ganache and go to the “Quickstart” option. It will start local Ethereum Blockchain. To deploy the contract, execute the following:

truffle migrate

Truffle console verifies that 1 million MyToken tokens have been sent to the deployer address. To interact with the smart contract, run:

truffle console

Now, write the following command:

  • For smart contract:

     myToken = await MyToken.deployed()
  • From Ganache, get the array of accounts:

     accounts = await web3.eth. getAccounts()
  • To check the balance:

     balance = await myToken.balanceOf(accounts [0])
  • To format the balance from 18 decimals:

     web3.utils.fromWei(balance.toString())

4. Create Farm Token Smart Contract

A FarmToken smart contract performs three main functions:

  • deposit(uint256 _amount): On behalf of the user, transfer MyToken to FarmToken smart contract. Then, mint and transfer the FarmToken to the user.
  • withdraw(uint256 _amount): Burns user’s FarmToken and transfer MyToken to its address.
  • balance(): Get MyToken balance on FarmToken smart contract. For FarmToken constructor:
    pragma solidity ^0.6.2;
    import @openzeppelin/contracts/token/ERC20/IERC20.sol;
    import @openzeppelin/contracts/utils/Address.sol;
    import @openzeppelin/contracts/token/ERC20/SafeERC20.sol;
    import @openzeppelin/contracts/token/ERC20/ERC20.sol
    contract FarmToken is ERC20 {
    using Address for address;
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    IERC20 public token;
    constructor(address _token)
    public
    ERC20(FarmToken, FRM)
    {
    token = IERC20(_token);
    }
    
  • Lines 3-6 import the following contract from OpenZeppelin
    IERC20.sol, Address.sol, SafeERC20.sol and ERC20.sol.
  • Line 8 represents the inheritance of FarmToken from the ERC20 contract.
  • Line 14-19 enables the FarmToken constructor to receive the MyToken contract’s address as a parameter and assign it to a public variable called the token.

Implement balance() function:

function balance() public view returns (uint256) {
return token.balanceOf(address(this));
}

For deposit() function:

function deposit(uint256 _amount) public {
require(_amount > 0, amount cannot be 0);
token.safeTransferFrom(msg.sender, address(this), _amount);
_mint(msg.sender, _amount);
}

To implement withdraw() function:

function withdraw(uint256 _amount) public {
_burn(msg.sender, _amount);
token.safeTransfer(msg.sender, _amount);
}

Now, deploy smart contract:

const MyToken = artifacts.require(MyToken)
const FarmToken = artifacts.require(FarmToken)
module.exports = async function(deployer, network, accounts) {
await deployer.deploy(MyToken)
const myToken = await MyToken.deployed()
await deployer.deploy(FarmToken, myToken.address)
const farmToken = await FarmToken.deployed()
}

Remember that while deploying the FarmToken, the MyToken smart contract’s address is passed as a parameter. Run truffle migrate and truffle compiler to deploy the contracts. Rather than using the truffle console to interact with the smart contract, create a script to automate the process. Create a “scripts” folder and add the “getMyTokenBalance.js” file. It’ll check the balance of MyToken in FarmToken smart contract.

const MyToken = artifacts.require(MyToken);
const FarmToken = artifacts.require(FarmToken);
module.exports = async function(callback) {
myToken = await MyToken.deployed()
farmToken = await FarmToken.deployed()
balance = await myToken.balanceOf(farmToken.address)
console.log(web3.utils.fromWei(balance.toString()))
callback();
}

Run the following CLI command to execute this script:

truffle exec .\scripts\getMyTokenBalance.js

Here, the expected result is 0. Now, MyToken is to be staked on the smart contract. The user needs to first approve the smart contract to transfer MyToken, since the deposit(uint256 _amount) function calls safeTransfer() function. To approve the request call the function:

const MyToken = artifacts.require(MyToken);
const FarmToken = artifacts.require(FarmToken);
module.exports = async function(callback) {
const accounts = await new web3.eth.getAccounts();
const myToken = await MyToken.deployed();
const farmToken = await FarmToken.deployed();
const allowanceBefore = await myToken.allowance(accounts[0],
farmToken.address);
console.log(Amount of MyToken FarmToken is allowed to transfer
on our behalf Before: + allowanceBefore.toString());
await myToken.approve(farmToken.address, web3.utils.toWei
(100, ether));
const allowanceAfter = await myToken.allowance(accounts[0],
farmToken.address);
console.log(Amount of MyToken FarmToken is allowed to transfer
on our behalf After: + allowanceAfter.toString());
balanceMyTokenBeforeAccounts0 = await myToken.balanceOf(accounts [0]);
balanceMyTokenBeforeFarmToken = await myToken.balanceOf
(farmToken.address);
console.log(*** My Token ***)
console.log('Balance MyToken Before accounts[0] ' + web3.utils.
fromWei(balanceMyTokenBeforeAccounts0.toString()))
console.log(Balance MyToken Before TokenFarm + web3.utils.
fromWei(balanceMyTokenBeforeFarmToken.toString()))
console.log(*** Farm Token ***)
balanceFarmTokenBeforeAccounts0 = await farmToken.balanceOf<br />(accounts[0]);
balanceFarmTokenBeforeFarmToken = await farmToken.balanceOf
(farmToken.address);
console.log(Balance FarmToken Before accounts[0] + web3.
utils.fromWei(balanceFarmTokenBeforeAccounts0.toString()))
console.log(Balance FarmToken Before TokenFarm + web3.utils.
fromWei(balanceFarmTokenBeforeFarmToken.toString()))
console.log(Call Deposit Function)
await farmToken.deposit(web3.utils.toWei(100, ether));
console.log(*** My Token ***)
balanceMyTokenAfterAccounts0 = await myToken.balanceOf(accounts [0]);
balanceMyTokenAfterFarmToken = await myToken.balanceOf
(farmToken.address);
console.log('Balance MyToken After accounts[0] + web3.utils.
fromWei(balanceMyTokenAfterAccounts0.toString()))
console.log(Balance MyToken After TokenFarm + web3.utils.
fromWei(balanceMyTokenAfterFarmToken.toString()))
console.log(*** Farm Token ***)
balanceFarmTokenAfterAccounts0 = await farmToken.balanceOf
(accounts[0]);
balanceFarmTokenAfterFarmToken = await farmToken.balanceOf
(farmToken.address);
console.log(Balance FarmToken After accounts[0] + web3.utils.
fromWei(balanceFarmTokenAfterAccounts0.toString()))
console.log(Balance FarmToken After TokenFarm + web3.utils.
fromWei(balanceFarmTokenAfterFarmToken.toString()))
callback();
}

Run this script with:

truffle exec .\scripts\transferMyTokenToFarmToken.js

Now, the job to successfully create and deploy a defi app is done.

Conclusion

The article presented how to set up the project development environment with Truffle and Ganache and create a Defi application that can deposit MyTokens, receive FarmTokens and withdraw MyTokens by burning FarmTokens.

This article has been published from the source link without modifications to the text. Only the headline has been changed.