文件 1 的 1:ArcStakeContract.sol
pragma solidity 0.8.19;
interface IERC20 {
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
interface IARC{
function getLine(address _us) external view returns(address[] memory);
}
interface Itransfer{
function transferToken(address token, address sender, address to, uint256 amount) external;
}
interface IOldStake{
struct UserInfo{
uint256 stakeArc;
uint256 canClaimArc;
uint256 lastTime;
uint256 lastStakeTime;
uint256 teamUser;
uint256 teamValue;
uint256 inviteRwd;
uint256 teamRwd;
uint256 teamLevel;
bool isAddTeamUser;
}
function userId(address _user)external view returns(uint256);
function idToUser(uint256 _userId)external view returns(address);
function getUserInfos(address _user) external view returns(UserInfo memory,uint256,uint256,uint256,uint256,uint256);
}
contract ArcStakeContract{
address private arc = 0xbdCA2E08bC10Dc500D82736D2Da423CaC4E98aF8;
address private transferContract = 0x394A8273A52d2D8EA25034e3A21281FCd517A882;
address private poolContract =0x1f0893158D9B54b6FC6575E1effd93E40C75c234;
address private bankContract = 0xfF35ee67D2272dd4A57E5C8a09020F2bB93Dd09F;
address private funder = 0xa5b07C950E5c9BEa7E7Dc10EEe93b2367883be8e;
address private oldStakeContract=0xE20e192dE583fB135bE82898Fa5180a850A78567;
mapping(address=>bool) public projectManage;
uint256 minStakeAmount = 2910 ether;
uint256 maxStakeAmount = 300000 ether;
uint256 coldTime = 1 days;
uint256 dayRewardRate = 7;
uint256 dayRewardPoint = 1000;
uint256 teamCd;
uint256 inviteCd;
bool stakeState;
bool claimState;
bool unstakeState;
uint256 stakeFee = 3;
uint256 totalFeePomt=100;
uint256[] feeTimes=[90 days,30 days,0];
uint256[] feeRate=[0,5,10];
uint256 public uid;
mapping(address=>uint256) public userId;
mapping(uint256=>address) public idToUser;
uint256 totalStakeAmt;
uint256 totalUnstakeAmt;
uint256 totalClaimAmt;
uint256 public totalClaimInviteCd;
uint256 public totalClaimTeamCd;
struct UserInfo{
uint256 stakeArc;
uint256 canClaimArc;
uint256 lastTime;
uint256 lastStakeTime;
uint256 teamUser;
uint256 teamValue;
uint256 inviteRwd;
uint256 teamRwd;
uint256 teamLevel;
bool isAddTeamUser;
}
mapping(address=>UserInfo) private userInfo;
constructor(){
projectManage[msg.sender] = true;
}
function setProjectManage(address _addr,bool _state) external {
require(_addr != msg.sender,'SAME');
require(projectManage[msg.sender],'M');
projectManage[_addr] = _state;
}
function setAddress(address _arc,address _transferContract,address _pool,address _bank,address _funder) external{
require(projectManage[msg.sender],'M');
arc = _arc;
transferContract=_transferContract;
poolContract=_pool;
bankContract = _bank;
funder=_funder;
}
function setStates(bool _stakeState,bool _claimState,bool _unstakeState) external {
require(projectManage[msg.sender],'M');
stakeState = _stakeState;
claimState = _claimState;
unstakeState = _unstakeState;
}
function setMinMaxStakeAmount(uint256 _minStakeAmount,uint256 _maxStakeAmount) external {
require(projectManage[msg.sender],'M');
minStakeAmount=_minStakeAmount;
maxStakeAmount = _maxStakeAmount;
}
function setFee(uint256 _totalFeePomt,uint256 _stakeFee,uint256[] memory _unstakeFeeTime,uint256[] memory _unstakeFeeRate) external{
require(projectManage[msg.sender],'M');
stakeFee=_stakeFee;
totalFeePomt=_totalFeePomt;
feeTimes = _unstakeFeeTime;
feeRate = _unstakeFeeRate;
}
function _calcUnstakeFee(uint256 _stakeTime) private view returns(uint256){
for(uint256 i=0;i<feeTimes.length;i++){
if(_stakeTime>=feeTimes[i]){
return feeRate[i];
}
}
return feeRate[feeRate.length-1];
}
function setColdTime(uint256 _coldTime)external{
require(projectManage[msg.sender],'M');
coldTime=_coldTime;
}
function setDayRewards(uint256 _rate,uint256 _point)external{
require(projectManage[msg.sender],'M');
require(_rate<_point,'MAX');
dayRewardRate = _rate;
dayRewardPoint = _point;
}
function claimTeamCd()external{
require(msg.sender == funder,'Funder');
require(teamCd>0,'No Rewards');
totalClaimTeamCd+=teamCd;
IERC20(arc).transferFrom(poolContract,funder,teamCd);
teamCd=0;
}
function claimInviteCd()external{
require(msg.sender == funder,'Funder');
require(inviteCd>0,'No Rewards');
totalClaimInviteCd+=inviteCd;
IERC20(arc).transferFrom(poolContract,funder,inviteCd);
inviteCd=0;
}
function _calcPerRewards(uint256 _stakeAmt) private view returns(uint256){
uint256 _perDay = _stakeAmt*dayRewardRate/dayRewardPoint;
uint256 _perSec = _perDay/86400;
return _perSec;
}
function stake(uint256 _arcAmt) external{
require(stakeState,'Wait Open');
address _user = msg.sender;
require(_user == tx.origin,'Bot');
address[] memory _line = IARC(arc).getLine(_user);
require(_line.length>0,'Bind');
uint256 _userId = userId[_user];
if(_userId ==0){
uid++;
userId[_user] = uid;
idToUser[uid] = _user;
}
totalStakeAmt+=_arcAmt;
uint256 _stakeFee = _arcAmt * stakeFee / totalFeePomt;
uint256 _stakeAmount = _arcAmt - _stakeFee;
require(_stakeAmount>=minStakeAmount,'Min');
Itransfer(transferContract).transferToken(arc, _user, bankContract, _stakeFee);
Itransfer(transferContract).transferToken(arc, _user, poolContract, _stakeAmount);
_stake(_user,_line, _stakeAmount);
}
function _stake(address _user,address[] memory _line,uint256 _amt) private{
UserInfo storage uInfo = userInfo[_user];
uint256 _stakeArc = uInfo.stakeArc;
require(maxStakeAmount >= (_stakeArc+_amt),'Max');
if(_stakeArc>0){
uint256 _rwdTime = block.timestamp - uInfo.lastTime;
if(_rwdTime>0){
uint256 _perSecRwd = _calcPerRewards(_stakeArc);
uint256 _checkRwd = _perSecRwd*_rwdTime;
uInfo.canClaimArc += _checkRwd;
}
}
uInfo.stakeArc += _amt;
uInfo.lastTime = block.timestamp;
uInfo.lastStakeTime = block.timestamp;
_sendTeamRwd(_line,_amt);
_addTeam(_line,_amt,uInfo.isAddTeamUser);
if(!uInfo.isAddTeamUser){
uInfo.isAddTeamUser = true;
}
}
function _addTeam(address[] memory _line,uint256 _amt,bool _isAddTeamUser) private{
for(uint256 i=0;i<_line.length;i++){
UserInfo storage lInfo = userInfo[_line[i]];
if(!_isAddTeamUser){
lInfo.teamUser++;
}
lInfo.teamValue +=_amt;
uint256 _levels = _calcLevel(lInfo.teamUser,lInfo.teamValue);
lInfo.teamLevel = _levels;
}
}
function _calcLevel(uint256 _teamUser,uint256 _teamValue) private pure returns(uint256){
if(_teamUser>=10000){
if(_teamValue>=50000000 ether){
return 7;
}
if(_teamValue>=20000000 ether){
return 6;
}
if(_teamValue>=10000000 ether){
return 5;
}
if(_teamValue>=5000000 ether){
return 4;
}
if(_teamValue>=2000000 ether){
return 3;
}
if(_teamValue>=1000000 ether){
return 2;
}
if(_teamValue>=500000 ether){
return 1;
}
return 0;
}
if(_teamUser>=4000){
if(_teamValue>=20000000 ether){
return 6;
}
if(_teamValue>=10000000 ether){
return 5;
}
if(_teamValue>=5000000 ether){
return 4;
}
if(_teamValue>=2000000 ether){
return 3;
}
if(_teamValue>=1000000 ether){
return 2;
}
if(_teamValue>=500000 ether){
return 1;
}
return 0;
}
if(_teamUser>=2000){
if(_teamValue>=10000000 ether){
return 5;
}
if(_teamValue>=5000000 ether){
return 4;
}
if(_teamValue>=2000000 ether){
return 3;
}
if(_teamValue>=1000000 ether){
return 2;
}
if(_teamValue>=500000 ether){
return 1;
}
return 0;
}
if(_teamUser>=1000){
if(_teamValue>=5000000 ether){
return 4;
}
if(_teamValue>=2000000 ether){
return 3;
}
if(_teamValue>=1000000 ether){
return 2;
}
if(_teamValue>=500000 ether){
return 1;
}
return 0;
}
if(_teamUser>=400){
if(_teamValue>=2000000 ether){
return 3;
}
if(_teamValue>=1000000 ether){
return 2;
}
if(_teamValue>=500000 ether){
return 1;
}
return 0;
}
if(_teamUser>=200){
if(_teamValue>=1000000 ether){
return 2;
}
if(_teamValue>=500000 ether){
return 1;
}
return 0;
}
if(_teamUser>=100){
if(_teamValue>=500000 ether){
return 1;
}
return 0;
}
return 0;
}
function _sendTeamRwd(address[] memory _line,uint256 _preSend)private{
uint256 bsAmt = _preSend;
UserInfo storage tInfo = userInfo[_line[0]];
if(tInfo.stakeArc>=minStakeAmount){
uint256 _inviteRwds = bsAmt * 5/100;
tInfo.inviteRwd += _inviteRwds;
}else{
inviteCd += bsAmt * 5/100;
}
uint256 maxTeamFee = 10;
uint256 useTeamFee;
for(uint256 i=0;i<_line.length;i++){
UserInfo storage linfo = userInfo[_line[i]];
uint256 _stakeAmt= linfo.stakeArc;
uint256 _userLevel = linfo.teamLevel;
if(_stakeAmt>=minStakeAmount ){
if(_userLevel == 7 && useTeamFee<10){
linfo.teamRwd += ((bsAmt * (10 - useTeamFee)) / 100);
useTeamFee = 10;
}
if(_userLevel == 6 && useTeamFee<8){
linfo.teamRwd += ((bsAmt * (8 - useTeamFee)) / 100);
useTeamFee = 8;
}
if(_userLevel == 5 && useTeamFee<7){
linfo.teamRwd += ((bsAmt * (7 - useTeamFee)) / 100);
useTeamFee = 7;
}
if(_userLevel == 4 && useTeamFee<6){
linfo.teamRwd += ((bsAmt * (6 - useTeamFee)) / 100);
useTeamFee = 6;
}
if(_userLevel == 3 && useTeamFee<5){
linfo.teamRwd += ((bsAmt * (5 - useTeamFee)) / 100);
useTeamFee = 5;
}
if(_userLevel == 2 && useTeamFee<4){
linfo.teamRwd += ((bsAmt * (4 - useTeamFee)) / 100);
useTeamFee = 4;
}
if(_userLevel == 1 && useTeamFee<3){
linfo.teamRwd += ((bsAmt * (3 - useTeamFee)) / 100);
useTeamFee = 3;
}
}
}
if(maxTeamFee>useTeamFee){
uint256 _funderTeamRwd = bsAmt * (maxTeamFee-useTeamFee) / 100;
teamCd += _funderTeamRwd;
}
}
function claimRewards()external{
require(claimState,'Wait Open');
address _user = msg.sender;
require(_user == tx.origin,'Bot');
_claimRewards(_user);
}
function _claimRewards(address _user) private{
UserInfo storage uInfo = userInfo[_user];
uint256 _rwdTime = block.timestamp - uInfo.lastTime;
uint256 _days = _rwdTime/coldTime;
require(_days>0,'Wait Cold');
uint256 _stakeArc = uInfo.stakeArc;
uint256 _pending;
if(_stakeArc>0 && _rwdTime>0){
uint256 _perSecRwd = _calcPerRewards(_stakeArc);
uint256 _checkRwd = _perSecRwd*_rwdTime;
_pending += _checkRwd;
}
uint256 _preSend = _pending + uInfo.canClaimArc;
totalClaimAmt+=_preSend;
require(_preSend>0,'Wait Rewards');
IERC20(arc).transferFrom(poolContract, _user, _preSend);
uInfo.canClaimArc=0;
uInfo.lastTime = block.timestamp;
}
function claimInviteRewards() external{
require(claimState,'Wait Open');
address _user = msg.sender;
require(_user == tx.origin,'Bot');
UserInfo storage uInfo = userInfo[_user];
uint256 _rwds = uInfo.inviteRwd;
require(_rwds>0,'No Rewards');
totalClaimInviteCd+=_rwds;
IERC20(arc).transferFrom(poolContract,_user,_rwds);
uInfo.inviteRwd =0;
}
function claimTeamRewards() external{
require(claimState,'Wait Open');
address _user = msg.sender;
require(_user == tx.origin,'Bot');
UserInfo storage uInfo = userInfo[_user];
uint256 _rwds = uInfo.teamRwd;
require(_rwds>0,'No Rewards');
totalClaimTeamCd+=_rwds;
IERC20(arc).transferFrom(poolContract,_user,_rwds);
uInfo.teamRwd =0;
}
function unStake(uint256 _amt)external{
require(_amt>0,'Input Error');
require(unstakeState,'Wait Open');
address _user = msg.sender;
require(_user == tx.origin,'Bot');
address[] memory _line = IARC(arc).getLine(_user);
_unStake(_user,_line,_amt);
}
function _unStake(address _user,address[] memory _line,uint256 _amt) private{
UserInfo storage uInfo = userInfo[_user];
uint256 _rwdTime = block.timestamp - uInfo.lastTime;
uint256 _stakeTime = block.timestamp - uInfo.lastStakeTime;
uint256 _days = _stakeTime/86400;
require(_days>0,'Wait Cold');
uint256 _stakeAmt = uInfo.stakeArc;
require(_stakeAmt>0,'No Stake');
require(_stakeAmt >=_amt,'Max');
if(_stakeAmt>0 && _rwdTime>0){
uint256 _perSecRwd = _calcPerRewards(_stakeAmt);
uint256 _checkRwd = _perSecRwd*_rwdTime;
uInfo.canClaimArc += _checkRwd;
}
uint256 _feeRate = _calcUnstakeFee(_stakeTime);
uint256 _feeAmt = _amt * _feeRate / totalFeePomt;
uint256 _sendAmt = _amt - _feeAmt;
totalUnstakeAmt+=_sendAmt;
IERC20(arc).transferFrom(poolContract,_user,_sendAmt);
bool isAllUnstake;
if(_stakeAmt == _amt){
isAllUnstake = true;
}
uInfo.stakeArc -= _amt;
uInfo.lastTime = block.timestamp;
uInfo.lastStakeTime = block.timestamp;
_subTeamValues(_line,_amt,uInfo.isAddTeamUser,isAllUnstake);
if(uInfo.stakeArc ==0){
uInfo.isAddTeamUser=false;
}
}
function _subTeamValues(address[] memory _line,uint256 _amt,bool _isAddTeamUser ,bool _isAllUnstake) private{
for(uint256 i=0;i<_line.length;i++){
UserInfo storage lInfo = userInfo[_line[i]];
if(_isAddTeamUser && _isAllUnstake){
uint256 _teamUser = lInfo.teamUser;
uint256 _newTeamUser = _teamUser>1?_teamUser-1:0;
lInfo.teamUser = _newTeamUser;
}
uint256 _teamValue = lInfo.teamValue;
uint256 _newTeamValue= _teamValue>_amt?_teamValue-_amt:0;
lInfo.teamValue =_newTeamValue;
uint256 _levels = _calcLevel(lInfo.teamUser,lInfo.teamValue);
lInfo.teamLevel = _levels;
}
}
function claimToken(address _token,address _to,uint256 _amt) external{
require(projectManage[msg.sender],'M');
IERC20(_token).transfer(_to, _amt);
}
function getAddress()external view returns(address,address,address,address,address){
return(arc,transferContract,poolContract,bankContract,funder);
}
function getUint()external view returns(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256){
return(minStakeAmount,maxStakeAmount,coldTime,dayRewardRate,dayRewardPoint,totalStakeAmt,totalUnstakeAmt,totalClaimAmt);
}
function getCd()external view returns(uint256,uint256,uint256,uint256){
return(teamCd,inviteCd,totalClaimTeamCd,totalClaimInviteCd);
}
function getState() external view returns(bool,bool,bool){
return(stakeState,claimState,unstakeState);
}
function getUnstakeFee()external view returns(uint256,uint256[] memory,uint256[] memory,uint256){
return(stakeFee,feeTimes,feeRate,totalFeePomt);
}
function calcLevel(uint256 _teamUser,uint256 _teamValue) external pure returns(uint256){
uint256 _lvs = _calcLevel(_teamUser,_teamValue);
return _lvs;
}
function calcPerRewards(uint256 _stakeAmt) external view returns(uint256){
uint256 _perSec = _calcPerRewards(_stakeAmt);
return _perSec;
}
function calcUnstakeFee(uint256 _stakeTime) external view returns(uint256){
uint256 _feeRate = _calcUnstakeFee(_stakeTime);
return _feeRate;
}
function getUserInfos(address _user) external view returns(UserInfo memory,uint256,uint256,uint256,uint256,uint256){
UserInfo memory uInfo = userInfo[_user];
uint256 _stakeArc = uInfo.stakeArc;
uint256 _pending;
if(_stakeArc>0){
uint256 _rwdTime = block.timestamp - uInfo.lastTime;
uint256 _perSecRwd = _calcPerRewards(_stakeArc);
_pending = _perSecRwd*_rwdTime;
}
uint256 _allowAmt = IERC20(arc).allowance(_user,transferContract);
uint256 _stakeTime = uInfo.lastStakeTime>0?block.timestamp - uInfo.lastStakeTime:0;
if(_stakeArc ==0){
_stakeTime=0;
}
uint256 _feeRate = _calcUnstakeFee(_stakeTime);
uint256 _inviteCd = _user==funder?inviteCd:0;
uint256 _teamCd = _user==funder?teamCd:0;
return(uInfo,_pending,_allowAmt,_feeRate,_inviteCd,_teamCd);
}
function syncGlobalUint(uint256[] memory _uintList)external{
require(projectManage[msg.sender],'M');
require(totalStakeAmt==0,'SYNC');
teamCd = _uintList[0];
inviteCd=_uintList[1];
totalStakeAmt=_uintList[2];
totalUnstakeAmt=_uintList[3];
totalClaimAmt=_uintList[4];
totalClaimInviteCd=_uintList[5];
totalClaimTeamCd=_uintList[6];
uid=_uintList[7];
}
function _syncUser(uint256 _id)private{
require(idToUser[_id] ==address(0),'SYNC');
address _user = IOldStake(oldStakeContract).idToUser(_id);
require(_user != address(0),'No User');
userId[_user] = _id;
idToUser[_id] = _user;
(IOldStake.UserInfo memory oInfo,,,,,) = IOldStake(oldStakeContract).getUserInfos(_user);
UserInfo storage uInfo = userInfo[_user];
uInfo.stakeArc = oInfo.stakeArc;
uInfo.canClaimArc = oInfo.canClaimArc;
uInfo.lastTime = oInfo.lastTime;
uInfo.lastStakeTime = oInfo.lastStakeTime;
uInfo.inviteRwd = oInfo.inviteRwd;
uInfo.teamRwd = oInfo.teamRwd;
uInfo.teamLevel = oInfo.teamLevel;
uInfo.isAddTeamUser = oInfo.isAddTeamUser;
if(oInfo.stakeArc>0){
address[] memory _line = IARC(arc).getLine(_user);
require(_line.length>0,'Bind');
_syncTeamValues(_line,oInfo.stakeArc);
}
}
function _syncTeamValues(address[] memory _line,uint256 _amt) private{
for(uint256 i=0;i<_line.length;i++){
UserInfo storage lInfo = userInfo[_line[i]];
lInfo.teamUser++;
lInfo.teamValue +=_amt;
uint256 _levels = _calcLevel(lInfo.teamUser,lInfo.teamValue);
lInfo.teamLevel = _levels;
}
}
function mutilSyncUser(uint256 _start,uint256 _end) external{
require(projectManage[msg.sender],'M');
for(uint256 i=_start;i<_end;i++){
_syncUser(i);
}
}
}