creation_sourcecode: // SPDX-License-Identifier: MIT
  
  pragma solidity ^0.8.26;
  
  
  library Address {
      function isContract(address account) internal view returns (bool) {
          uint256 size;
          assembly { size := extcodesize(account) }
          return size > 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);
              }
          }
      }
  }
  
  /**
   * @dev Wrappers over Solidity's arithmetic operations.
   * NOTE: SafeMath is no longer needed starting with Solidity 0.8. The compiler
   * now has built in overflow checking.
   */
  library SafeMath {
      function add(uint256 a, uint256 b) internal pure returns (uint256) {
          uint256 c = a + b;
          require(c >= a, "SafeMath: addition overflow");
  
          return c;
      }
  
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
          require(b <= a, "SafeMath: subtraction overflow");
          uint256 c = a - b;
  
          return c;
      }
  
      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
          if (a == 0) {
              return 0;
          }
  
          uint256 c = a * b;
          require(c / a == b, "SafeMath: multiplication overflow");
  
          return c;
      }
  
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
          require(b > 0, "SafeMath: division by zero");
          uint256 c = a / b;
  
          return c;
      }
  
      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
          require(b != 0, "SafeMath: modulo by zero");
          return a % b;
      }
  }
  
  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);
  }
  
  library SafeERC20 {
      using SafeMath for uint256;
      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).add(value);
          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
      }
  
      function safeDecreaseAllowance(
          IERC20 token,
          address spender,
          uint256 value
      ) internal {
          uint256 newAllowance = token.allowance(address(this), spender).sub(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");
          }
      }
  }
  
  contract SimpleStaking {
      using SafeERC20 for IERC20;
      using SafeMath for uint256;
  
      address public owner;
      uint256 public initialTimestamp;
      bool public timestampSet;
      uint256 public timePeriod;
      uint256 public constant initialStakingPeriod = 7 days;
      uint256 public constant lockUpPeriod = 90 days;
      bool private locked;
  
      mapping(address => uint256) public alreadyWithdrawn;
      mapping(address => uint256) public balances;
      uint256 public contractBalance;
  
      IERC20 public erc20Contract;
  
      event TokensStaked(address indexed from, uint256 amount);
      event TokensUnstaked(address indexed to, uint256 amount);
  
      constructor(address _erc20Contract) {
          owner = msg.sender;
          timestampSet = false;
          erc20Contract = IERC20(_erc20Contract);
          locked = false;
      }
  
      modifier noReentrant() {
          require(!locked, "No re-entrancy");
          locked = true;
          _;
          locked = false;
      }
  
      modifier onlyOwner() {
          require(msg.sender == owner, "Caller is not the owner");
          _;
      }
  
      modifier timestampNotSet() {
          require(!timestampSet, "Timestamp already set");
          _;
      }
  
      modifier timestampIsSet() {
          require(timestampSet, "Timestamp not set");
          _;
      }
  
      function setTimestamp(uint256 _timePeriodInSeconds) public onlyOwner timestampNotSet {
          require(_timePeriodInSeconds == initialStakingPeriod, "Initial staking period must be 7 days");
          timestampSet = true;
          initialTimestamp = block.timestamp;
          timePeriod = initialTimestamp.add(lockUpPeriod);
      }
  
      function stakeTokens(uint256 amount) public timestampIsSet noReentrant {
          require(amount <= erc20Contract.balanceOf(msg.sender), "Insufficient token balance");
          erc20Contract.safeTransferFrom(msg.sender, address(this), amount);
          balances[msg.sender] = balances[msg.sender].add(amount);
          emit TokensStaked(msg.sender, amount);
      }
  
      function unstakeTokens(uint256 amount) public timestampIsSet noReentrant {
          require(balances[msg.sender] >= amount, "Insufficient staked balance");
          if (block.timestamp >= timePeriod) {
              alreadyWithdrawn[msg.sender] = alreadyWithdrawn[msg.sender].add(amount);
              balances[msg.sender] = balances[msg.sender].sub(amount);
              erc20Contract.safeTransfer(msg.sender, amount);
              emit TokensUnstaked(msg.sender, amount);
          } else {
              revert("Tokens are locked");
          }
      }
  
      function transferAccidentallyLockedTokens(IERC20 token, uint256 amount) public onlyOwner noReentrant {
          require(address(token) != address(0), "Token address is zero");
          require(token != erc20Contract, "Cannot transfer staked token");
          token.safeTransfer(owner, amount);
      }
  }