编译器
0.8.10+commit.fc410830
文件 1 的 11:ContextUpgradeable.sol
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal initializer {
__Context_init_unchained();
}
function __Context_init_unchained() internal initializer {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
uint256[50] private __gap;
}
文件 2 的 11:ECDSAUpgradeable.sol
pragma solidity ^0.8.0;
library ECDSAUpgradeable {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
return tryRecover(hash, v, r, s);
}
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
文件 3 的 11:FoxGames_v1_0.sol
pragma solidity ^0.8.10;
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
import "./IFoxGame.sol";
import "./IFoxGameCarrot.sol";
import "./IFoxGameNFT.sol";
contract FoxGames_v1_0 is IFoxGame, OwnableUpgradeable, IERC721ReceiverUpgradeable,
PausableUpgradeable, ReentrancyGuardUpgradeable {
using ECDSAUpgradeable for bytes32;
uint8 public constant MAX_ADVANTAGE = 8;
uint8 public constant RABBIT_CLAIM_TAX_PERCENTAGE = 20;
uint8 private hunterStealFoxProbabilityMod;
uint8 private hunterTaxCutPercentage;
uint16 public totalMarksmanPointsStaked;
uint16 public totalCunningPointsStaked;
uint32 public totalRabbitsStaked;
uint32 public totalFoxesStaked;
uint32 public totalHuntersStaked;
uint48 public lastClaimTimestamp;
uint48 public constant RABBIT_MINIMUM_TO_EXIT = 2 days;
uint128 public constant MAXIMUM_GLOBAL_CARROT = 2500000000 ether;
uint128 public totalCarrotEarned;
uint128 public unaccountedFoxRewards;
uint128 public unaccountedHunterRewards;
uint128 public carrotPerCunningPoint;
uint128 public carrotPerMarksmanPoint;
uint128 public constant RABBIT_EARNING_RATE = 115740740740740740;
uint128 public constant HUNTER_EARNING_RATE = 231481481481481470;
struct TimeStake { uint16 tokenId; uint48 time; address owner; }
struct EarningStake { uint16 tokenId; uint128 earningRate; address owner; }
event TokenStaked(string kind, uint16 tokenId, address owner);
event TokenUnstaked(string kind, uint16 tokenId, address owner, uint128 earnings);
event FoxStolen(uint16 foxTokenId, address thief, address victim);
address private signVerifier;
IFoxGameNFT private foxNFT;
IFoxGameCarrot private foxCarrot;
mapping(uint16 => TimeStake) public rabbitStakeByToken;
mapping(uint8 => EarningStake[]) public foxStakeByCunning;
mapping(uint16 => uint16) public foxHierarchy;
mapping(uint16 => TimeStake) public hunterStakeByToken;
mapping(uint8 => EarningStake[]) public hunterStakeByMarksman;
mapping(uint16 => uint16) public hunterHierarchy;
mapping(address => uint48) public membershipDate;
mapping(address => uint32) public memberNumber;
event MemberJoined(address member, uint32 memberCount);
uint32 public membershipCount;
function initialize() public initializer {
__Ownable_init();
__ReentrancyGuard_init();
__Pausable_init();
hunterStealFoxProbabilityMod = 20;
hunterTaxCutPercentage = 30;
_pause();
}
function joinFoxGames() external {
require(tx.origin == msg.sender, "eos only");
require(membershipDate[msg.sender] == 0, "already joined");
membershipDate[msg.sender] = uint48(block.timestamp);
memberNumber[msg.sender] = membershipCount;
emit MemberJoined(msg.sender, membershipCount);
membershipCount += 1;
}
function getSigningHash(address recipient, bool membership, uint48 expiration, uint256 seed) public pure returns (bytes32) {
return keccak256(abi.encodePacked(recipient, membership, expiration, seed));
}
function isValidSignature(address recipient, bool membership, uint48 expiration, uint256 seed, bytes memory sig) public view returns (bool) {
bytes32 message = getSigningHash(recipient, membership, expiration, seed).toEthSignedMessageHash();
return ECDSAUpgradeable.recover(message, sig) == signVerifier;
}
function stakeTokens(address account, uint16[] calldata tokenIds) external whenNotPaused nonReentrant _updateEarnings {
require((account == msg.sender && tx.origin == msg.sender) || msg.sender == address(foxNFT), "not approved");
for (uint16 i = 0; i < tokenIds.length; i++) {
if (tokenIds[i] == 0) {
continue;
}
IFoxGameNFT.Kind kind = _getKind(tokenIds[i]);
if (kind == IFoxGameNFT.Kind.RABBIT) {
_addRabbitToKeep(account, tokenIds[i]);
} else if (kind == IFoxGameNFT.Kind.FOX) {
_addFoxToDen(account, tokenIds[i]);
} else {
_addHunterToCabin(account, tokenIds[i]);
}
if (msg.sender != address(foxNFT)) {
require(foxNFT.ownerOf(tokenIds[i]) == msg.sender, "only token owners can stake");
foxNFT.transferFrom(msg.sender, address(this), tokenIds[i]);
}
}
}
function _addRabbitToKeep(address account, uint16 tokenId) internal {
rabbitStakeByToken[tokenId] = TimeStake({
owner: account,
tokenId: tokenId,
time: uint48(block.timestamp)
});
totalRabbitsStaked += 1;
emit TokenStaked("RABBIT", tokenId, account);
}
function _addFoxToDen(address account, uint16 tokenId) internal {
uint8 cunning = _getAdvantagePoints(tokenId);
totalCunningPointsStaked += cunning;
foxHierarchy[tokenId] = uint16(foxStakeByCunning[cunning].length);
foxStakeByCunning[cunning].push(EarningStake({
owner: account,
tokenId: tokenId,
earningRate: carrotPerCunningPoint
}));
totalFoxesStaked += 1;
emit TokenStaked("FOX", tokenId, account);
}
function _addHunterToCabin(address account, uint16 tokenId) internal {
uint8 marksman = _getAdvantagePoints(tokenId);
totalMarksmanPointsStaked += marksman;
hunterHierarchy[tokenId] = uint16(hunterStakeByMarksman[marksman].length);
hunterStakeByMarksman[marksman].push(EarningStake({
owner: account,
tokenId: tokenId,
earningRate: carrotPerMarksmanPoint
}));
hunterStakeByToken[tokenId] = TimeStake({
owner: account,
tokenId: tokenId,
time: uint48(block.timestamp)
});
totalHuntersStaked += 1;
emit TokenStaked("HUNTER", tokenId, account);
}
function claimRewardsAndUnstake(uint16[] calldata tokenIds, bool unstake, bool membership, uint48 expiration, uint256 seed, bytes memory sig) external whenNotPaused nonReentrant _updateEarnings {
require(tx.origin == msg.sender, "eos only");
require(isValidSignature(msg.sender, membership, expiration, seed, sig), "invalid signature");
uint128 reward;
IFoxGameNFT.Kind kind;
uint48 time = uint48(block.timestamp);
for (uint8 i = 0; i < tokenIds.length; i++) {
kind = _getKind(tokenIds[i]);
if (kind == IFoxGameNFT.Kind.RABBIT) {
reward += _claimRabbitsFromKeep(tokenIds[i], unstake, time, seed);
} else if (kind == IFoxGameNFT.Kind.FOX) {
reward += _claimFoxFromDen(tokenIds[i], unstake, seed);
} else {
reward += _claimHunterFromCabin(tokenIds[i], unstake, time);
}
}
if (reward != 0) {
foxCarrot.mint(msg.sender, reward);
}
}
function _claimRabbitsFromKeep(uint16 tokenId, bool unstake, uint48 time, uint256 seed) internal returns (uint128 reward) {
TimeStake memory stake = rabbitStakeByToken[tokenId];
require(stake.owner == msg.sender, "only token owners can unstake");
require(!(unstake && block.timestamp - stake.time < RABBIT_MINIMUM_TO_EXIT), "rabbits need 2 days of carrot");
if (totalCarrotEarned < MAXIMUM_GLOBAL_CARROT) {
reward = (time - stake.time) * RABBIT_EARNING_RATE;
} else if (stake.time <= lastClaimTimestamp) {
reward = (lastClaimTimestamp - stake.time) * RABBIT_EARNING_RATE;
}
if (unstake) {
if (((seed >> 245) % 2) == 0) {
_payTaxToPredators(reward, true);
reward = 0;
}
delete rabbitStakeByToken[tokenId];
totalRabbitsStaked -= 1;
foxNFT.safeTransferFrom(address(this), msg.sender, tokenId, "");
} else {
_payTaxToPredators(reward * RABBIT_CLAIM_TAX_PERCENTAGE / 100, false);
reward = reward * (100 - RABBIT_CLAIM_TAX_PERCENTAGE) / 100;
rabbitStakeByToken[tokenId] = TimeStake({
owner: msg.sender,
tokenId: tokenId,
time: time
});
}
emit TokenUnstaked("RABBIT", tokenId, stake.owner, reward);
}
function _claimFoxFromDen(uint16 tokenId, bool unstake, uint256 seed) internal returns (uint128 reward) {
require(foxNFT.ownerOf(tokenId) == address(this), "must be staked to claim rewards");
uint8 cunning = _getAdvantagePoints(tokenId);
EarningStake memory stake = foxStakeByCunning[cunning][foxHierarchy[tokenId]];
require(stake.owner == msg.sender, "only token owners can unstake");
reward = (cunning) * (carrotPerCunningPoint - stake.earningRate);
if (unstake) {
totalCunningPointsStaked -= cunning;
EarningStake memory lastStake = foxStakeByCunning[cunning][foxStakeByCunning[cunning].length - 1];
foxStakeByCunning[cunning][foxHierarchy[tokenId]] = lastStake;
foxHierarchy[lastStake.tokenId] = foxHierarchy[tokenId];
foxStakeByCunning[cunning].pop();
delete foxHierarchy[tokenId];
totalFoxesStaked -= 1;
address recipient = msg.sender;
if (((seed >> 245) % hunterStealFoxProbabilityMod) == 0) {
recipient = _randomHunterOwner(seed);
if (recipient == address(0x0)) {
recipient = msg.sender;
} else if (recipient != msg.sender) {
emit FoxStolen(tokenId, recipient, msg.sender);
}
}
foxNFT.safeTransferFrom(address(this), recipient, tokenId, "");
} else {
foxStakeByCunning[cunning][foxHierarchy[tokenId]] = EarningStake({
owner: msg.sender,
tokenId: tokenId,
earningRate: carrotPerCunningPoint
});
}
emit TokenUnstaked("FOX", tokenId, stake.owner, reward);
}
function _claimHunterFromCabin(uint16 tokenId, bool unstake, uint48 time) internal returns (uint128 reward) {
require(foxNFT.ownerOf(tokenId) == address(this), "must be staked to claim rewards");
uint8 marksman = _getAdvantagePoints(tokenId);
EarningStake memory earningStake = hunterStakeByMarksman[marksman][hunterHierarchy[tokenId]];
require(earningStake.owner == msg.sender, "only token owners can unstake");
reward = (marksman) * (carrotPerMarksmanPoint - earningStake.earningRate);
if (unstake) {
totalMarksmanPointsStaked -= marksman;
EarningStake memory lastStake = hunterStakeByMarksman[marksman][hunterStakeByMarksman[marksman].length - 1];
hunterStakeByMarksman[marksman][hunterHierarchy[tokenId]] = lastStake;
hunterHierarchy[lastStake.tokenId] = hunterHierarchy[tokenId];
hunterStakeByMarksman[marksman].pop();
delete hunterHierarchy[tokenId];
} else {
hunterStakeByMarksman[marksman][hunterHierarchy[tokenId]] = EarningStake({
owner: msg.sender,
tokenId: tokenId,
earningRate: carrotPerMarksmanPoint
});
}
TimeStake memory timeStake = hunterStakeByToken[tokenId];
require(timeStake.owner == msg.sender, "only token owners can unstake");
if (totalCarrotEarned < MAXIMUM_GLOBAL_CARROT) {
reward += (time - timeStake.time) * HUNTER_EARNING_RATE;
} else if (timeStake.time <= lastClaimTimestamp) {
reward += (lastClaimTimestamp - timeStake.time) * HUNTER_EARNING_RATE;
}
if (unstake) {
delete hunterStakeByToken[tokenId];
totalHuntersStaked -= 1;
foxNFT.safeTransferFrom(address(this), msg.sender, tokenId, "");
} else {
hunterStakeByToken[tokenId] = TimeStake({
owner: msg.sender,
tokenId: tokenId,
time: time
});
}
emit TokenUnstaked("HUNTER", tokenId, earningStake.owner, reward);
}
function _payTaxToPredators(uint128 amount, bool includeHunters) internal {
uint128 amountDueFoxes = amount;
if (includeHunters) {
uint128 amountDueHunters = amount * hunterTaxCutPercentage / 100;
amountDueFoxes -= amountDueHunters;
if (totalMarksmanPointsStaked == 0) {
unaccountedHunterRewards += amountDueHunters;
} else {
carrotPerMarksmanPoint += (amountDueHunters + unaccountedHunterRewards) / totalMarksmanPointsStaked;
unaccountedHunterRewards = 0;
}
}
if (totalCunningPointsStaked == 0) {
unaccountedFoxRewards += amountDueFoxes;
} else {
carrotPerCunningPoint += (amountDueFoxes + unaccountedFoxRewards) / totalCunningPointsStaked;
unaccountedFoxRewards = 0;
}
}
modifier _updateEarnings() {
if (totalCarrotEarned < MAXIMUM_GLOBAL_CARROT) {
uint48 time = uint48(block.timestamp);
uint48 elapsed = time - lastClaimTimestamp;
totalCarrotEarned +=
(elapsed * totalRabbitsStaked * RABBIT_EARNING_RATE) +
(elapsed * totalHuntersStaked * HUNTER_EARNING_RATE);
lastClaimTimestamp = time;
}
_;
}
function _getKind(uint16 tokenId) internal view returns (IFoxGameNFT.Kind) {
return foxNFT.getTraits(tokenId).kind;
}
function _getAdvantagePoints(uint16 tokenId) internal view returns (uint8) {
return MAX_ADVANTAGE - foxNFT.getTraits(tokenId).advantage;
}
function randomFoxOwner(uint256 seed) external view returns (address) {
if (totalCunningPointsStaked == 0) {
return address(0x0);
}
uint256 bucket = (seed & 0xFFFFFFFF) % totalCunningPointsStaked;
uint256 cumulative;
seed >>= 32;
for (uint8 i = MAX_ADVANTAGE - 3; i <= MAX_ADVANTAGE; i++) {
cumulative += foxStakeByCunning[i].length * i;
if (bucket >= cumulative) continue;
return foxStakeByCunning[i][seed % foxStakeByCunning[i].length].owner;
}
return address(0x0);
}
function _randomHunterOwner(uint256 seed) internal view returns (address) {
if (totalMarksmanPointsStaked == 0) {
return address(0x0);
}
uint256 bucket = (seed & 0xFFFFFFFF) % totalMarksmanPointsStaked;
uint256 cumulative;
seed >>= 32;
for (uint8 i = MAX_ADVANTAGE - 3; i <= MAX_ADVANTAGE; i++) {
cumulative += hunterStakeByMarksman[i].length * i;
if (bucket >= cumulative) continue;
return hunterStakeByMarksman[i][seed % hunterStakeByMarksman[i].length].owner;
}
return address(0x0);
}
function togglePaused() external onlyOwner {
if (paused()) {
_unpause();
} else {
_pause();
}
}
function setSignVerifier(address verifier) external onlyOwner {
signVerifier = verifier;
}
function setNFTContract(address _address) external onlyOwner {
foxNFT = IFoxGameNFT(_address);
}
function setCarrotContract(address _address) external onlyOwner {
foxCarrot = IFoxGameCarrot(_address);
}
function setHunterTaxCutPercentage(uint8 percentCut) external onlyOwner {
hunterTaxCutPercentage = percentCut;
}
function setHunterStealFoxPropabilityMod(uint8 mod) external onlyOwner {
hunterStealFoxProbabilityMod = mod;
}
function onERC721Received(address, address from, uint256, bytes calldata) external pure override returns (bytes4) {
require(from == address(0x0), "only allow directly from mint");
return IERC721ReceiverUpgradeable.onERC721Received.selector;
}
}
文件 4 的 11:IERC721ReceiverUpgradeable.sol
pragma solidity ^0.8.0;
interface IERC721ReceiverUpgradeable {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 5 的 11:IFoxGame.sol
pragma solidity ^0.8.10;
interface IFoxGame {
function stakeTokens(address, uint16[] calldata) external;
function randomFoxOwner(uint256) external view returns (address);
function isValidSignature(address, bool, uint48, uint256, bytes memory) external view returns (bool);
}
文件 6 的 11:IFoxGameCarrot.sol
pragma solidity ^0.8.10;
interface IFoxGameCarrot {
function mint(address to, uint256 amount) external;
function burn(address from, uint256 amount) external;
}
文件 7 的 11:IFoxGameNFT.sol
pragma solidity ^0.8.10;
interface IFoxGameNFT {
enum Kind { RABBIT, FOX, HUNTER }
struct Traits { Kind kind; uint8 advantage; uint8[7] traits; }
function getMaxGEN0Players() external pure returns (uint16);
function getTraits(uint16) external view returns (Traits memory);
function ownerOf(uint256) external view returns (address owner);
function transferFrom(address, address, uint256) external;
function safeTransferFrom(address, address, uint256, bytes memory) external;
}
文件 8 的 11:Initializable.sol
pragma solidity ^0.8.0;
abstract contract Initializable {
bool private _initialized;
bool private _initializing;
modifier initializer() {
require(_initializing || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
}
文件 9 的 11:OwnableUpgradeable.sol
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function __Ownable_init() internal initializer {
__Context_init_unchained();
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal initializer {
_setOwner(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
uint256[49] private __gap;
}
文件 10 的 11:PausableUpgradeable.sol
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
function __Pausable_init() internal initializer {
__Context_init_unchained();
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal initializer {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
uint256[49] private __gap;
}
文件 11 的 11:ReentrancyGuardUpgradeable.sol
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
abstract contract ReentrancyGuardUpgradeable is Initializable {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal initializer {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal initializer {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
uint256[49] private __gap;
}
{
"compilationTarget": {
"contracts/FoxGames_v1_0.sol": "FoxGames_v1_0"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"foxTokenId","type":"uint16"},{"indexed":false,"internalType":"address","name":"thief","type":"address"},{"indexed":false,"internalType":"address","name":"victim","type":"address"}],"name":"FoxStolen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"member","type":"address"},{"indexed":false,"internalType":"uint32","name":"memberCount","type":"uint32"}],"name":"MemberJoined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"kind","type":"string"},{"indexed":false,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"TokenStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"kind","type":"string"},{"indexed":false,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint128","name":"earnings","type":"uint128"}],"name":"TokenUnstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"HUNTER_EARNING_RATE","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXIMUM_GLOBAL_CARROT","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ADVANTAGE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RABBIT_CLAIM_TAX_PERCENTAGE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RABBIT_EARNING_RATE","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RABBIT_MINIMUM_TO_EXIT","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"carrotPerCunningPoint","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"carrotPerMarksmanPoint","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"},{"internalType":"bool","name":"unstake","type":"bool"},{"internalType":"bool","name":"membership","type":"bool"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"claimRewardsAndUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"foxHierarchy","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"foxStakeByCunning","outputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"},{"internalType":"uint128","name":"earningRate","type":"uint128"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"membership","type":"bool"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint256","name":"seed","type":"uint256"}],"name":"getSigningHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"hunterHierarchy","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"hunterStakeByMarksman","outputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"},{"internalType":"uint128","name":"earningRate","type":"uint128"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"hunterStakeByToken","outputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"},{"internalType":"uint48","name":"time","type":"uint48"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"membership","type":"bool"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"joinFoxGames","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastClaimTimestamp","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"memberNumber","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"membershipCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"membershipDate","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"rabbitStakeByToken","outputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"},{"internalType":"uint48","name":"time","type":"uint48"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"seed","type":"uint256"}],"name":"randomFoxOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setCarrotContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"mod","type":"uint8"}],"name":"setHunterStealFoxPropabilityMod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"percentCut","type":"uint8"}],"name":"setHunterTaxCutPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setNFTContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"verifier","type":"address"}],"name":"setSignVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"}],"name":"stakeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"togglePaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalCarrotEarned","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCunningPointsStaked","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFoxesStaked","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalHuntersStaked","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMarksmanPointsStaked","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRabbitsStaked","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unaccountedFoxRewards","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unaccountedHunterRewards","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"}]