Description:
Smart contract deployed on Ethereum.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
contract ReentrancyGuard {
uint256 private _status = 1;
modifier nonReentrant() {
require(_status == 1, "Reentrant call");
_status = 2;
_;
_status = 1;
}
}
contract Staking is ReentrancyGuard {
IERC20 public immutable token;
struct StakeInfo {
uint256 amount;
uint256 lockupPeriod;
uint256 lockedUntil;
}
mapping(address => StakeInfo) public stakes;
mapping(uint256 => uint256) public lockupRewardPercents;
address public admin;
modifier onlyAdmin() {
require(msg.sender == admin, "Not admin");
_;
}
event Staked(address indexed user, uint256 amount, uint256 lockupPeriod);
event Withdrawn(address indexed user, uint256 amount, uint256 reward);
constructor(address _token) {
require(_token != address(0), "Invalid token");
token = IERC20(_token);
admin = msg.sender;
lockupRewardPercents[15 days] = 5;
lockupRewardPercents[30 days] = 15;
lockupRewardPercents[60 days] = 35;
lockupRewardPercents[90 days] = 55;
lockupRewardPercents[180 days] = 115;
lockupRewardPercents[365 days] = 230;
}
function setAdmin(address newAdmin) external onlyAdmin {
require(newAdmin != address(0), "Zero address");
admin = newAdmin;
}
function setLockupRewardPercent(uint256 period, uint256 percent) external onlyAdmin {
lockupRewardPercents[period] = percent;
}
function stake(uint256 amount, uint256 lockupPeriod) external nonReentrant {
require(amount > 0, "Amount zero");
require(lockupRewardPercents[lockupPeriod] > 0, "Invalid lockup");
StakeInfo storage s = stakes[msg.sender];
require(s.amount == 0 || block.timestamp >= s.lockedUntil, "Existing stake locked");
bool success = token.transferFrom(msg.sender, address(this), amount);
require(success, "TransferFrom failed");
s.amount = amount;
s.lockupPeriod = lockupPeriod;
s.lockedUntil = block.timestamp + lockupPeriod;
emit Staked(msg.sender, amount, lockupPeriod);
}
function withdraw() external nonReentrant {
StakeInfo storage s = stakes[msg.sender];
require(s.amount > 0, "No stake");
require(block.timestamp >= s.lockedUntil, "Lockup not ended");
uint256 principal = s.amount;
uint256 rewardPercent = lockupRewardPercents[s.lockupPeriod];
uint256 reward = (principal * rewardPercent) / 100;
s.amount = 0;
s.lockupPeriod = 0;
s.lockedUntil = 0;
bool success = token.transfer(msg.sender, principal + reward);
require(success, "Transfer failed");
emit Withdrawn(msg.sender, principal, reward);
}
}
Submitted on: 2025-09-28 11:36:48
Comments
Log in to comment.
No comments yet.