Create a Defi bank that pays interest (Yield Farm)

In this tutorial I will explain how to create a solidity smart contract that functions like a decentralized savings bank. This smart contract will allow users to stake their USDC tokens and receive an interest payment based on the amount staked. The smart contract will also allow users to unstake their tokens at anytime.

This information is for educational and entertainment purposes only. It is to help one understand how smart contracts in this environment function.

Process

  • Users will stake their tokens in the Defi Bank solidity smart contract
  • Contract supports ability to unstake / remove tokens at any time
  • Users will receive a periodic interest payment for the amount of tokens staked
  • The interest payment will be in the form of a custom ERC20 token
Create a Defi bank that pays interest Yield Farm Crypto

Build the Components

Requirements for this project are:

  1. A solidity ERC20 token that you create and own
  2. A Defi Bank solidity smart contract
  3. A program in Python or Java script to trigger the smart contracts interest payments

ERC20 Token

To start you will need to create a custom ERC20 token in Solidity. This token will be used to as the interest payments to users who stake their tokens. If you need help creating an ERC20 token you can following this tutorial (Create an ERC20 token smart contract).

Defi Bank Smart Contract

Next you need to create a Defi Bank smart contract in Solidity. This smart contract will allow one to stake tokens, unstake tokens, and issue interest payments. The contract below contains three functions to get your Defi Bank started. The contract can be expanded to contain additional functions. Read the code comments to get a better understanding of how the contract works.

pragma solidity ^0.6.12;


interface IERC20 {
    function totalSupply() external view returns (uint);
    function balanceOf(address account) external view returns (uint);
    function transfer(address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint amount) external returns (bool);
    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}


contract DefiBank {
    
    // call it DefiBank
    string public name = "DefiBank";
    
    // create 2 state variables
    address public usdc;
    address public bankToken;


    address[] public stakers;
    mapping(address => uint) public stakingBalance;
    mapping(address => bool) public hasStaked;
    mapping(address => bool) public isStaking;


    // in constructor pass in the address for USDC token and your custom bank token
    // that will be used to pay interest
    constructor() public {
        usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
        bankToken = INPUT-YOUR-TOKEN-ADDRESS-HERE;

    }


    // allow user to stake usdc tokens in contract
    
    function stakeTokens(uint _amount) public {

        // Trasnfer usdc tokens to contract for staking
        IERC20(usdc).transferFrom(msg.sender, address(this), _amount);

        // Update the staking balance in map
        stakingBalance[msg.sender] = stakingBalance[msg.sender] + _amount;

        // Add user to stakers array if they haven't staked already
        if(!hasStaked[msg.sender]) {
            stakers.push(msg.sender);
        }

        // Update staking status to track
        isStaking[msg.sender] = true;
        hasStaked[msg.sender] = true;
    }

        // allow user to unstake total balance and withdraw USDC from the contract
    
     function unstakeTokens() public {

    	// get the users staking balance in usdc
    	uint balance = stakingBalance[msg.sender];
    
        // reqire the amount staked needs to be greater then 0
        require(balance > 0, "staking balance can not be 0");
    
        // transfer usdc tokens out of this contract to the msg.sender
        IERC20(usdc).transfer(msg.sender, balance);
    
        // reset staking balance map to 0
        stakingBalance[msg.sender] = 0;
    
        // update the staking status
        isStaking[msg.sender] = false;

} 


    // Issue bank tokens as a reward for staking
    
    function issueInterestToken() public {
        for (uint i=0; i<stakers.length; i++) {
            address recipient = stakers[i];
            uint balance = stakingBalance[recipient];
            
    // if there is a balance transfer the SAME amount of bank tokens to the account that is staking as a reward
            
            if(balance >0 ) {
                IERC20(bankToken).transfer(recipient, balance);
                
            }
            
        }
        
    }
}

Try it in Remix

Modify this contract to support:

  • Staking more or different tokens (USDT, USDC, etc.)
  • Enhance the staking function to move tokens into an interest bearing DEFI protocol
  • Paying interest as a percentage of the users balance. For example pay only 10% interest on active balances

Program to make interest payments

Finally, create a program in Python or Java script to call the issueInterestToken function in the smart contract above. This function will issue interest payments to all the accounts that have a staked balance. To create this program in Python you can use the following tutorial to get started (How to send an Ethereum transaction in Python). Modify the Python code in the tutorial to send a transaction to your smart contract to issue the interest payments to all accounts.

This code is for learning and entertainment purposes only. The code has not been audited and use at your own risk. Remember smart contracts are experimental and could contain bugs.

Click here for more information about how to use the Ethereum test network and how to obtain test ETH.

Next Review – How to sign & verify an Ethereum message off chain

Leave a Reply