Explore the Future of Web3: Shardeum's Whitepaper Released!

Build and Deploy an ERC20 Vault on Shardeum

Build and Deploy an ERC20 Vault on Shardeum

In this guide, we are going to learn how to build and deploy a customized decentralized vault smart contract on...

Back to top
  • Share

In this guide, we are going to learn how to build and deploy a customized decentralized vault smart contract on Shardeum. A Vault is a DeFi product where users can stake their tokens. The vault then implements various lending strategies to make a profit and then distribute the profits amongst all the depositors. (Side note: Don’t mistake the topic for Crypto Vault which is a type of a wallet) 

For this tutorial, we are going to be using Remix IDE, a popular browser based Solidity IDE.

Vault Smart Contract

The basic strategy behind the vault is that when a user deposits ERC20 tokens into the Vault smart contract, we will mint shares (this represents the ownership of respective tokens this user has deposited into the vault contract) and when a user withdraws a token, we will burn the respective number of shares.

With the strategy in place, let’s start with the basic structure of the smart contract.

// SPDX-License-Identifier: MIT


pragma solidity ^0.8.17;
import "./IERC20.sol";


 contract Vault{
   IERC20 public immutable token;
   uint public totalSupply;
   mapping(address => uint) public balanceOf;


   constructor(address _token){
       token = IERC20(_token);
   }
}

In the above code, we are importing the IERC20 (Interface for ERC20 token which provides us the functions and events needed for the ERC20 token standard). 

  • Create a new file named IERC20.sol in the Remix Workspace and copy the entire contract from Openzeppelin IERC20.
  • Next, we will add two internal functions mint() and burn(). The mint() function takes input of the address where the shares will be minted to and the amount of how much will be minted.
  • Similarly the burn() function takes the input of the address whose shares needs to be burned
  function _mint(address _to,uint _amount) private{
       totalSupply += _amount;
       balanceOf[_to] += _amount;
   }
    function _burn(address from,uint _amount) private{
       totalSupply -= _amount;
       balanceOf[from] -= _amount;
   }
  • Now, let’s write the function to deposit and withdraw from the Vault. In deposit(), we are handling the case when totalSupply==0  separately because we don’t want the function to divide by zero. This function basically calculates the amount of shares that needs to be minted based upon the number of tokens being deposited.
  • In withdraw(), we are doing the similar calculation for calculating the number of shares to be burned and sending back the tokens to the user.
 function deposit(uint _amount) external {
       uint shares;
       if(totalSupply== 0){
           shares = _amount;
       }
       else{
           shares = _amount*totalSupply /token.balanceOf(address(this));
       }
       _mint(msg.sender, shares);
       token.transferFrom(msg.sender,address(this), _amount);
   }
 function withdraw(uint _shares) external {
       uint amount = (_shares*token.balanceOf(address(this)))/ totalSupply;
       _burn(msg.sender, _shares);
       token.transfer(msg.sender,amount);
   }

Create and Deploy an ERC20 Token

Now, let’s create a standard ERC20 token with the name of “VAULT” and token symbol “VLT” which we will use to deposit in our vault.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./IERC20.sol";


contract ERC20 is IERC20 {
   uint public totalSupply;
   mapping(address => uint) public balanceOf;
   mapping(address => mapping(address => uint)) public allowance;
   string public name = "VAULT";
   string public symbol = "VLT";
   uint8 public decimals = 18;


   function transfer(address recipient, uint amount) external returns (bool) {
       balanceOf[msg.sender] -= amount;
       balanceOf[recipient] += amount;
       emit Transfer(msg.sender, recipient, amount);
       return true;
   }


   function approve(address spender, uint amount) external returns (bool) {
       allowance[msg.sender][spender] = amount;
       emit Approval(msg.sender, spender, amount);
       return true;
   }


   function transferFrom(
       address sender,
       address recipient,
       uint amount
   ) external returns (bool) {
       allowance[sender][msg.sender] -= amount;
       balanceOf[sender] -= amount;
       balanceOf[recipient] += amount;
       emit Transfer(sender, recipient, amount);
       return true;
   }


   function mint(uint amount) external {
       balanceOf[msg.sender] += amount;
       totalSupply += amount;
       emit Transfer(address(0), msg.sender, amount);
   }


   function burn(uint amount) external {
       balanceOf[msg.sender] -= amount;
       totalSupply -= amount;
       emit Transfer(msg.sender, address(0), amount);
   }
}

Now, it’s Time to Deploy!

Now that we have all the smart contracts, let’s start deploying these on Shardeum testnet. 

  • Compile all three smart contracts ERC20.sol, IERC20.sol and Vault.sol from the solidity Compile section.
  • Next, go to the Deploy and Run transactions section of remix, and change the Environment from Remix VM to Injected Web3. If your metamask is properly configured, you should see ‘Custom (8082) Network’. Now you are all set!

Create and Deploy an ERC20 Token

Now, it’s time to test the practical performance of what we just built.

  • Deploy ERC20.sol and copy the token address once it’s deployed.
  • Select Vault.sol and paste the previously copied address beside the deploy button and deploy the contract.
  • Next, mint 100 VLT tokens from the ERC20 token using the mint function.
  • Paste your wallet address and the number of tokens beside the approve() function so that we are able to spend it in our Vault contract.
  • Now, Deposit 100 tokens into the Vault contract using deposit() function.
  • Now, if you call the balanceOf() function in Vault passing your wallet address, you will see 100 tokens.

For this example, you can send 100 tokens directly to the Vault contract, assuming that the Vault made some profit.

  • Now, if you call the withdraw() function and check your balance on your ERC20 token contract, you would see 200 tokens.

That’s it!. We just created a vault, then deposited 100 tokens, and eventually withdrew 200 tokens with the profit assumption.

This was a very abstracted and high level implementation of DeFi Vaults. In actual products, there are a lot more factors that will be baked with an optimal business logic to help create profit using various trading/lending strategies.


About the author : Sandipan Kundu is the Developer Relations Engineer at Shardeum. He has been an early contributor to the Web3 ecosystem since 2017 and has also contributed in growing the Polygon devrel team previously.

Building out strong developer evangelism programs with the help of hackathons, workshops, technical content etc to grow and spread the word around for web3 and decentralization has been his primary focus.

Social Links of author :

E-mail : sandipan@shardeum.org
Twitter:  https://twitter.com/SandipanKundu42

Popular Searches

DAO Guide  |  Blockchain Beyond Crypto  |  What is Chainlink  |  What are Cryptopunks  |  Advantages and Disadvantages of Decentralization  |  Peer to Peer Transaction  |  Web3 Training  |  Blockchain Proof of Work Vs Proof of Stake  |  What is Defi 2.0  |  What is Phishing and How to Prevent it  |  Main Features of Web 3.0  |  Blockchain Layers Explained  |  Cryptocurrency Liquidity Provider  |  EVM Wallet Address  |  EVM Blockchains Add EVM Network  |  Custodial Wallets Vs Non Custodial Wallets  |  Decentralized Identifiers  |  Cryptocurrency Career Opportunities  |  What is Consortium Blockchain  |  Major Components of Blockchain

The Shard

Sign up for The Shard community newsletter

Stay updated on major developments about Shardeum.

  • Share