编译器
0.8.19+commit.7dd6d404
文件 1 的 5: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 的 5:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
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);
}
文件 3 的 5: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());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
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);
}
}
文件 4 的 5:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 5 的 5:Staking.sol
pragma solidity ^0.8.19;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/utils/math/SafeMath.sol';
interface IUniswapV2Router {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function getAmountsOut(uint amountIn, address[] memory path) external view returns (uint[] memory amounts);
}
contract Staking is Ownable {
using SafeMath for uint256;
IUniswapV2Router public uniswapRouter;
IERC20 public token;
uint256 public stakingDuration = 15 days;
uint256 public withdrawalCooldown = 1 days;
uint256 public dailyWithdrawalLimitPercentage = 2;
address public penaltyWallet;
mapping(address => uint256) public stakes;
mapping(address => uint256) public ethValueOfStakes;
mapping(address => uint256) public lastDepositTime;
mapping(address => uint256) public lastETHWithdrawTime;
mapping(address => uint256) public totalETHWithdrawn;
event rewardWithdrawn(address indexed _user ,uint256 _amount, uint256 _claimDays);
event tokensStaked(address indexed _user ,uint256 _amount);
event tokensUnstaked(address indexed _user ,uint256 _amount);
event Received(address, uint256);
receive() external payable {
emit Received(msg.sender, msg.value);
}
modifier onlyToken() {
assert(msg.sender == address(token));
_;
}
constructor() {
uniswapRouter = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
}
function updateStakingDuration(uint256 _duration) external onlyOwner {
stakingDuration = _duration;
}
function updateWithdrawalCooldown(uint256 _cooldown) external onlyOwner {
withdrawalCooldown = _cooldown;
}
function setDailyWithdrawalLimit(uint256 _percentage) external onlyOwner {
require(_percentage <= 20, "Percentage must be less than 20%");
dailyWithdrawalLimitPercentage = _percentage;
}
function setTokenAddress(address _tokenAddress) external onlyOwner {
require(_tokenAddress != address(0), "Invalid address");
token = IERC20(_tokenAddress);
penaltyWallet = _tokenAddress;
}
function stakeTokens(address _user, uint _amount) external onlyToken {
require(_amount > 0, "Amount must be greater than 0");
uint256 ethValue = calculateTokenValueInETH(_amount);
stakes[_user] = stakes[_user].add(_amount);
ethValueOfStakes[_user] = ethValueOfStakes[_user].add(ethValue);
lastDepositTime[_user] = block.timestamp;
emit tokensStaked(_user,_amount);
if (lastETHWithdrawTime[_user] == 0){
lastETHWithdrawTime[_user] = block.timestamp;
}
}
function calculateTokenValueInETH(uint256 _amount) internal view returns (uint256) {
address[] memory path = new address[](2);
path[0] = address(token);
path[1] = uniswapRouter.WETH();
uint256[] memory amounts = uniswapRouter.getAmountsOut(_amount, path);
return amounts[1];
}
function calculateDailyWithdrawalLimit(address _user) internal view returns (uint256 total, uint256 daysSinceLastWithdrawal) {
uint256 ethValue = ethValueOfStakes[_user];
daysSinceLastWithdrawal = (block.timestamp.sub(lastETHWithdrawTime[_user])).div(withdrawalCooldown);
uint256 dailyLimit = ethValue.mul(dailyWithdrawalLimitPercentage).div(100);
total = dailyLimit.mul(daysSinceLastWithdrawal);
}
function withdrawReward() external {
require(stakes[msg.sender] > 0, "No tokens staked");
uint256 currentTime = block.timestamp;
require(currentTime >= lastETHWithdrawTime[msg.sender].add(withdrawalCooldown), "Cooldown period not passed");
(uint256 dailyWithdrawalAmount, uint256 claimDays) = calculateDailyWithdrawalLimit(msg.sender);
require(dailyWithdrawalAmount > 0, "No withdrawable amount available");
lastETHWithdrawTime[msg.sender] = currentTime;
totalETHWithdrawn[msg.sender] = totalETHWithdrawn[msg.sender].add(dailyWithdrawalAmount);
payable(msg.sender).transfer(dailyWithdrawalAmount);
emit rewardWithdrawn(msg.sender, dailyWithdrawalAmount, claimDays);
}
function unstakeTokens() external {
require(stakes[msg.sender] > 0, "No tokens staked");
uint256 withdrawTokens = 0;
uint256 stakedAmount = stakes[msg.sender];
if(block.timestamp <= lastDepositTime[msg.sender].add(stakingDuration)){
uint256 penalty = stakedAmount.mul(20).div(100);
withdrawTokens = stakedAmount.sub(penalty);
token.transfer(penaltyWallet, penalty);
}
else{
withdrawTokens = stakedAmount;
}
stakes[msg.sender] = 0;
ethValueOfStakes[msg.sender] = 0;
token.transfer(msg.sender, withdrawTokens);
emit tokensUnstaked(msg.sender, withdrawTokens);
}
function getUserStake(address _user) external view returns (uint256 totalStakedTokens, uint256 totalrewardwithdrawn, uint256 ethValueOfStake, uint256 remainingDays) {
totalStakedTokens = stakes[_user];
ethValueOfStake = ethValueOfStakes[_user];
uint256 currentTime = block.timestamp;
totalrewardwithdrawn = totalETHWithdrawn[_user];
if (currentTime < lastDepositTime[_user].add(stakingDuration)) {
remainingDays = (lastDepositTime[_user].add(stakingDuration).sub(currentTime)).div(1 days);
} else {
remainingDays = 0;
}
}
function emergencyWithdrawERC20(IERC20 erc20) external onlyOwner {
uint256 balanceToken = erc20.balanceOf(address(this));
erc20.transfer(owner(), balanceToken);
}
function emergencyWithdrawETH() external onlyOwner {
uint256 balanceETH = address(this).balance;
payable(msg.sender).transfer(balanceETH);
}
}
{
"compilationTarget": {
"Staking.sol": "Staking"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"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":"","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_claimDays","type":"uint256"}],"name":"rewardWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"tokensStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"tokensUnstaked","type":"event"},{"inputs":[],"name":"dailyWithdrawalLimitPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"erc20","type":"address"}],"name":"emergencyWithdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ethValueOfStakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getUserStake","outputs":[{"internalType":"uint256","name":"totalStakedTokens","type":"uint256"},{"internalType":"uint256","name":"totalrewardwithdrawn","type":"uint256"},{"internalType":"uint256","name":"ethValueOfStake","type":"uint256"},{"internalType":"uint256","name":"remainingDays","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastDepositTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastETHWithdrawTime","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":"penaltyWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_percentage","type":"uint256"}],"name":"setDailyWithdrawalLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"setTokenAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stakeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalETHWithdrawn","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":"uniswapRouter","outputs":[{"internalType":"contract IUniswapV2Router","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unstakeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"updateStakingDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cooldown","type":"uint256"}],"name":"updateWithdrawalCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]