161 lines
4.5 KiB
Solidity
161 lines
4.5 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.10;
|
|
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
|
import "../core/HasSignature.sol";
|
|
import "../utils/TimeChecker.sol";
|
|
|
|
|
|
contract TreasureHunt is HasSignature, ReentrancyGuard, TimeChecker{
|
|
mapping(address => mapping(uint256 => uint256)) public checkinHistory;
|
|
mapping(address => mapping(uint256 => uint256)) public exploreHistory;
|
|
mapping(address => mapping(uint256 => uint256)) public enhanceHistory;
|
|
mapping(address => mapping(uint256 => uint256)) public claimTaskHistory;
|
|
mapping(address => mapping(uint256 => uint256)) public openBoxHistory;
|
|
uint256 private immutable _CACHED_CHAIN_ID;
|
|
address private immutable _CACHED_THIS;
|
|
address private verifier;
|
|
|
|
bool public isPaused = false;
|
|
|
|
event ActionEvent(
|
|
address indexed user,
|
|
uint256 indexed action,
|
|
uint256 value
|
|
);
|
|
|
|
event StateUpdated(bool isPaused);
|
|
event VerifierUpdated(address indexed verifier);
|
|
|
|
constructor() {
|
|
_CACHED_CHAIN_ID = block.chainid;
|
|
_CACHED_THIS = address(this);
|
|
}
|
|
|
|
modifier whenNotPaused() {
|
|
require(!isPaused, "TreasureHunt: paused");
|
|
_;
|
|
}
|
|
|
|
function updatePaused(bool _isPaused) external onlyOwner {
|
|
isPaused = _isPaused;
|
|
emit StateUpdated(_isPaused);
|
|
}
|
|
|
|
/**
|
|
* @dev update verifier address
|
|
*/
|
|
function updateVerifier(address _verifier) external onlyOwner {
|
|
require(_verifier != address(0), "TreasureHunt: address can not be zero");
|
|
verifier = _verifier;
|
|
emit VerifierUpdated(_verifier);
|
|
}
|
|
|
|
// daily checkin
|
|
function dailyCheckin() external whenNotPaused {
|
|
address user = _msgSender();
|
|
uint256 day = block.timestamp / 1 days;
|
|
require(checkinHistory[user][day] == 0, "TreasureHunt: already checked in");
|
|
checkinHistory[user][day] = 1;
|
|
emit ActionEvent(user, 1, day);
|
|
}
|
|
|
|
// explore
|
|
function explore(
|
|
uint256 step
|
|
) external whenNotPaused {
|
|
address user = _msgSender();
|
|
exploreHistory[user][step] = 1;
|
|
emit ActionEvent(user, 2, step);
|
|
}
|
|
|
|
// enhance box
|
|
function enhanceBox(
|
|
uint256 boxId
|
|
) external whenNotPaused {
|
|
address user = _msgSender();
|
|
require(enhanceHistory[user][boxId] == 0, "TreasureHunt: already enhanced");
|
|
enhanceHistory[user][boxId] = 1;
|
|
emit ActionEvent(user, 3, boxId);
|
|
}
|
|
|
|
// open box
|
|
function openBox(
|
|
uint256 boxId
|
|
) external whenNotPaused {
|
|
address user = _msgSender();
|
|
require(openBoxHistory[user][boxId] == 0, "TreasureHunt: already opened");
|
|
openBoxHistory[user][boxId] = 1;
|
|
emit ActionEvent(user, 4, boxId);
|
|
}
|
|
|
|
// claim task reward
|
|
function claimTaskReward(
|
|
uint256 taskId
|
|
) external whenNotPaused{
|
|
address user = _msgSender();
|
|
require(claimTaskHistory[user][taskId] == 0, "TreasureHunt: already claimed");
|
|
claimTaskHistory[user][taskId] = 1;
|
|
emit ActionEvent(user, 5, taskId);
|
|
}
|
|
|
|
function generalAction(
|
|
uint256 actionType,
|
|
uint256 val,
|
|
uint256 signTime,
|
|
uint256 saltNonce,
|
|
bytes calldata signature
|
|
) external nonReentrant whenNotPaused timeValid(signTime){
|
|
address user = _msgSender();
|
|
bytes32 criteriaMessageHash = getMessageHash(
|
|
user,
|
|
actionType,
|
|
val,
|
|
_CACHED_THIS,
|
|
_CACHED_CHAIN_ID,
|
|
signTime,
|
|
saltNonce
|
|
);
|
|
checkSigner(verifier, criteriaMessageHash, signature);
|
|
if (actionType == 1) {
|
|
require(checkinHistory[user][val] == 0, "TreasureHunt: already checked in");
|
|
checkinHistory[user][val] = 1;
|
|
} else if (actionType == 2) {
|
|
require(exploreHistory[user][val] == 0, "TreasureHunt: already explored");
|
|
exploreHistory[user][val] = 1;
|
|
} else if (actionType == 3) {
|
|
require(enhanceHistory[user][val] == 0, "TreasureHunt: already enhanced");
|
|
enhanceHistory[user][val] = 1;
|
|
} else if (actionType == 4) {
|
|
require(openBoxHistory[user][val] == 0, "TreasureHunt: already opened");
|
|
openBoxHistory[user][val] = 1;
|
|
} else if (actionType == 5) {
|
|
require(claimTaskHistory[user][val] == 0, "TreasureHunt: already claimed");
|
|
claimTaskHistory[user][val] = 1;
|
|
} else {
|
|
revert("TreasureHunt: invalid action type");
|
|
}
|
|
emit ActionEvent(user, actionType, val);
|
|
}
|
|
|
|
function getMessageHash(
|
|
address _user,
|
|
uint256 _type,
|
|
uint256 _val,
|
|
address _contract,
|
|
uint256 _chainId,
|
|
uint256 _signTime,
|
|
uint256 _saltNonce
|
|
) public pure returns (bytes32) {
|
|
bytes memory encoded = abi.encodePacked(
|
|
_user,
|
|
_type,
|
|
_val,
|
|
_contract,
|
|
_chainId,
|
|
_signTime,
|
|
_saltNonce
|
|
);
|
|
return keccak256(encoded);
|
|
}
|
|
}
|