Staking

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);
    }
}

Tags:
addr:0xce8d85f7360b1dc38663a04648251153bd94a31f|verified:true|block:23459789|tx:0xc7fa867faca4207dc04e45d869af9d61e9689a2f1df946c4c46fd1c0a78050bc|first_check:1759052208

Submitted on: 2025-09-28 11:36:48

Comments

Log in to comment.

No comments yet.