基于ERC20代币协议实现的去中心化应用平台

文章目录

内容简介

使用 solidity 实现的基于 ERC20 代币协议的借贷款去中心化应用平台(极简版)。实现存款、取款、贷款、还款以及利息计算的功能。

设计逻辑

  • 平台提供ERC20协议代币的相关存取和利息计算工作。部署智能合约时初始化贷款和存款的年利率、代币实现地址。
  • 用户可以将手中的代币存入平台,等到一定的期限再次拿出获得本金加利息。也可以向平台申请代币,在一定的期限之后自主还款即可。

ERC20TokenLoanPlatform 合约

事件

合约包含4个事件,包括 Deposit 存款、Withdrawal 取款、CreateLoan 贷款、PayLoan 还款。

javascript 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "erc-token-standard/ERC/IERC20.sol"; 

// 基于ERC20代币协议的借贷款平台 
contract ERC20TokenLoanPlatform {
    event Deposit(address depositor, uint amount ,uint DepositTime); 
    event Withdrawal(address payee, uint amount, uint WithdrawalTime); 
    event CreateLoan(address loanAddress, uint amount, uint interest, uint CreateLoanTime); 
    event PayLoan(address loanAddress, uint amount, bool total, uint PayLoanTime); 

结构体

合约包含2个结构体, 包括 Client 客户信息、Loan 贷款信息。

javascript 复制代码
	// 客户信息 
	struct Client {
	    uint amount;
	    uint depositTime; 
	    uint withdrawalTime;
	}
	
	// 贷款信息
	struct Loan {
	    address loanAddress; 
	    uint amount;
	    uint interest; 
	}

状态变量

本合约使用了6个状态变量,其中有 clients 客户信息映射、loans 贷款信息映射、annualInterestRate 贷款年利率、annualDepositRate 存款年利率、tokenAddress 代币实现地址、erc20Token 代币对象。

javascript 复制代码
	mapping(address => Client) private clients; 
    mapping (uint => Loan) private loans;
    uint public annualInterestRate;        // 贷款年利率,如5%
    uint public annualDepositRate;         // 存款年利率,如2%
    address public tokenAddress;           // ERC20代币地址 
    IERC20 erc20Token; 

函数

本合约包含了8个基本函数,其中包括构造函数、deposit 存款、withdrawal 取款、createLoan 贷款、payLoan 还款、loanInquiry 待还款查询、depositInquiry 账户余额查询、balanceInquiry 客户信息查询 。

javascript 复制代码
	// 构造函数
    constructor(address _tokenAddress, uint _initLoanInterest, uint _initDepositInterest) {
        tokenAddress = _tokenAddress;           // 初始化代币地址 
        erc20Token = IERC20(tokenAddress);      // 声明IERC20接口合约变量
        annualInterestRate = _initLoanInterest; 
        annualDepositRate = _initDepositInterest;   
    }

    // 存款 
    function deposit(uint _amount) public {
        require(_amount > 0, "Amount is less than or equal to 0.");      // 存款代币数不能为0     
        require(erc20Token.balanceOf(msg.sender) >= _amount, "Number of tokens is insufficient.");            // 检查持有代币数是否大于等于存款代币数
        require(erc20Token.allowances(msg.sender, address(this)) >= _amount, "Not enough approvals.");        // 检查是否有足够的授权 

        erc20Token.transferFrom(msg.sender, address(this), _amount);             
        clients[msg.sender].amount += _amount;                      // 增加存款
        if (clients[msg.sender].depositTime == 0){
            clients[msg.sender].depositTime = block.timestamp;      // 当前的存款时间 
        }
        
        emit Deposit(msg.sender,_amount ,block.timestamp); 
    }

    // 取款 
    function withdrawal(uint _amount) public {
        require(_amount > 0, "Amount is less than or equal to 0.");               // 取款代币数不能为0  
        uint timestamp = block.timestamp;   
        depositInquiry();                 // 计算本金 + 利息2% 
        require(clients[msg.sender].amount >= _amount, "Insufficient balance.");         // 检查存款代币数是否大于等于取款代币数 
        require(erc20Token.balanceOf(address(this)) >= _amount, "Platform bankruptcy."); // 检查平台的代币数是否满足取款 
         
        erc20Token.transfer(msg.sender, _amount);            
        clients[msg.sender].amount -= _amount; 
        clients[msg.sender].withdrawalTime = timestamp; 

        emit Withdrawal(msg.sender, _amount, timestamp);
    }

    // 贷款
    function createLoan(uint _amount) public returns (uint){
        require(_amount > 0, "Amount is less than or equal to 0.");            // 贷款不能小于0        
        require(erc20Token.balanceOf(address(this))*10/100 >= _amount, "Exceeding the platform loan limit.");        // 超过平台总存款的10%
        require(erc20Token.balanceOf(msg.sender) + clients[msg.sender].amount >= _amount*20/100, "Invalid loan.");   // 账户资产数需有贷款的20%

        erc20Token.transfer(msg.sender, _amount); 
        uint timestamp = block.timestamp;           // 以当前块的时间戳为贷款id值 
        uint interest = _amount * annualInterestRate / 100;     // 计算利率 
        
        loans[timestamp].loanAddress = msg.sender; 
        loans[timestamp].amount = _amount; 
        loans[timestamp].interest = interest;     // 计算利率 

        emit CreateLoan(msg.sender, _amount, interest, timestamp);

        return timestamp; 
    }

    // 还款
    function payLoan(uint _amount, uint _loanId) public {
        require(_amount > 0, "Amount is less than or equal to 0.");        // 还款需大于0
        require(erc20Token.balanceOf(msg.sender) >= _amount, "Number of tokens is insufficient.");            // 检查持有代币数是否大于等于存款代币数
        require(erc20Token.allowances(msg.sender, address(this)) >= _amount, "Not enough approvals.");        // 检查是否有足够的授权 

        uint total = loanInquiry(_loanId);        // 计算代还款 
        bool fullPayment = false; 

        // 还一部分或一次性还 
        if (total <= _amount) {     
            erc20Token.transferFrom(msg.sender, address(this), total);       // 一次性还完
            delete loans[_loanId];                                           // 删除贷款记录  
            fullPayment = true; 
        } else {    
            erc20Token.transferFrom(msg.sender, address(this), _amount);        // 还了一部分 _amount 
            loans[_loanId].amount -= _amount;                                   // 重写贷款记录 
        }
        
        emit PayLoan(msg.sender, _amount, fullPayment, block.timestamp);
    }

    
    // 待还款查询
    function loanInquiry(uint _loanId) public returns (uint) {
        require(loans[_loanId].amount != 0, "Invalid loan id.");
        require(loans[_loanId].loanAddress == msg.sender, "Non-personal enquiry.");

        // 计算需要还款的代币数: 本金 + 利息
        uint timestamp = block.timestamp; 
        uint diffDays = ( timestamp - _loanId) / 86400;                 // 时间戳转换为天数 
        uint total = loans[_loanId].amount + loans[_loanId].interest*diffDays/365;      // 总计还款数 
        
        loans[_loanId].amount = total;            //重写用户贷款数 

        return total; 
    }

    // 余额+利息的计算
    function depositInquiry() public  returns (uint){
        uint principal = clients[msg.sender].amount;    // 本金
        uint diffDays = (block.timestamp - clients[msg.sender].depositTime) / 86400;                 // 时间戳转换为天数 
        uint interest = principal * annualDepositRate / 100 * diffDays / 365;
        uint total = principal + interest;
        clients[msg.sender].amount = total;

        return total;
    }

    // 客户信息查询 
    function balanceInquiry() public returns (address, uint, uint, uint){
        depositInquiry();                 // 计算本金 + 利息2% 
        uint balance = clients[msg.sender].amount;
        uint depositTime = clients[msg.sender].depositTime;
        uint withdrawalTime = clients[msg.sender].withdrawalTime;

        return (msg.sender, balance, depositTime, withdrawalTime);
    }
}

Remix 运行实现

部署相关智能合约

solidity实现ERC20代币标准。

先部署 ++ERC20 代币合约++ ,初始化代币合约信息。

部署 ++ERC20TokenLoanPlatform 合约++ ,初始化代币实现地址、贷款年利率5和存款年利率2。

首先需要给自己的账户铸造 200 个代币用于功能测试,

再给 ++ERC20TokenLoanPlatform 合约地址++ 铸造一定数量的代币和授权代币转账权限,保证平台功能的正常运行。

存款和取款

调用 deposit 函数 存款 100 个代币,

balanceInquiry 函数 查看余额变化,这里已经显示自己的余额为刚才存入的100。

调用 withdrawal 函数 取出指定数量的代币,不能超出自己的余额。平台会自动进行存款利息计算。

balanceInquiry 函数 查看余额变化,这里已经显示自己的余额还剩下50。

贷款和还款

调用 createLoan 函数 输入自己需要贷多少代币。在这里注意账户的资产需要有贷款数的20%才有资格贷款。成功后拿到此次贷款的id值 1703236890。

调用 payLoan 函数输入贷款的 id 值进行还款,可以先还一部分也可以一次性还完,平台会自动进行贷款利息计算。

调用 loanInquiry 函数 输入贷款的 id 值进行待还款的查询。

源码地址

本文只是简单介绍,具体实现看代码。gitee 开源地址。


相关推荐
Joker时代5 小时前
Anubi WebKey开启去中心化数字革命的新纪元
去中心化·区块链
软件工程小施同学6 小时前
区块链论文速读A会-ISSTA 2023(2/2)如何检测DeFi协议中的价格操纵漏洞
区块链·区块链会议·区块链论文
mutourend7 小时前
EVM-MLIR:以MLIR编写的EVM
区块链
虫小宝17 小时前
如何在Java中实现智能合约与区块链集成
java·区块链·智能合约
sino_sound17 小时前
从资金管理的角度 谈谈伦敦金投资技巧
区块链
UI设计开发服务商19 小时前
HMI 的 UI 风格成就经典
大数据·人工智能·数据分析·云计算·区块链
凄戚1 天前
分布式共识算法
分布式·区块链·共识算法
软件工程小施同学2 天前
区块链可投会议CCF C--TrustCom 2024 截止9.1 附去年录用文章
区块链·区块链会议·区块链论文·区块链投稿
Sui_Network2 天前
探索Sui的面向对象模型和Move编程语言
大数据·人工智能·学习·区块链·智能合约
Code blocks2 天前
小试牛刀-Solana合约账户详解
区块链·智能合约