文件 1 的 8:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 8:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 8:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, 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 from,
address to,
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);
}
文件 4 的 8:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_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 {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 5 的 8:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_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());
}
}
文件 6 的 8:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 7 的 8:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 8 的 8:Stake1Cat.sol
pragma solidity ^0.8.7;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
contract Stake1Cat is ReentrancyGuard, Ownable, Pausable {
using SafeERC20 for IERC20;
uint256[] public pointsSS = [11574074074075, 1653439153440, 385802469136, 128600823046, 32150205762];
uint256 private constant D1 = 1 days;
uint256 private constant D7 = 7 days;
uint256 private constant D8 = 8 days;
uint256 private constant D30 = 30 days;
uint256 private constant D38 = 38 days;
uint256 private constant D90 = 90 days;
uint256 private constant D128 = 128 days;
uint256 private constant D360 = 360 days;
address public tokenAddress;
uint256 public unStakeStartTime;
uint256 public unStakeEndTime;
bool public isTransfer;
address public transferAddress;
mapping(address => StakeInfo) private stakes;
struct StakeInfo {
uint256 lastTime;
uint256 amount;
}
event Stake(
address indexed sender,
uint256 amount
);
event UnStake(
address indexed sender,
uint256 amount
);
constructor(address _tokenAddress) {
tokenAddress = _tokenAddress;
}
function getStakeInfo(address addr) public virtual view returns (uint256 lastTime, uint256 amount, uint256 points){
StakeInfo memory info = stakes[addr];
lastTime = info.lastTime;
amount = info.amount;
points = getPoints(addr);
}
function getPoints(address sender) public virtual view returns (uint256 points){
points = getPoints(sender, block.timestamp);
}
function getPoints(address sender, uint256 timestamp) public virtual view returns (uint256 points){
StakeInfo memory info = stakes[sender];
if (info.lastTime > 0 && info.amount > 0) {
uint256 time = timestamp - info.lastTime;
if (time <= D1) {
points = (info.amount * time * pointsSS[0]) / 1e18;
} else if (time <= D8) {
points = info.amount * (D1 * pointsSS[0]
+ (time - D1) * pointsSS[1]) / 1e18;
} else if (time <= D38) {
points = info.amount * (D1 * pointsSS[0]
+ D7 * pointsSS[1]
+ (time - D8) * pointsSS[2]) / 1e18;
} else if (time <= D128) {
points = info.amount * (D1 * pointsSS[0]
+ D7 * pointsSS[1]
+ D30 * pointsSS[2]
+ (time - D38) * pointsSS[3]) / 1e18;
} else {
uint256 lTime = time - D128;
points = info.amount * (D1 * pointsSS[0]
+ D7 * pointsSS[1]
+ D30 * pointsSS[2]
+ D90 * pointsSS[3]
+ (lTime > D360 ? D360 : lTime) * pointsSS[4]) / 1e18;
}
} else points = 0;
}
function getLadder(uint256 amount, uint256 points) public view returns (uint256){
uint256 l1 = amount * D1 * pointsSS[0];
if (points <= l1 / 1e18) return 1;
uint256 l2 = l1 + amount * D7 * pointsSS[1];
if (points <= l2 / 1e18) return 2;
uint256 l3 = l2 + amount * D30 * pointsSS[2];
if (points <= l3 / 1e18) return 3;
uint256 l4 = l3 + amount * D90 * pointsSS[3];
if (points <= l4 / 1e18) return 4;
else return 5;
}
function getLastTime(uint256 amount, uint256 points, uint256 timestamp) public view returns (uint256 lastTime){
uint256 ladder = getLadder(amount, points);
if (ladder == 1) {
lastTime = timestamp - (points * 1e18 / amount / pointsSS[0]);
} else if (ladder == 2) {
lastTime = timestamp - ((points * 1e18 - amount * D1 * pointsSS[0])
/ amount / pointsSS[1] + D1);
} else if (ladder == 3) {
lastTime = timestamp - ((points * 1e18 - amount * (D1 * pointsSS[0] + D7 * pointsSS[1]))
/ amount / pointsSS[2] + D8);
} else if (ladder == 4) {
lastTime = timestamp - ((points * 1e18 - amount * (D1 * pointsSS[0] + D7 * pointsSS[1]
+ D30 * pointsSS[2]))
/ amount / pointsSS[3] + D38);
} else {
lastTime = timestamp - ((points * 1e18 - amount * (D1 * pointsSS[0] + D7 * pointsSS[1]
+ D30 * pointsSS[2] + D90 * pointsSS[3]))
/ amount / pointsSS[4] + D128);
}
}
function stakeBatch(
address[] memory tos,
uint256[] memory amounts
) public virtual {
require(tos.length == amounts.length, "length error");
uint256 amount;
for (uint256 i = 0; i < amounts.length; i++) {
amount += amounts[i];
_stake(tos[i], amounts[i]);
}
IERC20 token = IERC20(tokenAddress);
token.safeTransferFrom(_msgSender(), address(this), amount);
}
function stake(uint256 _amount) public virtual {
require(_amount > 0, 'Error: _amount == 0');
IERC20 token = IERC20(tokenAddress);
token.safeTransferFrom(_msgSender(), address(this), _amount);
_stake(_msgSender(), _amount);
}
function _stake(address _sender, uint256 _amount) internal virtual whenNotPaused {
uint256 points = getPoints(_sender);
StakeInfo storage info = stakes[_sender];
info.amount += _amount;
info.lastTime = getLastTime(info.amount, points, block.timestamp);
emit Stake(_sender, _amount);
}
function _unStake(address _receiver, uint256 _amount) internal virtual {
StakeInfo storage info = stakes[msg.sender];
require(_amount > 0 && _amount <= info.amount, 'Error: _amount');
info.amount -= _amount;
IERC20 token = IERC20(tokenAddress);
token.safeTransfer(_receiver, _amount);
emit UnStake(msg.sender, _amount);
}
function unStake(uint256 _amount) external whenNotPaused {
require(block.timestamp >= unStakeStartTime && block.timestamp <= unStakeEndTime, 'Error: Time not arrived');
_unStake(msg.sender, _amount);
}
function transfer(uint256 _amount) external {
require(isTransfer, 'Error: Disabled');
_unStake(transferAddress, _amount);
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
function setTransfer(bool _isTransfer) public onlyOwner {
isTransfer = _isTransfer;
}
function setTransferAddress(address _transferAddress) public onlyOwner {
require(_transferAddress != address(0), 'Error: Zero address');
transferAddress = _transferAddress;
}
function setUnStakeTime(uint256 _unStakeStartTime, uint256 _unStakeEndTime) public onlyOwner {
require(_unStakeEndTime > _unStakeStartTime, 'Error');
unStakeStartTime = _unStakeStartTime;
unStakeEndTime = _unStakeEndTime;
}
function emergencyWithdrawEther() public onlyOwner {
payable(msg.sender).transfer(address(this).balance);
}
function emergencyWithdrawErc20(address _tokenAddress) public onlyOwner {
IERC20 token = IERC20(_tokenAddress);
token.safeTransfer(msg.sender, token.balanceOf(address(this)));
}
}
{
"compilationTarget": {
"contracts/stake/Stake1Cat.sol": "Stake1Cat"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 999999
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"emergencyWithdrawErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"points","type":"uint256"}],"name":"getLadder","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"points","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getLastTime","outputs":[{"internalType":"uint256","name":"lastTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPoints","outputs":[{"internalType":"uint256","name":"points","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"getPoints","outputs":[{"internalType":"uint256","name":"points","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getStakeInfo","outputs":[{"internalType":"uint256","name":"lastTime","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"points","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pointsSS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isTransfer","type":"bool"}],"name":"setTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_transferAddress","type":"address"}],"name":"setTransferAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unStakeStartTime","type":"uint256"},{"internalType":"uint256","name":"_unStakeEndTime","type":"uint256"}],"name":"setUnStakeTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tos","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"stakeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unStakeEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unStakeStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]