编译器
0.8.10+commit.fc410830
文件 1 的 7: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;
}
}
文件 2 的 7:ERC20.sol
pragma solidity ^0.8.0;
import "IERC20.sol";
import "IERC20Metadata.sol";
import "Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
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 virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual 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");
unchecked {
_approve(sender, _msgSender(), currentAllowance - amount);
}
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
uint256 currentAllowance = _allowances[_msgSender()][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(_msgSender(), spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[sender] = senderBalance - amount;
}
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
_afterTokenTransfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
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 {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 3 的 7:ERC20Burnable.sol
pragma solidity ^0.8.0;
import "ERC20.sol";
import "Context.sol";
abstract contract ERC20Burnable is Context, ERC20 {
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
function burnFrom(address account, uint256 amount) public virtual {
uint256 currentAllowance = allowance(account, _msgSender());
require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance");
unchecked {
_approve(account, _msgSender(), currentAllowance - amount);
}
_burn(account, amount);
}
}
文件 4 的 7: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 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);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 7:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 6 的 7:Ownable.sol
pragma solidity ^0.8.0;
import "Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_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);
}
}
文件 7 的 7:Staking.sol
pragma solidity ^0.8.10;
import "Ownable.sol";
import "ERC20Burnable.sol";
contract Staking is Ownable {
address public stakeToken;
address public treasure;
uint public unHoldFee;
uint public minStakeAmount;
uint public zeroRewardTimePercent;
bool public paused=true;
struct StakeData {
uint stakeAmount;
uint startTimestamp;
uint stakeTime;
bool active;
}
mapping(address => StakeData) public stakes;
event Stake(address indexed staker, uint stakeAmountIn, uint stakeTime);
event Withdraw(address indexed staker, uint stakeAmountOut);
mapping (uint => uint) public timeReward;
constructor(address stakeToken_, address treasure_, uint zeroRewardTimePercent_, uint minStakeAmount_) {
require(
stakeToken_ != address(0)
&& treasure_ != address(0),
"Staking::initialize: address is 0"
);
stakeToken = stakeToken_;
treasure = treasure_;
minStakeAmount = minStakeAmount_;
unHoldFee = 30e18;
zeroRewardTimePercent = zeroRewardTimePercent_;
timeReward[90 days] = 20e18;
timeReward[180 days] = 40e18;
timeReward[360 days] = 60e18;
timeReward[720 days] = 60e18;
}
function updateZeroRewardTimePercent(uint _newPercent) public onlyOwner returns (bool) {
zeroRewardTimePercent = _newPercent;
return true;
}
function updateTimeReward(uint stakeTime, uint percentReward) public onlyOwner returns (bool) {
timeReward[stakeTime] = percentReward;
return true;
}
function setTreasure(address treasure_) public onlyOwner returns (bool) {
treasure = treasure_;
return true;
}
function setPause(bool paused_) public onlyOwner returns (bool) {
paused = paused_;
return true;
}
function updateMinStakeAmount(uint amount_) public onlyOwner returns (bool) {
minStakeAmount = amount_;
return true;
}
function stake(uint tokenAmount, uint stakeTime) public returns (bool) {
require(!paused, "Staking::stake: stake is paused");
uint rewardPercent = timeReward[stakeTime];
require(rewardPercent != 0, "Staking::stake:rewardPercent must be more than 0");
address staker = msg.sender;
require(!stakes[staker].active, "Staking::stake:stake must be not active");
stakes[staker].active = true;
uint amountIn = doTransferIn(staker, stakeToken, tokenAmount);
require(amountIn > minStakeAmount, "Staking::stake: stake amount must be more than minStakeAmount");
uint timestamp = getBlockTimestamp();
stakes[staker].startTimestamp = timestamp;
stakes[staker].stakeTime = stakeTime;
stakes[staker].stakeAmount = amountIn;
emit Stake(staker, amountIn, stakeTime);
return true;
}
function withdraw() external {
address staker = msg.sender;
require(stakes[staker].active, "Staking::withdraw: stake must be active");
stakes[staker].active = false;
(uint amountOut, uint feeAmount) = calcOutAmount(staker);
if (feeAmount > 0) {
uint transferOutAmount = feeAmount / 2;
ERC20Burnable(stakeToken).burn(transferOutAmount);
ERC20Burnable(stakeToken).transfer(treasure, transferOutAmount);
}
doTransferOut(stakeToken, staker, amountOut);
emit Withdraw(staker, amountOut);
}
function calcFee(uint stakeAmount, uint currentTimestamp, uint startTimestamp, uint stakeTime) public view returns (uint) {
uint delta = (currentTimestamp - startTimestamp);
if (stakeTime <= delta) {
return 0;
}
return stakeAmount * unHoldFee * (stakeTime - delta) / stakeTime / 100e18;
}
function getStake(address user) public view returns (StakeData memory) {
return stakes[user];
}
function calcOutAmount(address staker) public view returns (uint, uint) {
uint stakeAmount = stakes[staker].stakeAmount;
uint startTimestamp = stakes[staker].startTimestamp;
uint stakeTime = stakes[staker].stakeTime;
uint currentTimestamp = getBlockTimestamp();
uint feeAmount = calcFee(stakeAmount, currentTimestamp, startTimestamp, stakeTime);
uint amountOut;
if (feeAmount > 0) {
amountOut = stakeAmount - feeAmount;
}
else {
uint endZeroRewardPeriod = (startTimestamp + stakeTime) + stakeTime * zeroRewardTimePercent / 100;
if(currentTimestamp <= endZeroRewardPeriod) {
amountOut = stakeAmount;
}
else {
amountOut = stakeAmount + (stakeAmount * timeReward[stakeTime] / 100e18);
}
}
return(amountOut, feeAmount);
}
function getBlockTimestamp() internal virtual view returns (uint) {
return block.timestamp;
}
function doTransferIn(address from, address token, uint amount) internal returns (uint) {
uint balanceBefore = ERC20(token).balanceOf(address(this));
ERC20(token).transferFrom(from, address(this), amount);
bool success;
assembly {
switch returndatasize()
case 0 {
success := not(0)
}
case 32 {
returndatacopy(0, 0, 32)
success := mload(0)
}
default {
revert(0, 0)
}
}
require(success, "TOKEN_TRANSFER_IN_FAILED");
uint balanceAfter = ERC20(token).balanceOf(address(this));
require(balanceAfter >= balanceBefore, "TOKEN_TRANSFER_IN_OVERFLOW");
return balanceAfter - balanceBefore;
}
function doTransferOut(address token, address to, uint amount) internal {
ERC20(token).transfer(to, amount);
bool success;
assembly {
switch returndatasize()
case 0 {
success := not(0)
}
case 32 {
returndatacopy(0, 0, 32)
success := mload(0)
}
default {
revert(0, 0)
}
}
require(success, "TOKEN_TRANSFER_OUT_FAILED");
}
}
{
"compilationTarget": {
"Staking.sol": "Staking"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"stakeToken_","type":"address"},{"internalType":"address","name":"treasure_","type":"address"},{"internalType":"uint256","name":"zeroRewardTimePercent_","type":"uint256"},{"internalType":"uint256","name":"minStakeAmount_","type":"uint256"}],"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":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeAmountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakeTime","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeAmountOut","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"uint256","name":"stakeAmount","type":"uint256"},{"internalType":"uint256","name":"currentTimestamp","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"stakeTime","type":"uint256"}],"name":"calcFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"calcOutAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getStake","outputs":[{"components":[{"internalType":"uint256","name":"stakeAmount","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"stakeTime","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct Staking.StakeData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minStakeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused_","type":"bool"}],"name":"setPause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"treasure_","type":"address"}],"name":"setTreasure","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"stakeTime","type":"uint256"}],"name":"stake","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"stakeAmount","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"stakeTime","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"timeReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasure","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unHoldFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"updateMinStakeAmount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeTime","type":"uint256"},{"internalType":"uint256","name":"percentReward","type":"uint256"}],"name":"updateTimeReward","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPercent","type":"uint256"}],"name":"updateZeroRewardTimePercent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zeroRewardTimePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]