前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >defi质押挖矿智能合约dapp系统开发详解

defi质押挖矿智能合约dapp系统开发详解

原创
作者头像
开发v_hkkf5566
发布2022-10-21 16:46:07
8210
发布2022-10-21 16:46:07
举报
文章被收录于专栏:技术开发分享

本文介绍通过质押底层币(以太坊)资产获取收益的一般逻辑及其实现方法,该方案在很多defi项目得到应用;本文中的收益为ERC20通证,收益获取也可以理解为挖矿行为。

1 合约主要功能函数介绍

1.1 主要参数

address private owner; //合约部署(拥有者)账号地址

address private profitor; //收益分配者账号地址,仅该地址有权分配收益

bool _isDIS = false; //质押合约功能状态,true才可以进行质押

ERC20 _Token; //用于分配收益的ERC20资产

KeyFlag[] keys; //用于标记用户地址的质押状态

uint256 size; //质押者地址(用户)数量

uint256 _maxPledgeAmount; //最大质押(底层币)额度

uint256 _maxMiningAmount; //最大(ERC20收益分配)额度

uint256 _leftMiningAmount; //剩余额度

uint256 _minAmount; //单次最少质押额度

uint256 _totalPledegAmount; //已质押总额度

uint256 _maxPreMiningAmount; //最大单次分配额度

uint256 _startTime; //开始时间,单位“秒”

uint256 _endTime; //结束时间,单位“秒”

uint256 _precentUp=100; //与_precentDown一起设定每次收益提取比例

uint256 _precentDown=100; //与_precentUp一起设定每次收益提取比例

struct PledgeOrder { //结构体,用于标记质押用户的各类状态

bool isExist; //质押状态

uint256 token; //质押额度

uint256 profitToken; //收益额度

uint256 time; //最近一次提取收益时间

uint256 index; //质押地址序号

}

struct KeyFlag { //结构体,用于标记用户地址的质押状态

address key; //地址

bool isExist; //质押状态

}

部署合约时,构造函数内的参数需要用户输入,以完成相应的参数设置并实现相应功能;

1.2 质押函数pledgeToken

function pledgeToken() public payable{

require(address(msg.sender) == address(tx.origin), "no contract");

require(_isDIS, "is disable");

require(_leftMiningAmount>0, "less token");

require(msg.value>=_minAmount, "less token");

require(_totalPledegAmount.add(msg.value)<=_maxPledgeAmount, "more token");

require(block.timestamp>=_startTime&&block.timestamp<=_endTime, "is disable");

if(_orders[msg.sender].isExist==false){

keys.push(KeyFlag(msg.sender,true));

size++;

createOrder(msg.value,keys.length.sub(1));

}else{

PledgeOrder storage order=_orders[msg.sender];

order.token=order.token.add(msg.value);

keys[order.index].isExist=true;

}

_totalPledegAmount=_totalPledegAmount.add(msg.value);

}

功能说明:

明显的,该函数具有接收底层币功能(payable);

质押地址必须是账号地址,不能是合约地址;

需要合约质押功能已经开始,且在活动限定时间内;

剩余额度大于0;

进行质押的底层币额度不能少于最小值,质押后也不能超过限定的最大质押额度;

如果该用户之前没有质押过,则建立档案(createOrder),否则仅修改档案;

1.3 收益分配函数profit

function profit() public onlyProfitor{

require(_leftMiningAmount>0, "less token");

require(_totalPledegAmount>0, "no pledge");

uint256 preToken=_maxPreMiningAmount;

if(_leftMiningAmount<_maxPreMiningAmount){

preToken=_leftMiningAmount;

}

for(uint i = 0; i < keys.length; i++) {

if(keys[i].isExist==true){

PledgeOrder storage order=_orders[keys[i].key];

order.profitToken=order.profitToken.add(order.token.mul(preToken).div(_totalPledegAmount));

}

}

_leftMiningAmount=_leftMiningAmount.sub(preToken);

}

功能说明:

必须尚有剩余额度可供分配;

当前质押总额必须大于0;

如果剩余额度足够,则按规则分配设定的每次最大分配额度(_maxPreMiningAmount);

如果剩余额度小于每次最大分配额度,则将剩余额度全部进行分配;根据用户质押数量,平均分配所有额度;

即质押余额越多,收益越多;

1.4 收益提取函数takeProfit

function takeProfit() public {

require(address(msg.sender) == address(tx.origin), "no contract");

require(_orders[msg.sender].profitToken>0,"less token");

uint256 time=block.timestamp;

uint256 diff=time.sub(_takeProfitTime[msg.sender]);

require(diff>86400,"less time");

PledgeOrder storage order=_orders[msg.sender];

uint256 takeToken=order.profitToken.mul(_precentUp).div(_precentDown);

order.profitToken=order.profitToken.sub(takeToken);

_takeProfitTime[msg.sender]=time;

_Token.safeTransfer(address(msg.sender),takeToken);

}

功能说明:

质押地址必须是账号地址,不能是合约地址;

质押地址必须有尚未提取的ERC20收益;

必须距离上次提取时间超过一天(86400秒,该值可以在部署时修改);

通过_precentUp和_precentDown可以设置提取比例,本文示例为100%;

记录本次提取时间并完成资产转账;

注意:必须提前给合约地址转账足够的ERC20资产,否则用户无法成功提取收益;

1.5 本金提取函数takeToken

function takeToken(uint256 amount) public {

require(address(msg.sender) == address(tx.origin), "no contract");

PledgeOrder storage order=_orders[msg.sender];

require(order.token>0,"no order");

require(amount<=order.token,"less token");

_totalPledegAmount=_totalPledegAmount.sub(amount);

if(order.token==amount){

order.token=0;

keys[order.index].isExist=false;

}else{

order.token=order.token.sub(amount);

}

address payable addr = getPayable(msg.sender);

addr.transfer(amount);

}

功能说明:

质押地址必须是账号地址,不能是合约地址;

质押地址必须有尚未提取的本金;

用户可以随时提取本金;

用户可以确定提取本金的额度(少于或等于本人的质押金额度);

完成资产转账

1.6 其它功能函数

//获取用户质押本金余额

function getPledgeToken(address tokenAddress) public view returns(uint256) {}

//获取用户收益余额

function getProfitToken(address tokenAddress) public view returns(uint256) {}

//获取当前质押总额

function getTotalPledge() public view returns(uint256) {}

//地址转换,允许地址接收资产

function getPayable(address tokenAddress) private pure returns (address payable) {}

//设置项目开始状态

function changeIsDIS(bool flag) public onlyOwner {}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档