0%

thlm | 空投合约

新空投合约代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract GameAirdrop is Ownable, Pausable, ReentrancyGuard {

address public GAMETokenAddress;
address public RecordOwner;
bool public emergencyUnstakeFlag;

struct StakeInfo {
uint256 stakeAmount;
uint256 unstakeTimestamp;
}

mapping(address => StakeInfo) internal _stakeRecords;

uint256 internal _stakeTimestamp = 2 * 365 * 24 * 60 * 60;

event GameStake(address user, uint256 oldStakeAmount,uint256 newStakeAmount, uint256 oldUnstakeTimestamp,uint256 newUnstakeTimestamp);

event GameUnstake(address user, uint256 unstakeAmount, uint256 unstakeTimestamp);

event GameRecordStake(address user, uint256 stakeAmount, uint256 unstakeTimestamp);

modifier onlyEOA() {
require(msg.sender.code.length == 0, "only EOA");
_;
}

modifier onlyRecordOwner() {
require(msg.sender == RecordOwner, "only RecordOwner");
_;
}

constructor(address ownerAddress,address RecordOwner_,address GameTokenAddress_) Ownable(ownerAddress) {
GAMETokenAddress = GameTokenAddress_;
RecordOwner = RecordOwner_;
emergencyUnstakeFlag = false;

}

function updateEmergeceUnstakeFlag(bool flag) public onlyOwner {
emergencyUnstakeFlag = flag;
}

function getUserStakeInfo(address user) public view returns(StakeInfo memory) {
StakeInfo memory stakeRecord = _stakeRecords[user];
return stakeRecord;
}

function pause() public onlyOwner {
_pause();
}

function unpause() public onlyOwner {
_unpause();
}

function RecordStake(address[] memory recordAddress,StakeInfo[] memory recordInfos) public onlyRecordOwner{
for (uint256 i = 0; i < recordAddress.length; i++) {
StakeInfo memory stakeRecord = recordInfos[i];
_stakeRecords[recordAddress[i]] = stakeRecord;
emit GameRecordStake(recordAddress[i],stakeRecord.stakeAmount,stakeRecord.unstakeTimestamp);
}
}

function renounceRecordOwner() public onlyRecordOwner {
RecordOwner = address(0);
}

function stake(uint256 amount) public nonReentrant whenNotPaused onlyEOA {

StakeInfo storage stakeRecord = _stakeRecords[msg.sender];
uint256 oldAmount = stakeRecord.stakeAmount;
uint256 oldUnstakeTimestamp = stakeRecord.unstakeTimestamp;
uint256 newUnstakeTimestamp = block.timestamp + _stakeTimestamp;
require(amount > 0, "invalid amount");
IERC20(GAMETokenAddress).transferFrom(msg.sender, address(this), amount);
stakeRecord.stakeAmount += amount;
stakeRecord.unstakeTimestamp = newUnstakeTimestamp;
emit GameStake(msg.sender, oldAmount, stakeRecord.stakeAmount,
oldUnstakeTimestamp, stakeRecord.unstakeTimestamp);
}

function queryUnstake(address user) public view returns(uint256 userAmount, uint256 unstakeTimestamp) {
StakeInfo memory stakeRecord = _stakeRecords[user];
userAmount = stakeRecord.stakeAmount;
unstakeTimestamp = stakeRecord.unstakeTimestamp;
}

function unstake() public nonReentrant whenNotPaused {
StakeInfo storage stakeRecord = _stakeRecords[msg.sender];
uint256 unstakeAmount = stakeRecord.stakeAmount;
require(stakeRecord.stakeAmount > 0, "not stake yet");
require(block.timestamp > stakeRecord.unstakeTimestamp, "invalid timestamp");
IERC20(GAMETokenAddress).transfer(msg.sender, unstakeAmount);
stakeRecord.stakeAmount = 0;
stakeRecord.unstakeTimestamp = 0;
emit GameUnstake(msg.sender, unstakeAmount, block.timestamp);
}

/*
* 紧急情况下,管理员可以通过修改设置,让用户可以提取所有的资金
*/
function emergencyUnstake() public nonReentrant whenNotPaused {
require(emergencyUnstakeFlag, "emergency unstake is not allowed");

StakeInfo storage stakeRecord = _stakeRecords[msg.sender];
uint256 unstakeAmount = stakeRecord.stakeAmount;
require(stakeRecord.stakeAmount > 0, "not stake yet");

IERC20(GAMETokenAddress).transfer(msg.sender, unstakeAmount);
stakeRecord.stakeAmount = 0;
stakeRecord.unstakeTimestamp = 0;

emit GameUnstake(msg.sender, unstakeAmount, block.timestamp);
}
}
请我喝杯咖啡吧~