creation_sourcecode: //SPDX-License-Identifier: UNLICENSED
  pragma solidity 0.8.11;
  
  contract Context {
   
      constructor() {}
  
      function _msgSender() internal view returns (address payable) {
          return payable(msg.sender);
      }
  
      function _msgData() internal view returns (bytes memory) {
          this; 
          return msg.data;
      }
  }
  
  
  contract Ownable is Context {
      address private _owner;
  
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
  
     
      constructor() {
          address msgSender = _msgSender();
          _owner = msgSender;
          emit OwnershipTransferred(address(0), msgSender);
      }
  
     
      function owner() public view returns (address) {
          return _owner;
      }
  
      
      modifier onlyOwner() {
          require(_owner == _msgSender(), 'Ownable: caller is not the owner');
          _;
      }
  
     
      function renounceOwnership() public onlyOwner {
          emit OwnershipTransferred(_owner, address(0));
          _owner = address(0);
      }
  
     
      function transferOwnership(address newOwner) public onlyOwner {
          _transferOwnership(newOwner);
      }
  
      function _transferOwnership(address newOwner) internal {
          require(newOwner != address(0), 'Ownable: new owner is the zero address');
          emit OwnershipTransferred(_owner, newOwner);
          _owner = newOwner;
      }
  }
  
  
  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) {
          return sub(a, b, 'SafeMath: subtraction overflow');
      }
  
      
      function sub(
          uint256 a,
          uint256 b,
          string memory errorMessage
      ) internal pure returns (uint256) {
          require(b <= a, errorMessage);
          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) {
          return div(a, b, 'SafeMath: division by zero');
      }
  
    
      function div(
          uint256 a,
          uint256 b,
          string memory errorMessage
      ) internal pure returns (uint256) {
          require(b > 0, errorMessage);
          uint256 c = a / b;
  
          return c;
      }
  
   
      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
          return mod(a, b, 'SafeMath: modulo by zero');
      }
  
      
      function mod(
          uint256 a,
          uint256 b,
          string memory errorMessage
      ) internal pure returns (uint256) {
          require(b != 0, errorMessage);
          return a % b;
      }
  
      function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
          z = x < y ? x : y;
      }
  
      function sqrt(uint256 y) internal pure returns (uint256 z) {
          if (y > 3) {
              z = y;
              uint256 x = y / 2 + 1;
              while (x < z) {
                  z = x;
                  x = (y / x + x) / 2;
              }
          } else if (y != 0) {
              z = 1;
          }
      }
  }
  
  interface IBEP20 {
     
      function totalSupply() external view returns (uint256);
  
      
      function decimals() external view returns (uint8);
  
      
      function symbol() external view returns (string memory);
  
    
      function name() external view returns (string memory);
  
      
      function getOwner() external view returns (address);
  
     
      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 SafeBEP20 {
      using SafeMath for uint256;
      using Address for address;
  
      function safeTransfer(
          IBEP20 token,
          address to,
          uint256 value
      ) internal {
          _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
      }
  
      function safeTransferFrom(
          IBEP20 token,
          address from,
          address to,
          uint256 value
      ) internal {
          _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
      }
  
      
      function safeApprove(
          IBEP20 token,
          address spender,
          uint256 value
      ) internal {
    
          require(
              (value == 0) || (token.allowance(address(this), spender) == 0),
              'SafeBEP20: approve from non-zero to non-zero allowance'
          );
          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
      }
  
      function safeIncreaseAllowance(
          IBEP20 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(
          IBEP20 token,
          address spender,
          uint256 value
      ) internal {
          uint256 newAllowance = token.allowance(address(this), spender).sub(
              value,
              'SafeBEP20: decreased allowance below zero'
          );
          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
      }
  
      function _callOptionalReturn(IBEP20 token, bytes memory data) private {
      
  
          bytes memory returndata = address(token).functionCall(data, 'SafeBEP20: low-level call failed');
          if (returndata.length > 0) {
              
              require(abi.decode(returndata, (bool)), 'SafeBEP20: BEP20 operation did not succeed');
          }
      }
  }
  
  
  library Address {
    
      function isContract(address account) internal view returns (bool) {
         
          bytes32 codehash;
          bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
          assembly {
              codehash := extcodehash(account)
          }
          return (codehash != accountHash && codehash != 0x0);
      }
  
      
      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');
          return _functionCallWithValue(target, data, value, errorMessage);
      }
  
      function _functionCallWithValue(
          address target,
          bytes memory data,
          uint256 weiValue,
          string memory errorMessage
      ) private returns (bytes memory) {
          require(isContract(target), 'Address: call to non-contract');
  
          (bool success, bytes memory returndata) = target.call{value: weiValue}(data);
          if (success) {
              return returndata;
          } else {
              if (returndata.length > 0) {
  
                  
                  assembly {
                      let returndata_size := mload(returndata)
                      revert(add(32, returndata), returndata_size)
                  }
              } else {
                  revert(errorMessage);
              }
          }
      }
  }
  
  abstract contract ReentrancyGuard {
     
  
      
      uint256 private constant _NOT_ENTERED = 1;
      uint256 private constant _ENTERED = 2;
  
      uint256 private _status;
  
      constructor() {
          _status = _NOT_ENTERED;
      }
  
     
      modifier nonReentrant() {
          require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
  
          
          _status = _ENTERED;
  
          _;
  
        
          _status = _NOT_ENTERED;
      }
  }
  
  contract AZHMstake is Ownable, ReentrancyGuard {
      using SafeMath for uint256;
      using SafeBEP20 for IBEP20;
  
   
      struct UserInfo {
          uint256 amount;     
          uint256 rewardDebt; 
      }
  
   
      struct PoolInfo {
          IBEP20 lpToken;           
          uint256 allocPoint;       
          uint256 lastRewardTimestamp;  
          uint256 accTokensPerShare; 
      }
  
      IBEP20 public immutable stakingToken;
      IBEP20 public immutable rewardToken;
      mapping (address => uint256) public holderUnlockTime;
  
      uint256 public totalStaked;
      uint256 public apy;
      uint256 public lockDuration;
      uint256 public exitPenaltyPerc;
  
      PoolInfo[] public poolInfo;
      mapping (address => UserInfo) public userInfo;
      uint256 private totalAllocPoint = 0;
  
      event Deposit(address indexed user, uint256 amount);
      event Withdraw(address indexed user, uint256 amount);
      event EmergencyWithdraw(address indexed user, uint256 amount);
  
      constructor(
      ) {
          stakingToken = IBEP20(0x99a2Ed4d7b703b61CDDcE7417F003c5A3171aCc5);
          rewardToken = stakingToken;
  
          apy = 300;
          lockDuration = 28 days;
          exitPenaltyPerc = 20;
  
          // staking pool
          poolInfo.push(PoolInfo({
              lpToken: stakingToken,
              allocPoint: 1000,
              lastRewardTimestamp: 99999999,
              accTokensPerShare: 0
          }));
  
          totalAllocPoint = 1000;
  
      }
  
      function stopReward() external onlyOwner {
          updatePool(0);
          apy = 0;
      }
  
      function startReward() external onlyOwner {
          require(poolInfo[0].lastRewardTimestamp == 99999999, "Can only start rewards once");
          poolInfo[0].lastRewardTimestamp = block.timestamp;
      }
  
      function pendingReward(address _user) external view returns (uint256) {
          PoolInfo storage pool = poolInfo[0];
          UserInfo storage user = userInfo[_user];
          if(pool.lastRewardTimestamp == 99999999){
              return 0;
          }
          uint256 accTokensPerShare = pool.accTokensPerShare;
          uint256 lpSupply = totalStaked;
          if (block.timestamp > pool.lastRewardTimestamp && lpSupply != 0) {
              uint256 tokenReward = calculateNewRewards().mul(pool.allocPoint).div(totalAllocPoint);
              accTokensPerShare = accTokensPerShare.add(tokenReward.mul(1e12).div(lpSupply));
          }
          return user.amount.mul(accTokensPerShare).div(1e12).sub(user.rewardDebt);
      }
  
      function updatePool(uint256 _pid) internal {
          PoolInfo storage pool = poolInfo[_pid];
          if (block.timestamp <= pool.lastRewardTimestamp) {
              return;
          }
          uint256 lpSupply = totalStaked;
          if (lpSupply == 0) {
              pool.lastRewardTimestamp = block.timestamp;
              return;
          }
          uint256 tokenReward = calculateNewRewards().mul(pool.allocPoint).div(totalAllocPoint);
          pool.accTokensPerShare = pool.accTokensPerShare.add(tokenReward.mul(1e12).div(lpSupply));
          pool.lastRewardTimestamp = block.timestamp;
      }
  
      function massUpdatePools() public onlyOwner {
          uint256 length = poolInfo.length;
          for (uint256 pid = 0; pid < length; ++pid) {
              updatePool(pid);
          }
      }
  
      function deposit(uint256 _amount) public nonReentrant {
          if(holderUnlockTime[msg.sender] == 0){
              holderUnlockTime[msg.sender] = block.timestamp + lockDuration;
          }
          PoolInfo storage pool = poolInfo[0];
          UserInfo storage user = userInfo[msg.sender];
  
          updatePool(0);
          if (user.amount > 0) {
              uint256 pending = user.amount.mul(pool.accTokensPerShare).div(1e12).sub(user.rewardDebt);
              if(pending > 0) {
                  require(pending <= rewardsRemaining(), "Cannot withdraw other people's staked tokens.  Contact an admin.");
                  rewardToken.safeTransfer(address(msg.sender), pending);
              }
          }
          uint256 amountTransferred = 0;
          if(_amount > 0) {
              uint256 initialBalance = pool.lpToken.balanceOf(address(this));
              pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
              amountTransferred = pool.lpToken.balanceOf(address(this)) - initialBalance;
              user.amount = user.amount.add(amountTransferred);
              totalStaked += amountTransferred;
          }
          user.rewardDebt = user.amount.mul(pool.accTokensPerShare).div(1e12);
  
          emit Deposit(msg.sender, _amount);
      }
  
      // Withdraw primary tokens from STAKING.
  
      function withdraw() public nonReentrant {
  
          require(holderUnlockTime[msg.sender] <= block.timestamp, "May not do normal withdraw early");
          
          PoolInfo storage pool = poolInfo[0];
          UserInfo storage user = userInfo[msg.sender];
  
          uint256 _amount = user.amount;
          updatePool(0);
          uint256 pending = user.amount.mul(pool.accTokensPerShare).div(1e12).sub(user.rewardDebt);
          if(pending > 0) {
              require(pending <= rewardsRemaining(), "Cannot withdraw other people's staked tokens.  Contact an admin.");
              rewardToken.safeTransfer(address(msg.sender), pending);
          }
  
          if(_amount > 0) {
              user.amount = 0;
              totalStaked -= _amount;
              pool.lpToken.safeTransfer(address(msg.sender), _amount);
          }
  
          user.rewardDebt = user.amount.mul(pool.accTokensPerShare).div(1e12);
          
          if(user.amount > 0){
              holderUnlockTime[msg.sender] = block.timestamp + lockDuration;
          } else {
              holderUnlockTime[msg.sender] = 0;
          }
  
          emit Withdraw(msg.sender, _amount);
      }
  
      function emergencyWithdraw() external nonReentrant {
          PoolInfo storage pool = poolInfo[0];
          UserInfo storage user = userInfo[msg.sender];
          uint256 _amount = user.amount;
          totalStaked -= _amount;
          if(holderUnlockTime[msg.sender] >= block.timestamp){
              _amount -= _amount * exitPenaltyPerc / 100;
          }
          holderUnlockTime[msg.sender] = 0;
          pool.lpToken.safeTransfer(address(msg.sender), _amount);
          user.amount = 0;
          user.rewardDebt = 0;
          emit EmergencyWithdraw(msg.sender, _amount);
      }
  
      function emergencyRewardWithdraw(uint256 _amount) external onlyOwner {
          require(_amount <= rewardToken.balanceOf(address(this)) - totalStaked, 'not enough tokens to take out');
          rewardToken.safeTransfer(address(msg.sender), _amount);
      }
      
  
      function calculateNewRewards() public view returns (uint256) {
          PoolInfo storage pool = poolInfo[0];
          if(pool.lastRewardTimestamp > block.timestamp){
              return 0;
          }
          return (((block.timestamp - pool.lastRewardTimestamp) * totalStaked) * apy / 100 / 365 days);
      }
  
      function rewardsRemaining() public view returns (uint256){
          return rewardToken.balanceOf(address(this)) - totalStaked;
      }
  
      function updateApy(uint256 newApy) external onlyOwner {
          require(newApy <= 1000, "APY must be below 1000%");
          updatePool(0);
          apy = newApy;
      }
  
      function updatelockduration(uint256 newlockDuration) external onlyOwner {
          require(newlockDuration <= 14838400, "Duration must be below 4 weeks");
          lockDuration = newlockDuration;
  
      }
  
      function updateExitPenalty(uint256 newPenaltyPerc) external onlyOwner {
          require(newPenaltyPerc <= 20, "May not set higher than 20%");
          exitPenaltyPerc = newPenaltyPerc;
      }
  }