內(nèi)容簡(jiǎn)介
使用 solidity 實(shí)現(xiàn)的基于 ERC20 代幣協(xié)議的借貸款去中心化應(yīng)用平臺(tái)(極簡(jiǎn)版)。實(shí)現(xiàn)存款、取款、貸款、還款以及利息計(jì)算的功能。
設(shè)計(jì)邏輯
- 平臺(tái)提供ERC20協(xié)議代幣的相關(guān)存取和利息計(jì)算工作。部署智能合約時(shí)初始化貸款和存款的年利率、代幣實(shí)現(xiàn)地址。
- 用戶可以將手中的代幣存入平臺(tái),等到一定的期限再次拿出獲得本金加利息。也可以向平臺(tái)申請(qǐng)代幣,在一定的期限之后自主還款即可。
ERC20TokenLoanPlatform 合約
事件
合約包含4個(gè)事件,包括 Deposit 存款、Withdrawal 取款、CreateLoan 貸款、PayLoan 還款。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "erc-token-standard/ERC/IERC20.sol";
// 基于ERC20代幣協(xié)議的借貸款平臺(tái)
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);
結(jié)構(gòu)體
合約包含2個(gè)結(jié)構(gòu)體, 包括 Client 客戶信息、Loan 貸款信息。
// 客戶信息
struct Client {
uint amount;
uint depositTime;
uint withdrawalTime;
}
// 貸款信息
struct Loan {
address loanAddress;
uint amount;
uint interest;
}
狀態(tài)變量
本合約使用了6個(gè)狀態(tài)變量,其中有 clients 客戶信息映射、loans 貸款信息映射、annualInterestRate 貸款年利率、annualDepositRate 存款年利率、tokenAddress 代幣實(shí)現(xiàn)地址、erc20Token 代幣對(duì)象。
mapping(address => Client) private clients;
mapping (uint => Loan) private loans;
uint public annualInterestRate; // 貸款年利率,如5%
uint public annualDepositRate; // 存款年利率,如2%
address public tokenAddress; // ERC20代幣地址
IERC20 erc20Token;
函數(shù)
本合約包含了8個(gè)基本函數(shù),其中包括構(gòu)造函數(shù)、deposit 存款、withdrawal 取款、createLoan 貸款、payLoan 還款、loanInquiry 待還款查詢、depositInquiry 賬戶余額查詢、balanceInquiry 客戶信息查詢 。
// 構(gòu)造函數(shù)
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."); // 存款代幣數(shù)不能為0
require(erc20Token.balanceOf(msg.sender) >= _amount, "Number of tokens is insufficient."); // 檢查持有代幣數(shù)是否大于等于存款代幣數(shù)
require(erc20Token.allowances(msg.sender, address(this)) >= _amount, "Not enough approvals."); // 檢查是否有足夠的授權(quán)
erc20Token.transferFrom(msg.sender, address(this), _amount);
clients[msg.sender].amount += _amount; // 增加存款
if (clients[msg.sender].depositTime == 0){
clients[msg.sender].depositTime = block.timestamp; // 當(dāng)前的存款時(shí)間
}
emit Deposit(msg.sender,_amount ,block.timestamp);
}
// 取款
function withdrawal(uint _amount) public {
require(_amount > 0, "Amount is less than or equal to 0."); // 取款代幣數(shù)不能為0
uint timestamp = block.timestamp;
depositInquiry(); // 計(jì)算本金 + 利息2%
require(clients[msg.sender].amount >= _amount, "Insufficient balance."); // 檢查存款代幣數(shù)是否大于等于取款代幣數(shù)
require(erc20Token.balanceOf(address(this)) >= _amount, "Platform bankruptcy."); // 檢查平臺(tái)的代幣數(shù)是否滿足取款
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."); // 超過平臺(tái)總存款的10%
require(erc20Token.balanceOf(msg.sender) + clients[msg.sender].amount >= _amount*20/100, "Invalid loan."); // 賬戶資產(chǎn)數(shù)需有貸款的20%
erc20Token.transfer(msg.sender, _amount);
uint timestamp = block.timestamp; // 以當(dāng)前塊的時(shí)間戳為貸款id值
uint interest = _amount * annualInterestRate / 100; // 計(jì)算利率
loans[timestamp].loanAddress = msg.sender;
loans[timestamp].amount = _amount;
loans[timestamp].interest = interest; // 計(jì)算利率
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."); // 檢查持有代幣數(shù)是否大于等于存款代幣數(shù)
require(erc20Token.allowances(msg.sender, address(this)) >= _amount, "Not enough approvals."); // 檢查是否有足夠的授權(quán)
uint total = loanInquiry(_loanId); // 計(jì)算代還款
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.");
// 計(jì)算需要還款的代幣數(shù): 本金 + 利息
uint timestamp = block.timestamp;
uint diffDays = ( timestamp - _loanId) / 86400; // 時(shí)間戳轉(zhuǎn)換為天數(shù)
uint total = loans[_loanId].amount + loans[_loanId].interest*diffDays/365; // 總計(jì)還款數(shù)
loans[_loanId].amount = total; //重寫用戶貸款數(shù)
return total;
}
// 余額+利息的計(jì)算
function depositInquiry() public returns (uint){
uint principal = clients[msg.sender].amount; // 本金
uint diffDays = (block.timestamp - clients[msg.sender].depositTime) / 86400; // 時(shí)間戳轉(zhuǎn)換為天數(shù)
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(); // 計(jì)算本金 + 利息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 運(yùn)行實(shí)現(xiàn)
部署相關(guān)智能合約
solidity實(shí)現(xiàn)ERC20代幣標(biāo)準(zhǔn)。
先部署 ERC20 代幣合約,初始化代幣合約信息。
部署 ERC20TokenLoanPlatform 合約,初始化代幣實(shí)現(xiàn)地址、貸款年利率5和存款年利率2。
首先需要給自己的賬戶鑄造 200 個(gè)代幣用于功能測(cè)試,
再給 ERC20TokenLoanPlatform 合約地址鑄造一定數(shù)量的代幣和授權(quán)代幣轉(zhuǎn)賬權(quán)限,保證平臺(tái)功能的正常運(yùn)行。
存款和取款
調(diào)用 deposit 函數(shù)存款 100 個(gè)代幣,
balanceInquiry 函數(shù)查看余額變化,這里已經(jīng)顯示自己的余額為剛才存入的100。
調(diào)用 withdrawal 函數(shù)取出指定數(shù)量的代幣,不能超出自己的余額。平臺(tái)會(huì)自動(dòng)進(jìn)行存款利息計(jì)算。
balanceInquiry 函數(shù)查看余額變化,這里已經(jīng)顯示自己的余額還剩下50。
貸款和還款
調(diào)用 createLoan 函數(shù)輸入自己需要貸多少代幣。在這里注意賬戶的資產(chǎn)需要有貸款數(shù)的20%才有資格貸款。成功后拿到此次貸款的id值 1703236890。
調(diào)用 payLoan 函數(shù)輸入貸款的 id 值進(jìn)行還款,可以先還一部分也可以一次性還完,平臺(tái)會(huì)自動(dòng)進(jìn)行貸款利息計(jì)算。
調(diào)用 loanInquiry 函數(shù)輸入貸款的 id 值進(jìn)行待還款的查詢。文章來源:http://www.zghlxwxcb.cn/news/detail-761776.html
源碼地址
本文只是簡(jiǎn)單介紹,具體實(shí)現(xiàn)看代碼。gitee 開源地址。文章來源地址http://www.zghlxwxcb.cn/news/detail-761776.html
到了這里,關(guān)于基于ERC20代幣協(xié)議實(shí)現(xiàn)的去中心化應(yīng)用平臺(tái)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!