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

文章目录

  • 内容简介
  • 设计逻辑
  • ERC20TokenLoanPlatform 合约
    • 事件
    • 结构体
    • 状态变量
    • 函数
  • Remix 运行实现
    • 部署相关智能合约
    • 存款和取款
    • 贷款和还款
  • 源码地址

内容简介

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

设计逻辑

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

ERC20TokenLoanPlatform 合约

事件

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

// 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 贷款信息。

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

状态变量

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

	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 客户信息查询 。

	// 构造函数
    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 开源地址。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/267357.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

宜春万申智能装备携粉体自动化产线解决方案盛装亮相2024济南生物发酵展

宜春万申智能装备股份有限公司受邀盛装亮相2024第12届济南国际生物发酵展 展位号&#xff1a;1号馆A16-2展位 2024第12届国际生物发酵产品与技术装备展览会&#xff08;济南&#xff09;于3月5-7日在山东国际会展中心盛大召开&#xff0c;全方面展示&#xff1a;生物发酵、生…

分布式锁功效初探——以电商问题为例

文章目录 电商库存问题单机处理-Sychronized多机器处理-分布式锁入门级别&#xff0c;用redis实现&#xff0c;setnx问题1&#xff1a;逻辑可能异常&#xff0c;造成死锁问题2&#xff1a;机器宕机问题3&#xff1a;锁一直失效&#xff0c;乱套锁续命 redisson分布式丢锁问题主…

数独 -- 合法数独与完全数独

一、数独的介绍 从2004年底开始&#xff0c;数独游戏在英国变得非常流行。数独(Sudoku)是一个日语单词意思是数字位置之类的单词(或短语)。谜题的理念非常简单;面对一个9 9的网格&#xff0c;被分成9个3 3的块: 在其中的一些盒子里&#xff0c;设置者放一些数字1-9:求解者的目…

前端未死,顺势而生

随着人工智能和低代码的崛起&#xff0c;“前端已死”的声音逐渐兴起。前端已死&#xff1f;尊嘟假嘟&#xff1f;快来发表你的看法吧&#xff01; 一、“前端已死”因何而来&#xff1f; 在开始讨论之前&#xff0c;首先要明确什么是“前端”。 所谓前端&#xff0c;主要涉及…

vue使用ElementUI搭建精美页面入门

ElementUI简直是css学得不好的同学的福音 ElementUI官网&#xff1a; Element - The worlds most popular Vue UI framework 安装 在vue文件下&#xff0c;用这个命令去安装Element UI。 npm i element-ui -S step1\先切换到vue的目录下去&#xff0c;注意这里面的WARN不是…

每日一题:LCR 095.最长公共子序列(DP)

题目描述&#xff1a; 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些…

R语言基础 | 安徽某高校《统计建模与R软件》期末复习

第一节 数字、字符与向量 1.1 向量的赋值 c<-(1,2,3,4,5) 1.2 向量的运算 对于向量&#xff0c;我们可以直接对其作加&#xff08;&#xff09;&#xff0c;减&#xff08;-&#xff09;&#xff0c;乘&#xff08;*&#xff09;&#xff0c;除&#xff08;/&#xff09…

使用Python实现发送Email电子邮件【第19篇—python发邮件】

文章目录 &#x1f47d;使用Python实现发送Email电子邮件&#x1f3b6;实现原理&#x1f3c3;Python实现发送Email电子邮件-基础版&#x1f46b;实现源码&#x1f646;源码解析 &#x1f487;Python实现发送Email电子邮件-完善版&#x1f46b;实现源码&#x1f646;源码解析&am…

随机无限采集JK妹妹高清壁纸下载HTML网页源码

源码介绍 美图网站千千万&#xff0c;美图自己说了算&#xff01;本源码由宋佳乐博客 开发&#xff0c;首页图片做了浏览器窗口自适应&#xff0c;最大化占满PC浏览器和移动浏览器的窗口&#xff0c;并且防止出现滚动条。 功能介绍 首页图片设置了4个点击功能区&#xff0c;…

【数据结构入门精讲 | 第十一篇】一文讲清树

在上一篇中我们进行了排序算法的专项练习&#xff0c;现在让我们开始树的知识点讲解。 目录 树二叉搜索树二叉排序树哈夫曼树折半查找判定树kruskal算法、prim算法、最小生成树完全二叉树 树 树是一种非线性的数据结构&#xff0c;也是一种表示一对多关系的数据结构&#xff0…

Flink CDC 1.0至3.0回忆录

Flink CDC 1.0至3.0回忆录 一、引言二、CDC概述三、Flink CDC 1.0&#xff1a;扬帆起航3.1 架构设计3.2 版本痛点 四、Flink CDC 2.0&#xff1a;成长突破4.1 DBlog 无锁算法4.2 FLIP-27 架构实现4.3 整体流程 五、Flink CDC 3.0&#xff1a;应运而生六、Flink CDC 的影响和价值…

Python 数据分析 Matplotlib篇 plot设置线条样式(第2讲)

Python 数据分析 Matplotlib篇 plot设置线条样式(第2讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

算法基础之完全背包问题

完全背包问题 核心思想&#xff1a;集合表示&#xff1a; f[i][j]表示前i种物品 总容量不超过j的最大价值 求f[i][j]时 分为选0、1、2……n个第i种物品 n种情况 每种情况为 f[i][j-kv] (取k个第i种物品) 即f[i][j] max(f[i-1][j] , f[i-1][j-v]w,f[i-1][j-2v]2w….f[i-1][j-k…

【自用】Ubuntu20.4从Vivado到ddr200t运行HelloWorld

【自用】Ubuntu20.4新系统从输入法到ddr200t运行HelloWorld 一、编辑bashrc二、Vivado2022.2安装三、编译蜂鸟E203自测样例1. 环境准备2. 下载e203_hbirdv2工程文件3. 尝试编译自测案例1. 安装RISC-V GNU工具链2. 编译测试样例 4. 用vivado为FPGA生成mcs文件1.准备RTL2.生成bit…

Centos 7.9安装Oracle19c步骤亲测可用有视频

视频介绍了在虚拟机安装centos 7.9并安装数据库软件的全过程 视频链接&#xff1a;https://www.zhihu.com/zvideo/1721267375351996416 下面的文字描述是安装数据库的部分介绍 一.安装环境准备 链接&#xff1a;https://pan.baidu.com/s/1Ogn47UZQ2w7iiHAiVdWDSQ 提取码&am…

贝叶斯球快速检验条件独立

贝叶斯球 定义几个术语&#xff0c;描述贝叶斯球在一个结点上的动作&#xff1a; 通过&#xff08;pass through&#xff09;&#xff1a;从当前结点的父结点方向过来的球&#xff0c;可以访问当前结点的任意子结点&#xff08;父->子&#xff09;。从当前节点的子结点方向…

基于电商场景的高并发RocketMQ实战-NameServer内核原理剖析、Broker 主从架构与集群模式原理分析

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 【11来了】文章导读地址&#xff1a;点击查看文章导读&#xff01; &#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f3…

Prometheus介绍和安装

Prometheus介绍和安装 1. Prometheus介绍 Prometheus&#xff08;普罗米修斯&#xff09;是一个最初在SoundCloud上构建的监控系统。自2012年成为社区开源项目&#xff0c;拥有非常活跃的开发人员和用户社区。为强调开源及独立维护&#xff0c;Prometheus于2016年加入云原生云…

指标体系构建-03-交易型的数据指标体系

参考&#xff1a; 本文参考 1.接地气的陈老师的数据指标系列 2.科普 | 零售行业的数据指标体系及其含义、应用阶段 3.”人货场”模型搞懂没&#xff1f;数据分析大部分场景都能用&#xff01; 4.一分钟读懂广告投放各计费CPM、CPC等&#xff08;公式推导干货&#xff09; 5.AA…

mysql 数据编译安装以及参数说明 安装包下载

目录 MySQL 官网地址官网下载源码包安装步骤修改密码 MySQL 官网地址 https://dev.mysql.com/doc/ 官网下载源码包 安装步骤 # 所需要的依赖及安装mysql的包" [rootmysql_source ~]# yum -y install ncurses ncurses-devel openssl-devel bison libgcrypt gcc gcc-c ma…