先简述一下问题: 1:部署的时候是用小狐狸部署的然后部署在ETH链下,现在账号里面测试ETH币还有不少,但是在调用ownerTransfer转账的时候执行 to.transfer(withdrawAmount/10000);这一行就会出问题,去掉这一行就没问题,那位大佬帮忙看看原因
2:userTransfer函数中如何给用户自己给自己提币 ownerTransfer 函数中合约拥有者如何给矿工转账,用来结算奖励
3:现阶段是部署在ETH下,但是后续会部署在其他ERC20的链上(自己发的链和币),给矿工结算奖励的时候应该如何结算,现有合约代码需要做什么改变
4:因为头一次写挖矿合约,所以未引入其他的合约,是否需要引入一些其他合约用来保证安全性
改挖矿合约和现有市面上的流动性质押挖矿有区别,只是单纯的通过挖矿速度计算矿工奖励,然后通过合约拥有者给矿工结算奖励 其中如果有什么问题,望各位大佬能指点一下
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MiningContract {
//合约拥有者
address private owner;
//合约解锁时间
uint256 private lockoutTime;
// 挖矿速度,每秒钟一个币
uint256 constant miningSpeed = 1;
//用户信息体
struct UserInfo {
uint256 totalCumulative;//恒定总累积量
uint256 totalReward; //累积奖励
uint256 userSpeed; //速度
uint256 startTime; //当前速度的挖矿开始时间
}
//用户信息体 = 地址 对应 用户信息体
mapping(address => UserInfo) private userInfo;
address[] private addressList;
//构造方法,部署的时候给合约拥有者赋值
constructor() payable {
owner = msg.sender;
}
event userLog(uint256 blockTime ,uint256 lockoutTime ,UserInfo userInfo);
event lockoutLog(string message, address[] addressList, uint256 timeDiff, uint256 lastReward);
event ownerTransferLog(address formAddress,uint256 withdrawAmount);
//挖矿函数
function strat(address user, uint256 speed) external {
require(msg.sender == owner, "Only owner can call this function");
require(lockoutTime == 0 ,"locked warehouse");//判断是否锁仓,未锁仓,才能挖矿
UserInfo storage info = userInfo[user];
addressList.push(user);//定义一个addressList用来存储用户信息地址,以便在后续中锁仓时使用
if (info.startTime == 0) {
info.startTime = block.timestamp;
}else{
uint256 timeDiff = block.timestamp - info.startTime;
if(timeDiff > 24*60*60){
uint256 lastReward = info.userSpeed * 24*60*60 * getRatio();
info.totalReward += lastReward;
info.startTime = block.timestamp;
}else{
uint256 lastReward = info.userSpeed * timeDiff * getRatio();
info.totalReward += lastReward;
info.startTime = block.timestamp;
}
}
info.userSpeed = speed;
emit userLog(block.timestamp , lockoutTime , info);
}
//锁仓函数
function lockout() external {
require(msg.sender == owner, "Only owner can call this function");
lockoutTime = block.timestamp;
for (uint256 i = 0; i < addressList.length; i++) {
address userAddress = addressList[i];
UserInfo storage info = userInfo[userAddress]; //声明一个UserInfo类型的变量info,将userInfo[users[i]]赋值给它
uint256 lastReward = 0; //声明一个uint256类型的变量lastReward,初始值为0
if (info.userSpeed != 0) { //如果info.userSpeed不等于0
uint256 timeDiff = lockoutTime - info.startTime; //计算时间差
if (timeDiff >= 24*60*60) { //如果时间差大于等于1天
lastReward = info.userSpeed * 24*60*60 * getRatio(); //计算上一次奖励的数量
} else {
lastReward = info.userSpeed * timeDiff * getRatio(); //计算上一次奖励的数量
}
emit lockoutLog("lockout Log Value is", addressList, timeDiff, lastReward);
}
info.totalCumulative = info.totalReward + lastReward; //将总累计奖励赋值给info.totalCumulative
}
// totalCumulative = getTotalCumulative(); //将所有用户的总累计奖励赋值给totalCumulative
}
//声明一个函数userTransfer
function userTransfer() external payable {
require(lockoutTime > 0 ,"Unlocked warehouse");//判断是否锁仓,已锁仓,才能提币
UserInfo storage info = userInfo[msg.sender]; //声明一个UserInfo类型的变量info,将userInfo[msg.sender]赋值给它
uint256 percentage = withdraw();
uint256 withdrawAmount = info.totalCumulative * percentage/100 - (info.totalCumulative - info.totalReward); // 提币额度,其中totalReward为累计奖励数
require(msg.value <= withdrawAmount, "Insufficient mining fee");//这一步判定暂定,看看有无必要加上
info.totalReward -= withdrawAmount;//将转账金额从info.totalCumulative中减去
payable(msg.sender).transfer(withdrawAmount);//将转账金额转账给to地址
}
//声明一个函数ownerTransfer,只有owner才能调用
function ownerTransfer(address payable to) external payable{
require(msg.sender == owner, "Only owner can call this function");//要求只有owner才能调用该函数
// require(lockoutTime > 0 ,"Unlocked warehouse");//判断是否锁仓,已锁仓,才能提币
UserInfo storage info = userInfo[to];
uint256 percentage = withdraw();
uint256 withdrawAmount = info.totalCumulative * percentage/100 - (info.totalCumulative - info.totalReward); // 提币额度,其中totalReward为累计奖励数
require(msg.value <= withdrawAmount, "Insufficient mining fee");//要求支付的以太币数量大于等于转账金额
info.totalReward -= withdrawAmount;//将转账金额从totalCumulative中减去
to.transfer(withdrawAmount/10000);
emit ownerTransferLog(to, withdrawAmount);
}
//锁仓后提币时,计算截止到今天的可提币比例
function withdraw() internal view returns (uint256) {
uint256 daysPassed = (block.timestamp - lockoutTime) / 86400; // 计算当前是第几天,86400为一天的秒数
uint256 withdrawPercentage = 0;
if (daysPassed == 0) {
withdrawPercentage = 5; // 第一天提币比例为5%
} else {
withdrawPercentage = 3; // 第二天及以后提币比例为3%
for (uint i = 1; i < daysPassed; i++) {
withdrawPercentage += 3; // 每过一天提币比例增加3%
}
}
return withdrawPercentage; // 当前可提币比例
}
//声明一个函数amount,获取用户的累计奖励
function userAmount(address user) external view returns (uint256) {
UserInfo storage info = userInfo[user];//声明一个UserInfo类型的变量info,将userInfo[user]赋值给它
uint256 userLastReward = 0;//声明一个uint256类型的变量lastReward,初始值为0,用来获取用户在当前速度下的累计奖励量
uint256 timeDiff = block.timestamp - info.startTime;
if(timeDiff > 24*60*60){
userLastReward = info.userSpeed * 24*60*60 * getRatio();
}else{
userLastReward = info.userSpeed * timeDiff * getRatio();
}
return info.totalReward + userLastReward;//返回总累计奖励加上上一次奖励的数量
}
//声明一个私有函数getRatio,获取基础挖矿速度的奖励
function getRatio() private pure returns (uint256) {
return miningSpeed;
}
//声明一个函数speed,获取当前用户的挖矿速度
function userSpeed(address user) external view returns (uint256) {
return userInfo[user].userSpeed;//返回用户的速度
}
//声明一个函数residueTime,获取当前用户的剩余挖矿时间
function residueTime(address user) external view returns (uint256) {
uint256 timeDiff = block.timestamp - userInfo[user].startTime;
if (timeDiff >= 24*60*60) { //如果时间差大于等于1天
return 0;
} else {
return 24*60*60 - timeDiff; //返回剩余时间
}
}
//声明一个函数residueTime,获取当前用户的剩余挖矿时间
function getBlockTime() external view returns (uint256) {
return block.timestamp;
}
}
to.transfer(withdrawAmount/10000);
出问题,一般有这两个可能性:
to
是一个合约, transfer 只是用2300 gas, 不够执行合约的Receive 函数 。 部署在其他EVM 链上(没有 ERC20的链 这个说法) 通常不需要修改代码, 如果有第三方合约地址依赖的话,修改一下地址就可以。
要不要引入其他的合约, 这个要看你的逻辑,不是必须的。