We have built a collection of DeFi Smart-Contracts for XDC chain

Contracts


Lending Contract

  • Create a pool contract that accepts deposit from lenders and borrow money to the borrowers
  • Lenders can lend any amount of money and earn some interest for it.
  • User or borrower can borrow some amount of tokens (limited) , and pay back with interest for some time period.
  • Interest is calculated according the interest rate and borrowing time peroid
  • Lender can withdraw the amount later with extra interest earning
  • Other functions can be called to determine the balance at any point of time , and the rewards earned
// SPDX-License-Identifier: MIT
  pragma solidity ^0.8.13;
  
  // - Create a pool contract that accepts deposit from lenders , who earn interest on lending
  // - User  or borrower can borrow some amount of tokens (limited) , and pay back with some interest for some time period.
  // - lender can withdraw the amount later with some interest
  
  // interface of the tokens to be awarded as rewards for the user
  interface IERC20 {
      function totalSupply() external view returns (uint256);
  
      function balanceOf(address account) external view returns (uint256);
  
      function transfer(address recipient, uint256 amount)
          external
          returns (bool);
  
      function allowance(address owner, address spender)
          external
          view
          returns (uint256);
  
      function approve(address spender, uint256 amount) external returns (bool);
  
      function transferFrom(
          address sender,
          address recipient,
          uint256 amount
      ) external returns (bool);
  
      event Transfer(address indexed from, address indexed to, uint256 value);
      event Approval(
          address indexed owner,
          address indexed spender,
          uint256 value
      );
  }
  
  contract LiquidityPool {
      /// intialize token
      IERC20 token;
      uint256 totalSupply;
  
      /// the rate earned by the lender per second
      uint256 lendRate = 100;
      /// the rate paid by the borrower per second
      uint256 borrowRate = 130;
  
      uint256 peroidBorrowed;
  
      ///  struct with amount and date of borrowing or lending
      struct amount {
          uint256 amount;
          uint256 start;
      }
  
      // mapping to check if the address has lended any amount
      mapping(address => amount) lendAmount;
      // mapping for the interest earned by the lender ;
      mapping(address => uint256) earnedInterest;
  
      // arrays to store the info about lender & borrowers
      mapping(address => bool) lenders;
      mapping(address => bool) borrowers;
  
      // mapping to check if the address has borrowed any amount
      mapping(address => amount) borrowAmount;
      // mapping for the interest to be paid by the borrower ;
      mapping(address => uint256) payInterest;
  
      /// events
  
      /// making the contract payable and adding the tokens in starting to the pool
  
      constructor(address _tokenAddress, uint256 _amount) payable {
          token = IERC20(_tokenAddress);
          token.transferFrom(msg.sender, address(this), _amount);
      }
  
      /// @dev - to lend the amount by  , add liquidity
      /// @param _amount - the amount to be lender
      function lend(uint256 _amount) external {
          require(_amount != 0, " amount can not be 0");
  
          /// transferring the tokens to the pool contract
          token.transferFrom(msg.sender, address(this), _amount);
  
          /// adding in lending and lenders array for record
          lendAmount[msg.sender].amount = _amount;
          lendAmount[msg.sender].start = block.timestamp;
          lenders[msg.sender] = true;
  
          /// updating total supply
          totalSupply += _amount;
      }
  
      /// @dev - to borrow token
      /// @param _amount - amount to be withdraw
      function borrow(uint256 _amount) external {
          require(_amount != 0, " amount can not be 0");
  
          /// updating records first
          borrowAmount[msg.sender].amount = _amount;
          borrowAmount[msg.sender].start = block.timestamp;
          totalSupply -= _amount;
  
          /// then transfer
          token.transfer(msg.sender, _amount);
          borrowers[msg.sender] = true;
      }
  
      /// @dev  - repay the whole loan
      function repay() external {
          /// check borrower
          require(borrowers[msg.sender], "not a borrower");
  
          /// total amount to be repaid with intrest
          amount storage amount_ = borrowAmount[msg.sender];
          uint256 _amount = (amount_.amount +
              (amount_.amount *
                  ((block.timestamp - amount_.start) * borrowRate * 1e18)) /
              totalSupply);
  
          require(_amount != 0, " amount can not be 0");
  
          /// transferring the tokens
          token.transferFrom(msg.sender, address(this), _amount);
  
          /// updating records and deleting the record of borrowing
          delete borrowAmount[msg.sender];
          borrowers[msg.sender] = false;
  
          /// update total supply at the end
          totalSupply += _amount;
      }
  
      /// @dev  - to withdraw the amount for the lender
      function withdraw() external {
          /// checking if the caller is a lender or not
          require(lenders[msg.sender], "you are not a lender");
  
          // calculating the total amount along with the interest
          amount storage amount_ = lendAmount[msg.sender];
          uint256 _amount = (amount_.amount +
              (amount_.amount *
                  ((block.timestamp - amount_.start) * lendRate * 1e18)) /
              totalSupply);
  
          require(_amount != 0, " amount can not be 0");
  
          /// deleting the records and updating the list
          delete lendAmount[msg.sender];
          lenders[msg.sender] = false;
  
          /// updating total supply earlier before transfering token , so as to be safe from attacks
          totalSupply -= _amount;
  
          /// transferring the tokens in the end
          token.transfer(msg.sender, _amount);
      

Staking Contract

  • Rewards user for staking their tokens in the contract
  • User can withdraw and deposit at an point of time
  • Tokens Earned can be withdrawed any time
  • Rewards are calculated with reward rate and time period staked for
  • The balance and reward earned can be checked at any point of time
// SPDX-License-Identifier: MIT
  pragma solidity ^0.8.13;
  
  // interface of the tokens to be awarded as rewards for the user
  interface IERC20 {
      function totalSupply() external view returns (uint256);
  
      function balanceOf(address account) external view returns (uint256);
  
      function transfer(address recipient, uint256 amount)
          external
          returns (bool);
  
      function allowance(address owner, address spender)
          external
          view
          returns (uint256);
  
      function approve(address spender, uint256 amount) external returns (bool);
  
      function transferFrom(
          address sender,
          address recipient,
          uint256 amount
      ) external returns (bool);
  
      event Transfer(address indexed from, address indexed to, uint256 value);
      event Approval(
          address indexed owner,
          address indexed spender,
          uint256 value
      );
  }
  
  // - Rewards user for staking their tokens
  // - User can withdraw and deposit
  // - Earns token while withdrawing
  
  /// rewards are calculated with reward rate and time period staked for
  
  contract Staking {
      // tokens intialized
      IERC20 public rewardsToken;
      IERC20 public stakingToken;
  
      // 100 wei per second , calculated for per anum
      uint256 public rewardRate = 100;
      uint256 public lastUpdateTime;
      uint256 public rewardPerTokenStored;
  
      // mapping for the rewards for an address
      mapping(address => uint256) public rewards;
  
      // mapping for the rewards per token paid
      mapping(address => uint256) public rewardsPerTokenPaid;
  
      // mapping for staked amount by an address
      mapping(address => uint256) staked;
  
      // total supply for the staked token in the contract
      uint256 public _totalSupply;
  
      constructor(address _stakingToken, address _rewardsToken) {
          stakingToken = IERC20(_stakingToken);
          rewardsToken = IERC20(_rewardsToken);
      }
  
      /// @dev - to calculate the amount of rewards per token staked at current instance
      /// @return uint - the amount of rewardspertoken
      function rewardPerToken() public view returns (uint256) {
          if (_totalSupply == 0) {
              return rewardPerTokenStored;
          }
          return
              rewardPerTokenStored +
              (((block.timestamp - lastUpdateTime) * rewardRate * 1e18) /
                  _totalSupply);
      }
  
      /// @dev - to calculate the earned rewards for the token staked
      /// @param account - for which it is to be calculated
      /// @return uint -  amount of earned rewards
      function earned(address account) public view returns (uint256) {
          /// amount will be the earned amount according to the staked + the rewards the user earned earlier
          return
              ((staked[account] *
                  (rewardPerToken() - rewardsPerTokenPaid[account])) / 1e18) +
              rewards[account];
      }
  
      /// modifier that will calculate the amount every time the user calls , and update them in the rewards array
      modifier updateReward(address account) {
          rewardPerTokenStored = rewardPerToken();
          lastUpdateTime = block.timestamp;
  
          /// updating the total rewards owned by the user
          rewards[account] = earned(account);
          /// updatig per token reward amount in the mapping
          rewardsPerTokenPaid[account] = rewardPerTokenStored;
          _;
      }
  
      /// @dev to stake some amount of token
      /// @param _amount -  amount to be staked
      function stake(uint256 _amount) external updateReward(msg.sender) {
          _totalSupply += _amount;
          staked[msg.sender] += _amount;
          stakingToken.transferFrom(msg.sender, address(this), _amount);
      }
  
      /// @dev to withdraw the staked amount
      /// @param _amount - amount to be withdrawn
      function withdraw(uint256 _amount) external updateReward(msg.sender) {
          _totalSupply -= _amount;
          staked[msg.sender] -= _amount;
          stakingToken.transfer(msg.sender, _amount);
      }
  
      /// @dev to withdraw the reward token
      function getReward() external updateReward(msg.sender) {
          uint256 reward = rewards[msg.sender];
          rewards[msg.sender] = 0;
          rewardsToken.transfer(msg.sender, reward);
      }
  }

Vault Contract

  • Sharing of Yield For the no. of shares owned
  • User can deposit their money
  • Some shares are minted according to the value deposited
  • Vault generate some yield by a puropose and the value of share increases
  • user can withdraw the amount by burning those share at any point of time .
// SPDX-License-Identifier: MIT
  pragma solidity ^0.8.13;
  
  /// user can deposit his money
  /// it wll mint some share
  /// vault generate some yield
  /// user can withdraw the shares with the increased amount
  
  contract Vault {
      IERC20 public immutable token;
      uint256 public totalSupply;
  
      mapping(address => uint256) public balanceOf;
  
      constructor(address _token) {
          token = IERC20(_token);
      }
  
      function mint(address _to, uint256 shares) private {
          totalSupply += shares;
          balanceOf[_to] += shares;
      }
  
      function burn(address _from, uint256 shares) private {
          totalSupply -= shares;
          balanceOf[_from] -= shares;
      }
  
      function deposit(uint256 _amount) external {
          uint256 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(uint256 _shares) external {
          uint256 amount = (_shares * token.balanceOf(address(this))) /
              totalSupply;
          burn(msg.sender, _shares);
          token.transfer(msg.sender, amount);
      }
  }
  
  interface IERC20 {
      function totalSupply() external view returns (uint256);
  
      function balanceOf(address account) external view returns (uint256);
  
      function transfer(address recipient, uint256 amount)
          external
          returns (bool);
  
      function allowance(address owner, address spender)
          external
          view
          returns (uint256);
  
      function approve(address spender, uint256 amount) external returns (bool);
  
      function transferFrom(
          address sender,
          address recipient,
          uint256 amount
      ) external returns (bool);
  
      event Transfer(address indexed from, address indexed to, uint256 amount);
      event Approval(
          address indexed owner,
          address indexed spender,
          uint256 amount
      );
  }