质押挖矿合约

本文合约部署步骤:https://blog.csdn.net/wonderBlock/article/details/109903310

本文环境:以太坊POA联盟链 + chrome浏览器 + metamask + remix

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

 

1.质押挖矿合约源码

1.1 SafeMath.sol


   
  1. pragma solidity 0.5 .8;
  2. library SafeMath {
  3. function add(uint256 a, uint256 b) internal pure returns (uint256) {
  4. uint256 c = a + b;
  5. require(c >= a, "SafeMath: addition overflow");
  6. return c;
  7. }
  8. function sub(uint256 a, uint256 b) internal pure returns (uint256) {
  9. return sub(a, b, "SafeMath: subtraction overflow");
  10. }
  11. function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
  12. require(b <= a, errorMessage);
  13. uint256 c = a - b;
  14. return c;
  15. }
  16. function mul(uint256 a, uint256 b) internal pure returns (uint256) {
  17. if (a == 0) {
  18. return 0;
  19. }
  20. uint256 c = a * b;
  21. require(c / a == b, "SafeMath: multiplication overflow");
  22. return c;
  23. }
  24. function div(uint256 a, uint256 b) internal pure returns (uint256) {
  25. return div(a, b, "SafeMath: division by zero");
  26. }
  27. function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
  28. require(b > 0, errorMessage);
  29. uint256 c = a / b;
  30. return c;
  31. }
  32. function mod(uint256 a, uint256 b) internal pure returns (uint256) {
  33. return mod(a, b, "SafeMath: modulo by zero");
  34. }
  35. function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
  36. require(b != 0, errorMessage);
  37. return a % b;
  38. }
  39. }

它提供了数学函数来保护您的合约不受溢出和下溢的影响,以达到更安全的计算目的;使用该库可以消除没有检测的计算类错误;因此建议始终使用它;

1.2 Address.sol


   
  1. pragma solidity 0.5 .8;
  2. library Address {
  3. function isContract(address account) internal view returns (bool) {
  4. bytes32 codehash;
  5. // 空字符串hash值
  6. bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
  7. //内联编译(inline assembly)语言,是用一种非常底层的方式来访问EVM
  8. assembly { codehash := extcodehash(account) }
  9. return (codehash != accountHash && codehash != 0x0);
  10. }
  11. function sendValue(address payable recipient, uint256 amount) internal {
  12. require(address(this).balance >= amount, "Address: insufficient balance");
  13. ( bool success, ) = recipient.call.value(amount)( "");
  14. require(success, "Address: unable to send value, recipient may have reverted");
  15. }
  16. }

与地址类型相关的函数集合;

功能主要包括判断地址类型(合约地址 or 账号地址),限定地址调用合约功能(比如限定余额充足)等;

1.3 SafeERC20.sol


   
  1. pragma solidity 0.5 .8;
  2. import "./Address.sol";
  3. import "./SafeMath.sol";
  4. library SafeERC20 {
  5. using SafeMath for uint256;
  6. using Address for address;
  7. function safeTransfer(ERC20 token, address to, uint256 value) internal {
  8. callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
  9. }
  10. function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal {
  11. callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
  12. }
  13. function safeApprove(ERC20 token, address spender, uint256 value) internal {
  14. require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance");
  15. callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
  16. }
  17. function safeIncreaseAllowance(ERC20 token, address spender, uint256 value) internal {
  18. uint256 newAllowance = token.allowance(address(this), spender).add(value);
  19. callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
  20. }
  21. function safeDecreaseAllowance(ERC20 token, address spender, uint256 value) internal {
  22. uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
  23. callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
  24. }
  25. function callOptionalReturn(ERC20 token, bytes memory data) private {
  26. require(address(token).isContract(), "SafeERC20: call to non-contract");
  27. ( bool success, bytes memory returndata) = address(token).call(data);
  28. require(success, "SafeERC20: low-level call failed");
  29. if (returndata.length > 0) {
  30. require(abi.decode(returndata, ( bool)), "SafeERC20: ERC20 operation did not succeed");
  31. }
  32. }
  33. }
  34. interface ERC20 {
  35. function totalSupply() external view returns (uint256);
  36. function balanceOf(address account) external view returns (uint256);
  37. function transfer(address recipient, uint256 amount) external returns (bool);
  38. function allowance(address owner, address spender) external view returns (uint256);
  39. function approve(address spender, uint256 amount) external returns (bool);
  40. function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
  41. event Transfer(address indexed from, address indexed to, uint256 value);
  42. event Approval(address indexed owner, address indexed spender, uint256 value);
  43. }

标准ERC20接口,本文中的质押收益使用ERC20支付,也可以认为是质押挖矿的标的;

1.4 ProfitToken.sol


   
  1. pragma solidity ^ 0.4 .25;
  2. library SafeMath {
  3. /**
  4. * @dev Multiplies two numbers, reverts on overflow.
  5. */
  6. function mul(uint256 a, uint256 b) internal pure returns (uint256) {
  7. if (a == 0) {
  8. return 0;
  9. }
  10. uint256 c = a * b;
  11. require(c / a == b);
  12. return c;
  13. }
  14. /**
  15. * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
  16. */
  17. function div(uint256 a, uint256 b) internal pure returns (uint256) {
  18. require(b > 0); // Solidity only automatically asserts when dividing by 0
  19. uint256 c = a / b;
  20. return c;
  21. }
  22. /**
  23. * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
  24. */
  25. function sub(uint256 a, uint256 b) internal pure returns (uint256) {
  26. require(b <= a);
  27. uint256 c = a - b;
  28. return c;
  29. }
  30. /**
  31. * @dev Adds two numbers, reverts on overflow.
  32. */
  33. function add(uint256 a, uint256 b) internal pure returns (uint256) {
  34. uint256 c = a + b;
  35. require(c >= a);
  36. return c;
  37. }
  38. /**
  39. * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
  40. * reverts when dividing by zero.
  41. */
  42. function mod(uint256 a, uint256 b) internal pure returns (uint256) {
  43. require(b != 0);
  44. return a % b;
  45. }
  46. }
  47. interface IERC20 {
  48. function totalSupply() external view returns (uint256);
  49. function balanceOf(address who) external view returns (uint256);
  50. function allowance(address owner, address spender) external view returns (uint256);
  51. function transfer(address to, uint256 value) external returns (bool);
  52. function approve(address spender, uint256 value) external returns (bool);
  53. function transferFrom(address from, address to, uint256 value) external returns (bool);
  54. event Transfer(address indexed from,address indexed to,uint256 value);
  55. event Approval(address indexed owner,address indexed spender,uint256 value);
  56. }
  57. contract ERC20 is IERC20 {
  58. using SafeMath for uint256;
  59. mapping (address => uint256) public _balances;
  60. mapping (address => mapping (address => uint256)) private _allowed;
  61. uint256 public _totalSupply;
  62. /**
  63. * @dev Total number of tokens in existence
  64. */
  65. function totalSupply() public view returns (uint256) {
  66. return _totalSupply;
  67. }
  68. function balanceOf(address owner) public view returns (uint256) {
  69. return _balances[owner];
  70. }
  71. function allowance(address owner,address spender) public view returns (uint256) {
  72. return _allowed[owner][spender];
  73. }
  74. function transfer(address to, uint256 value) public returns (bool) {
  75. _transfer(msg.sender, to, value);
  76. return true;
  77. }
  78. function approve(address spender, uint256 value) public returns (bool) {
  79. require(spender != address( 0));
  80. _allowed[msg.sender][spender] = value;
  81. emit Approval(msg.sender, spender, value);
  82. return true;
  83. }
  84. function transferFrom(address from,address to,uint256 value) public returns (bool) {
  85. require(value <= _allowed[ from][msg.sender]);
  86. _allowed[ from][msg.sender] = _allowed[ from][msg.sender].sub(value);
  87. _transfer( from, to, value);
  88. return true;
  89. }
  90. function increaseAllowance(address spender,uint256 addedValue) public returns (bool) {
  91. require(spender != address( 0));
  92. _allowed[msg.sender][spender] = (_allowed[msg.sender][spender].add(addedValue));
  93. emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
  94. return true;
  95. }
  96. function decreaseAllowance(address spender,uint256 subtractedValue) public returns (bool) {
  97. require(spender != address( 0));
  98. _allowed[msg.sender][spender] = (_allowed[msg.sender][spender].sub(subtractedValue));
  99. emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
  100. return true;
  101. }
  102. function _transfer(address from, address to, uint256 value) internal {
  103. require(to != address( 0));
  104. require(value <= _balances[ from]);
  105. _balances[ from] = _balances[ from].sub(value);
  106. _balances[to] = _balances[to].add(value);
  107. emit Transfer( from, to, value);
  108. }
  109. }
  110. contract ProfitToken is ERC20 {
  111. string private _name;
  112. string private _symbol;
  113. uint8 private _decimals;
  114. constructor (uint256 _initialAmount, string name, uint8 decimals, string symbol) public {
  115. _name = name;
  116. _symbol = symbol;
  117. _decimals = decimals;
  118. _totalSupply = _initialAmount.mul( 10 ** uint256(_decimals));
  119. _balances[msg.sender] = _initialAmount.mul( 10 ** uint256(_decimals));
  120. }
  121. /**
  122. * @return the name of the token.
  123. */
  124. function name() public view returns (string) {
  125. return _name;
  126. }
  127. /**
  128. * @return the symbol of the token.
  129. */
  130. function symbol() public view returns (string) {
  131. return _symbol;
  132. }
  133. /**
  134. * @return the number of decimals of the token.
  135. */
  136. function decimals() public view returns (uint8) {
  137. return _decimals;
  138. }
  139. }

独立实现的、符合ERC20标准的资产合约,用于分发质押收益,用户也可以使用任何符合ERC20标准的资产合约(参考第21、22篇文档);

1.5 GinPledge.sol


   
  1. pragma solidity 0.5 .8;
  2. import "./SafeMath.sol";
  3. import "./SafeERC20.sol";
  4. contract GinPledge {
  5. using SafeMath for uint256;
  6. using SafeERC20 for ERC20;
  7. address private owner;
  8. address private profitor;
  9. bool _isDIS = false;
  10. mapping(address => PledgeOrder) _orders;
  11. mapping(address => uint256) _takeProfitTime;
  12. ERC20 _Token;
  13. KeyFlag[] keys;
  14. uint256 size;
  15. uint256 _maxPledgeAmount;
  16. uint256 _maxMiningAmount;
  17. uint256 _leftMiningAmount;
  18. uint256 _minAmount;
  19. uint256 _totalPledegAmount;
  20. uint256 _maxPreMiningAmount;
  21. uint256 _startTime;
  22. uint256 _endTime;
  23. uint256 _precentUp= 100;
  24. uint256 _precentDown= 100;
  25. struct PledgeOrder {
  26. bool isExist;
  27. uint256 token;
  28. uint256 profitToken;
  29. uint256 time;
  30. uint256 index;
  31. }
  32. struct KeyFlag {
  33. address key;
  34. bool isExist;
  35. }
  36. constructor (
  37. address tokenAddress,
  38. address paramProfitor,
  39. uint256 maxPledgeAmount,
  40. uint256 minAmount,
  41. uint256 maxMiningAmount,
  42. uint256 maxPreMiningAmount,
  43. uint256 startTime,
  44. uint256 endTime
  45. )
  46. public
  47. {
  48. _Token = ERC20(tokenAddress);
  49. owner = msg.sender;
  50. profitor = paramProfitor;
  51. _maxPledgeAmount = maxPledgeAmount;
  52. _minAmount = minAmount;
  53. _maxMiningAmount = maxMiningAmount;
  54. _maxPreMiningAmount = maxPreMiningAmount;
  55. _startTime = startTime;
  56. _endTime = endTime;
  57. _leftMiningAmount = maxMiningAmount;
  58. }
  59. function pledgeToken() public payable{
  60. require(address(msg.sender) == address(tx.origin), "no contract");
  61. require(_isDIS, "is disable");
  62. require(_leftMiningAmount> 0, "less token");
  63. require(msg.value>=_minAmount, "less token");
  64. require(_totalPledegAmount.add(msg.value)<=_maxPledgeAmount, "more token");
  65. require(block.timestamp>=_startTime&&block.timestamp<=_endTime, "is disable");
  66. if(_orders[msg.sender].isExist== false){
  67. keys.push(KeyFlag(msg.sender, true));
  68. size++;
  69. createOrder(msg.value,keys.length.sub( 1));
  70. } else{
  71. PledgeOrder storage order=_orders[msg.sender];
  72. order.token=order.token.add(msg.value);
  73. keys[order.index].isExist= true;
  74. }
  75. _totalPledegAmount=_totalPledegAmount.add(msg.value);
  76. }
  77. function createOrder(uint256 trcAmount,uint256 index) private {
  78. _orders[msg.sender]=PledgeOrder(
  79. true,
  80. trcAmount,
  81. 0,
  82. block.timestamp,
  83. index
  84. );
  85. }
  86. function profit() public onlyProfitor{
  87. require(_leftMiningAmount> 0, "less token");
  88. require(_totalPledegAmount> 0, "no pledge");
  89. uint256 preToken=_maxPreMiningAmount;
  90. if(_leftMiningAmount<_maxPreMiningAmount){
  91. preToken=_leftMiningAmount;
  92. }
  93. for(uint i = 0; i < keys.length; i++) {
  94. if(keys[i].isExist== true){
  95. PledgeOrder storage order=_orders[keys[i].key];
  96. order.profitToken=order.profitToken.add(order.token.mul(preToken).div(_totalPledegAmount));
  97. }
  98. }
  99. _leftMiningAmount=_leftMiningAmount.sub(preToken);
  100. }
  101. function takeProfit() public {
  102. require(address(msg.sender) == address(tx.origin), "no contract");
  103. require(_orders[msg.sender].profitToken> 0, "less token");
  104. uint256 time=block.timestamp;
  105. uint256 diff=time.sub(_takeProfitTime[msg.sender]);
  106. require(diff> 86400, "less time");
  107. PledgeOrder storage order=_orders[msg.sender];
  108. uint256 takeToken=order.profitToken.mul(_precentUp).div(_precentDown);
  109. order.profitToken=order.profitToken.sub(takeToken);
  110. _takeProfitTime[msg.sender]=time;
  111. _Token.safeTransfer(address(msg.sender),takeToken);
  112. }
  113. function takeToken(uint256 amount) public {
  114. require(address(msg.sender) == address(tx.origin), "no contract");
  115. PledgeOrder storage order=_orders[msg.sender];
  116. require(order.token> 0, "no order");
  117. require(amount<=order.token, "less token");
  118. _totalPledegAmount=_totalPledegAmount.sub(amount);
  119. if(order.token==amount){
  120. order.token= 0;
  121. keys[order.index].isExist= false;
  122. } else{
  123. order.token=order.token.sub(amount);
  124. }
  125. address payable addr = getPayable(msg.sender);
  126. addr.transfer(amount);
  127. }
  128. function takeAllToken() public {
  129. require(address(msg.sender) == address(tx.origin), "no contract");
  130. PledgeOrder storage order=_orders[msg.sender];
  131. require(order.token> 0, "no order");
  132. keys[order.index].isExist= false;
  133. uint256 takeAmount=order.token;
  134. order.token= 0;
  135. _totalPledegAmount=_totalPledegAmount.sub(takeAmount);
  136. uint256 time=block.timestamp;
  137. uint256 diff=time.sub(_takeProfitTime[msg.sender]);
  138. if(diff>= 86400){
  139. uint256 profitPart=order.profitToken.mul(_precentUp).div(_precentDown);
  140. keys[order.index].isExist = false;
  141. order.profitToken=order.profitToken.sub(profitPart);
  142. _takeProfitTime[msg.sender]=time;
  143. _Token.safeTransfer(address(msg.sender),profitPart);
  144. }
  145. address payable addr = getPayable(msg.sender);
  146. addr.transfer(takeAmount);
  147. }
  148. function getPledgeToken(address tokenAddress) public view returns(uint256) {
  149. require(address(msg.sender) == address(tx.origin), "no contract");
  150. PledgeOrder memory order=_orders[tokenAddress];
  151. return order.token;
  152. }
  153. function getProfitToken(address tokenAddress) public view returns(uint256) {
  154. require(address(msg.sender) == address(tx.origin), "no contract");
  155. PledgeOrder memory order=_orders[tokenAddress];
  156. return order.profitToken;
  157. }
  158. function getTotalPledge() public view returns(uint256) {
  159. require(address(msg.sender) == address(tx.origin), "no contract");
  160. return _totalPledegAmount;
  161. }
  162. function getPayable(address tokenAddress) private pure returns (address payable) {
  163. return address(uint168(tokenAddress));
  164. }
  165. function getTakeProfitTime(address tokenAddress) public view returns(uint256) {
  166. return _takeProfitTime[tokenAddress];
  167. }
  168. function changeIsDIS(bool flag) public onlyOwner {
  169. _isDIS= flag;
  170. }
  171. function changeOwner(address paramOwner) public onlyOwner {
  172. require(paramOwner != address( 0));
  173. owner= paramOwner;
  174. }
  175. function changeProfitor(address paramProfitor) public onlyOwner {
  176. profitor= paramProfitor;
  177. }
  178. modifier onlyOwner(){
  179. require(msg.sender == owner);
  180. _;
  181. }
  182. modifier onlyProfitor(){
  183. require(msg.sender == profitor);
  184. _;
  185. }
  186. function getOwner() public view returns (address) {
  187. return owner;
  188. }
  189. function getProfitor() public view returns (address) {
  190. return profitor;
  191. }
  192. function getsize() public view returns (uint256) {
  193. return size;
  194. }
  195. function maxPledgeAmount() public view returns (uint256) {
  196. return _maxPledgeAmount;
  197. }
  198. function maxMiningAmount() public view returns (uint256) {
  199. return _maxMiningAmount;
  200. }
  201. function leftMiningAmount() public view returns (uint256) {
  202. return _leftMiningAmount;
  203. }
  204. function minAmount() public view returns (uint256) {
  205. return _minAmount;
  206. }
  207. function maxPreMiningAmount() public view returns (uint256) {
  208. return _maxPreMiningAmount;
  209. }
  210. function startTime() public view returns (uint256) {
  211. return _startTime;
  212. }
  213. function endTime() public view returns (uint256) {
  214. return _endTime;
  215. }
  216. function nowTime() public view returns (uint256) {
  217. return block.timestamp;
  218. }
  219. function isDIS() public view returns (bool) {
  220. return _isDIS;
  221. }
  222. }

质押挖矿合约;

 

2.合约主要功能函数介绍

本节介绍质押挖矿合约 GinPledge.sol 的主要功能:

2.1 主要参数


   
  1. address private owner; //合约部署(拥有者)账号地址
  2. address private profitor; //收益分配者账号地址,仅该地址有权分配收益
  3. bool _isDIS = false; //质押合约功能状态,true才可以进行质押
  4. ERC20 _Token; //用于分配收益的ERC20资产
  5. KeyFlag[] keys; //用于标记用户地址的质押状态
  6. uint256 size; //质押者地址(用户)数量
  7. uint256 _maxPledgeAmount; //最大质押(底层币)额度
  8. uint256 _maxMiningAmount; //最大挖矿(ERC20收益分配)额度
  9. uint256 _leftMiningAmount; //剩余挖矿额度
  10. uint256 _minAmount; //单次最少质押额度
  11. uint256 _totalPledegAmount; //已质押总额度
  12. uint256 _maxPreMiningAmount; //最大单次分配额度
  13. uint256 _startTime; //开始时间,单位“秒”
  14. uint256 _endTime; //结束时间,单位“秒”
  15. uint256 _precentUp= 100; //与_precentDown一起设定每次收益提取比例
  16. uint256 _precentDown= 100; //与_precentUp一起设定每次收益提取比例
  17. struct PledgeOrder { //结构体,用于标记质押用户的各类状态
  18. bool isExist; //质押状态
  19. uint256 token; //质押额度
  20. uint256 profitToken; //收益额度
  21. uint256 time; //最近一次提取收益时间
  22. uint256 index; //质押地址序号
  23. }
  24. struct KeyFlag { //结构体,用于标记用户地址的质押状态
  25. address key; //地址
  26. bool isExist; //质押状态
  27. }

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

2.1 质押函数pledgeToken


   
  1. function pledgeToken() public payable{
  2. require(address(msg.sender) == address(tx.origin), "no contract");
  3. require(_isDIS, "is disable");
  4. require(_leftMiningAmount> 0, "less token");
  5. require(msg.value>=_minAmount, "less token");
  6. require(_totalPledegAmount.add(msg.value)<=_maxPledgeAmount, "more token");
  7. require(block.timestamp>=_startTime&&block.timestamp<=_endTime, "is disable");
  8. if(_orders[msg.sender].isExist== false){
  9. keys.push(KeyFlag(msg.sender, true));
  10. size++;
  11. createOrder(msg.value,keys.length. sub( 1));
  12. } else{
  13. PledgeOrder storage order=_orders[msg.sender];
  14. order.token=order.token.add(msg.value);
  15. keys[order.index].isExist= true;
  16. }
  17. _totalPledegAmount=_totalPledegAmount.add(msg.value);
  18. }

功能说明:

  1. 明显的,该函数具有接收底层币功能(payable);
  2. 质押地址必须是账号地址,不能是合约地址;
  3. 需要合约质押功能已经开始,且在活动限定时间内;
  4. 剩余挖矿额度大于0;
  5. 进行质押的底层币额度不能少于最小值,质押后也不能超过限定的最大质押额度;
  6. 如果该用户之前没有质押过,则建立档案(createOrder),否则仅修改档案;

1.3 收益分配函数profit


   
  1. function profit() public onlyProfitor{
  2.         require(_leftMiningAmount> 0, "less token");
  3.         require(_totalPledegAmount> 0, "no pledge");
  4.         uint256 preToken=_maxPreMiningAmount;
  5.         if(_leftMiningAmount<_maxPreMiningAmount){
  6.             preToken=_leftMiningAmount;
  7.         }
  8.         for(uint i = 0; i < keys.length; i++) {
  9.             if(keys[i].isExist== true){
  10.                 PledgeOrder storage order=_orders[keys[i].key];
  11.                 order.profitToken=order.profitToken.add(order.token.mul(preToken).div(_totalPledegAmount));
  12.             }
  13.         }
  14.         _leftMiningAmount=_leftMiningAmount. sub(preToken);
  15.     }

功能说明:

  1. 必须尚有剩余挖矿额度可供分配;
  2. 当前质押总额必须大于0;
  3. 如果剩余挖矿额度足够,则按规则分配设定的每次最大分配额度(_maxPreMiningAmount);
  4. 如果剩余挖矿额度小于每次最大分配额度,则将剩余额度全部进行分配;
  5. 根据用户质押数量,平均分配所有额度;即质押余额越多,收益越多;

1.4收益提取函数takeProfit


   
  1. function takeProfit() public {
  2. require(address(msg.sender) == address(tx.origin), "no contract");
  3. require(_orders[msg.sender].profitToken> 0, "less token");
  4. uint256 time=block.timestamp;
  5. uint256 diff= time. sub(_takeProfitTime[msg.sender]);
  6. require(diff> 86400, "less time");
  7. PledgeOrder storage order=_orders[msg.sender];
  8. uint256 takeToken=order.profitToken.mul(_precentUp).div(_precentDown);
  9. order.profitToken=order.profitToken. sub(takeToken);
  10. _takeProfitTime[msg.sender]= time;
  11. _Token.safeTransfer(address(msg.sender),takeToken);
  12. }

功能说明:

  1. 质押地址必须是账号地址,不能是合约地址;
  2. 质押地址必须有尚未提取的ERC20收益;
  3. 必须距离上次提取时间超过一天(86400秒,该值可以在部署时修改);
  4. 通过_precentUp_precentDown可以设置提取比例,本文示例为100%;
  5. 记录本次提取时间并完成资产转账;
  6. 注意:必须提前给合约地址转账足够的ERC20资产,否则用户无法成功提取收益;

1.5 本金提取函数takeToken


   
  1. function takeToken(uint256 amount) public {
  2. require(address(msg.sender) == address(tx.origin), "no contract");
  3. PledgeOrder storage order=_orders[msg.sender];
  4. require(order.token> 0, "no order");
  5. require(amount<=order.token, "less token");
  6. _totalPledegAmount=_totalPledegAmount.sub(amount);
  7. if(order.token==amount){
  8. order.token= 0;
  9. keys[order.index].isExist= false;
  10. } else{
  11. order.token=order.token.sub(amount);
  12. }
  13. address payable addr = getPayable(msg.sender);
  14. addr.transfer(amount);
  15. }

功能说明:

  1. 质押地址必须是账号地址,不能是合约地址;
  2. 质押地址必须有尚未提取的本金;
  3. 用户可以随时提取本金;
  4. 用户可以确定提取本金的额度(少于或等于本人的质押金额度);
  5. 完成资产转账;

1.6 其它功能函数


   
  1. //获取用户质押本金余额
  2. function getPledgeToken(address tokenAddress) public view returns(uint256) {}
  3. //获取用户收益余额
  4. function getProfitToken(address tokenAddress) public view returns(uint256) {}
  5. //获取当前质押总额
  6. function getTotalPledge() public view returns(uint256) {}
  7. //地址转换,允许地址接收资产
  8. function getPayable(address tokenAddress) private pure returns (address payable) {}
  9. //设置项目开始状态
  10. function changeIsDIS(bool flag) public onlyOwner {}