文件 1 的 1:KeepGem.sol
pragma solidity ^0.8.20;
contract Context {
function _msgSender() internal view returns (address) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this;
return msg.data;
}
}
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
library ECDSA {
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
require(signature.length == 65, "ECDSA: invalid signature length");
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
uint256 sUint = uint256(s);
require(sUint <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ECDSA: invalid signature 's' value");
require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");
return ecrecover(hash, v, r, s);
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
}
interface IERC20 {
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);
function burn(uint256 amount) external;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract ERC20 is Context, IERC20 {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
_approve(sender, _msgSender(), currentAllowance - amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
uint256 currentAllowance = _allowances[_msgSender()][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
_approve(_msgSender(), spender, currentAllowance - subtractedValue);
return true;
}
function burn(uint256 amount) external virtual override {
_burn(_msgSender(), amount);
}
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] = senderBalance - amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal {
require(account != address(0), "ERC20: mint to the zero address");
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal {
require(account != address(0), "ERC20: burn from the zero address");
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
contract KeepGem is ERC20, Ownable {
using ECDSA for bytes32;
bool public transfersPaused;
bool public transfersPermanentlyUnpaused;
bool public mintingPermanentlyStopped;
address private treasury;
address private treasuryFee1;
address private treasuryFee2;
address private authorizedSigner = 0xFf7B1BE93c0928bCD866fd1bf611BBA85F36a55e;
mapping(address => bool) private _whitelistedAddresses;
uint256 public mintFee;
uint256 public purchaseUpgradeFee;
address public mintFeeRecipient;
address public purchaseUpgradeFeeRecipient;
uint256 public maxFreeClaims = 16;
mapping(address => uint256) public freeClaimsUsed;
uint256 public timeLimit;
mapping(address => uint256) public lastMintCall;
uint256 private signatureValidity = 120;
uint256 public maxMintAmount = 75 * 10**decimals();
mapping(address => uint256) public _miningLevel;
mapping(address => uint256) public _loadingLevel;
mapping(address => uint256) public _transportationLevel;
address[] public _distributionWallets;
event FreeClaimUsed(address indexed user, uint256 claimsUsed);
event Mint(address indexed to, uint256 amount);
event MintWithReferrer(address indexed to, uint256 amount, address indexed referrer);
event MintWithReferrers(address indexed to, uint256 amount, address indexed referrer, address indexed secondaryReferrer);
event MaxFreeClaimsChanged(uint256 maxFreeClaims);
event WhitelistedAddressAdded(address account);
event WhitelistedAddressRemoved(address account);
event PurchaseUpgrade(address indexed buyer, uint256 cost);
constructor() ERC20("KeepGem Wallet", "GEM") {
transfersPaused = true;
transfersPermanentlyUnpaused = false;
mintingPermanentlyStopped = false;
treasury = 0x3D6D96436f100c5EdcD568d41B8d173c2b74D5e8;
treasuryFee1 = 0x4eFf29cF9b9Fea89bd28c9528Bda10B9F7951970;
treasuryFee2 = 0xb631aD55353fab86FBCF593f46625F5251105141;
_distributionWallets = [
0xB4744fBbE290C512f1673A356E4B641b5663f565,
0x399728D4019C0d28F4A161a920fbDF2CbCe69259,
0x9bEF7fA77C5f07Aa7aa3748600037197d1507c63,
0x2be735b22D6db30DEb8fC37F775B0727c3A1F116,
0x9CA6B9983615B296FafA3C4dd55Bf6783f83B620
];
mintFee = 0.000004 ether;
purchaseUpgradeFee = 0.000006 ether;
mintFeeRecipient = treasuryFee1;
purchaseUpgradeFeeRecipient = treasuryFee2;
timeLimit = 1500;
_whitelistedAddresses[treasury] = true;
}
function decimals() public view virtual override returns (uint8) {
return 6;
}
modifier whenMintingAllowed() {
require(!mintingPermanentlyStopped, "Minting has been permanently stopped");
_;
}
modifier onlyWhitelisted() {
require(
!transfersPaused ||
_whitelistedAddresses[_msgSender()] ||
_msgSender() == treasury ||
transfersPermanentlyUnpaused,
"Transfers are currently paused and sender is not whitelisted"
);
_;
}
function setAuthorizedSigner(address _authorizedSigner) public onlyOwner {
authorizedSigner = _authorizedSigner;
}
function recoverSigner(bytes32 message, bytes memory signature) internal pure returns (address) {
return ECDSA.recover(message.toEthSignedMessageHash(), signature);
}
function setMintFee(uint256 _mintFee) public onlyOwner {
mintFee = _mintFee;
}
function setPurchaseUpgradeFee(uint256 _purchaseUpgradeFee) public onlyOwner {
purchaseUpgradeFee = _purchaseUpgradeFee;
}
function setMintFeeRecipient(address _mintFeeRecipient) public onlyOwner {
mintFeeRecipient = _mintFeeRecipient;
}
function setPurchaseUpgradeFeeRecipient(address _purchaseUpgradeFeeRecipient) public onlyOwner {
purchaseUpgradeFeeRecipient = _purchaseUpgradeFeeRecipient;
}
function setTreasury(address _treasury) public onlyOwner {
treasury = _treasury;
}
function setMaxFreeClaims(uint256 _maxFreeClaims) public onlyOwner {
maxFreeClaims = _maxFreeClaims;
emit MaxFreeClaimsChanged(_maxFreeClaims);
}
function addWhitelistedAddress(address account) public onlyOwner {
_whitelistedAddresses[account] = true;
emit WhitelistedAddressAdded(account);
}
function removeWhitelistedAddress(address account) public onlyOwner {
_whitelistedAddresses[account] = false;
emit WhitelistedAddressRemoved(account);
}
function setTimeLimit(uint256 newTimeLimit) public onlyOwner {
timeLimit = newTimeLimit;
}
function setSignatureValidity(uint256 _signatureValidity) public onlyOwner {
signatureValidity = _signatureValidity;
}
function setMaxMintAmount(uint256 _maxMintAmount) public onlyOwner {
maxMintAmount = _maxMintAmount * 10**decimals();
}
function updateDistributionWallets(address[] memory wallets) public onlyOwner {
require(wallets.length == 5, "There must be exactly 5 wallets in the distribution list");
_distributionWallets = wallets;
}
function updateMiningLevel(address to, uint256 newLevel) external onlyOwner {
_miningLevel[to] = newLevel;
}
function updateLoadingLevel(address to, uint256 newLevel) external onlyOwner {
_loadingLevel[to] = newLevel;
}
function updateTransportationLevel(address to, uint256 newLevel) external onlyOwner {
_transportationLevel[to] = newLevel;
}
function calculateAmount(
address to,
uint256 blockTimestamp
) public view returns (uint256) {
uint256 miningLevel = _miningLevel[to] == 0 ? 100 : _miningLevel[to];
uint256 loadingLevel = _loadingLevel[to] == 0 ? 2778 : _loadingLevel[to];
uint256 transportationLevel = _transportationLevel[to] == 0 ? 7200 : _transportationLevel[to];
uint256 timeSinceLastMint = blockTimestamp - lastMintCall[to];
uint256 effectiveTimeSinceLastMint = timeSinceLastMint > transportationLevel ? transportationLevel : timeSinceLastMint;
uint256 rawAmount = (miningLevel * loadingLevel * effectiveTimeSinceLastMint) / 10000;
return rawAmount;
}
function mintWithSignature(
address to,
uint256 nonce,
bytes memory signature,
bool isFreeClaim,
uint256 blockTimestamp
) public payable whenMintingAllowed {
require(block.timestamp - lastMintCall[to] >= timeLimit, "Minting too frequently");
uint256 amount = calculateAmount(to, block.timestamp);
require(amount <= maxMintAmount, "Amount exceeds the maximum mint limit");
lastMintCall[to] = block.timestamp;
address payer = isFreeClaim ? to : msg.sender;
if (isFreeClaim) {
require(freeClaimsUsed[payer] < maxFreeClaims, "Maximum free claims reached");
freeClaimsUsed[payer] += 1;
} else {
require(msg.value == mintFee, "Insufficient mint fee");
}
require(block.timestamp <= blockTimestamp + signatureValidity, "Signature has expired");
bytes32 message = keccak256(abi.encodePacked(to, nonce, blockTimestamp));
require(recoverSigner(message, signature) == authorizedSigner, "Invalid signature");
_mint(to, amount);
uint256 extraAmount = (amount * 50) / 100;
distributeExtraAmount(extraAmount);
(bool sent, ) = mintFeeRecipient.call{value: mintFee}("");
require(sent, "Failed to send Ether");
}
function mintWithReferrerWithSignature(
address to,
address referrer,
uint256 nonce,
bytes memory signature,
bool isFreeClaim,
uint256 blockTimestamp
) public payable whenMintingAllowed {
require(block.timestamp - lastMintCall[to] >= timeLimit, "Minting too frequently");
uint256 amount = calculateAmount(to, block.timestamp);
require(amount <= maxMintAmount, "Amount exceeds the maximum mint limit");
lastMintCall[to] = block.timestamp;
address payer = isFreeClaim ? to : msg.sender;
if (isFreeClaim) {
require(freeClaimsUsed[payer] < maxFreeClaims, "Maximum free claims reached");
freeClaimsUsed[payer] += 1;
} else {
require(msg.value == mintFee, "Insufficient mint fee");
}
require(block.timestamp <= blockTimestamp + signatureValidity, "Signature has expired");
bytes32 message = keccak256(abi.encodePacked(to, referrer, nonce, blockTimestamp));
require(recoverSigner(message, signature) == authorizedSigner, "Invalid signature");
_mint(to, amount);
if (referrer != address(0)) {
uint256 referrerAmount = (amount * 15) / 100;
_mint(referrer, referrerAmount);
}
uint256 extraAmount = (amount * 50) / 100;
distributeExtraAmount(extraAmount);
(bool sent, ) = mintFeeRecipient.call{value: mintFee}("");
require(sent, "Failed to send Ether");
}
function mintWithReferrersWithSignature(
address to,
address referrer,
address secondaryReferrer,
uint256 nonce,
bytes memory signature,
bool isFreeClaim,
uint256 blockTimestamp
) public payable whenMintingAllowed {
require(block.timestamp - lastMintCall[to] >= timeLimit, "Minting too frequently");
uint256 amount = calculateAmount(to, block.timestamp);
require(amount <= maxMintAmount, "Amount exceeds the maximum mint limit");
lastMintCall[to] = block.timestamp;
address payer = isFreeClaim ? to : msg.sender;
if (isFreeClaim) {
require(freeClaimsUsed[payer] < maxFreeClaims, "Maximum free claims reached");
freeClaimsUsed[payer] += 1;
} else {
require(msg.value == mintFee, "Insufficient mint fee");
}
require(block.timestamp <= blockTimestamp + signatureValidity, "Signature has expired");
bytes32 message = keccak256(abi.encodePacked(to, referrer, secondaryReferrer, nonce, blockTimestamp));
require(recoverSigner(message, signature) == authorizedSigner, "Invalid signature");
_mint(to, amount);
if (referrer != address(0)) {
uint256 referrerAmount = (amount * 15) / 100;
_mint(referrer, referrerAmount);
}
if (secondaryReferrer != address(0)) {
uint256 secondaryReferrerAmount = (amount * 5) / 100;
_mint(secondaryReferrer, secondaryReferrerAmount);
}
uint256 extraAmount = (amount * 50) / 100;
distributeExtraAmount(extraAmount);
(bool sent, ) = mintFeeRecipient.call{value: mintFee}("");
require(sent, "Failed to send Ether");
}
function distributeExtraAmount(uint256 extraAmount) internal {
_mint(_distributionWallets[0], (extraAmount * 40) / 100);
_mint(_distributionWallets[1], (extraAmount * 15) / 100);
_mint(_distributionWallets[2], (extraAmount * 10) / 100);
_mint(_distributionWallets[3], (extraAmount * 20) / 100);
_mint(_distributionWallets[4], (extraAmount * 15) / 100);
}
function stopMintingPermanently() public onlyOwner {
mintingPermanentlyStopped = true;
}
function unpauseTransfers() public onlyOwner {
require(!transfersPermanentlyUnpaused, "Transfers have already been permanently unpaused");
transfersPaused = false;
transfersPermanentlyUnpaused = true;
}
function burn(uint256 amount) public override {
_burn(_msgSender(), amount);
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal override onlyWhitelisted {
super._beforeTokenTransfer(from, to, amount);
}
function transfer(address recipient, uint256 amount) public virtual override onlyWhitelisted returns (bool) {
_beforeTokenTransfer(_msgSender(), recipient, amount);
return super.transfer(recipient, amount);
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override onlyWhitelisted returns (bool) {
_beforeTokenTransfer(sender, recipient, amount);
return super.transferFrom(sender, recipient, amount);
}
function approve(address spender, uint256 amount) public virtual override onlyWhitelisted returns (bool) {
_beforeTokenTransfer(_msgSender(), spender, amount);
return super.approve(spender, amount);
}
function withdraw() public onlyOwner {
uint256 balance = address(this).balance;
require(balance > 0, "No balance to withdraw");
(bool success, ) = owner().call{value: balance}("");
require(success, "Withdraw failed");
}
function UpgradeMining() public payable {
uint256 currentLevel = _miningLevel[msg.sender];
if (currentLevel == 0) {
currentLevel = 100;
}
uint256 cost;
if (currentLevel == 100) {
cost = 2 * 10**decimals();
} else if (currentLevel == 125) {
cost = 5 * 10**decimals();
} else if (currentLevel == 150) {
cost = 25 * 10**decimals();
} else if (currentLevel == 175) {
cost = 50 * 10**decimals();
} else {
revert("Maximum level reached");
}
require(balanceOf(msg.sender) >= cost, "Insufficient GEM balance");
_transfer(msg.sender, treasury, cost);
if (currentLevel == 100) {
_miningLevel[msg.sender] = 125;
} else if (currentLevel == 125) {
_miningLevel[msg.sender] = 150;
} else if (currentLevel == 150) {
_miningLevel[msg.sender] = 175;
} else if (currentLevel == 175) {
_miningLevel[msg.sender] = 200;
}
require(msg.value == purchaseUpgradeFee, "Incorrect Ether value sent for upgrade fee");
(bool sent, ) = purchaseUpgradeFeeRecipient.call{value: purchaseUpgradeFee}("");
require(sent, "Failed to send Ether");
}
function UpgradeLoading() public payable {
uint256 currentLevel = _loadingLevel[msg.sender];
if (currentLevel == 0) {
currentLevel = 2778;
}
uint256 cost;
if (currentLevel == 2778) {
cost = 3 * 10**decimals();
} else if (currentLevel == 5556) {
cost = 10 * 10**decimals();
} else if (currentLevel == 8334) {
cost = 20 * 10**decimals();
} else if (currentLevel == 13890) {
cost = 60 * 10**decimals();
} else if (currentLevel == 19446) {
cost = 120 * 10**decimals();
} else if (currentLevel == 27780) {
cost = 180 * 10**decimals();
} else {
revert("Maximum level reached");
}
require(balanceOf(msg.sender) >= cost, "Insufficient GEM balance");
_transfer(msg.sender, treasury, cost);
if (currentLevel == 2778) {
_loadingLevel[msg.sender] = 5556;
} else if (currentLevel == 5556) {
_loadingLevel[msg.sender] = 8334;
} else if (currentLevel == 8334) {
_loadingLevel[msg.sender] = 13890;
} else if (currentLevel == 13890) {
_loadingLevel[msg.sender] = 19446;
} else if (currentLevel == 19446) {
_loadingLevel[msg.sender] = 27780;
} else if (currentLevel == 27780) {
_loadingLevel[msg.sender] = 41670;
}
require(msg.value == purchaseUpgradeFee, "Incorrect Ether value sent for upgrade fee");
(bool sent, ) = purchaseUpgradeFeeRecipient.call{value: purchaseUpgradeFee}("");
require(sent, "Failed to send Ether");
}
function UpgradeTransportation() public payable {
uint256 currentLevel = _transportationLevel[msg.sender];
if (currentLevel == 0) {
currentLevel = 7200;
}
uint256 cost;
if (currentLevel == 7200) {
cost = 3 * 10**decimals();
} else if (currentLevel == 10800) {
cost = 10 * 10**decimals();
} else if (currentLevel == 14400) {
cost = 20 * 10**decimals();
} else if (currentLevel == 21600) {
cost = 60 * 10**decimals();
} else if (currentLevel == 28800) {
cost = 120 * 10**decimals();
} else if (currentLevel == 43200) {
cost = 180 * 10**decimals();
} else {
revert("Maximum level reached");
}
require(balanceOf(msg.sender) >= cost, "Insufficient GEM balance");
_transfer(msg.sender, treasury, cost);
if (currentLevel == 7200) {
_transportationLevel[msg.sender] = 10800;
} else if (currentLevel == 10800) {
_transportationLevel[msg.sender] = 14400;
} else if (currentLevel == 14400) {
_transportationLevel[msg.sender] = 21600;
} else if (currentLevel == 21600) {
_transportationLevel[msg.sender] = 28800;
} else if (currentLevel == 28800) {
_transportationLevel[msg.sender] = 43200;
} else if (currentLevel == 43200) {
_transportationLevel[msg.sender] = 86400;
}
require(msg.value == purchaseUpgradeFee, "Incorrect Ether value sent for upgrade fee");
(bool sent, ) = purchaseUpgradeFeeRecipient.call{value: purchaseUpgradeFee}("");
require(sent, "Failed to send Ether");
}
}