// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; contract NTAKE is Ownable, ReentrancyGuard { using SafeMath for uint256; IERC20 public navisToken; mapping(address => uint256) public stakedBalances; mapping(address => uint256) public lastStakeTimestamp; uint256 public constant BONUS_PERIOD = 30 days; uint256 public constant BONUS_MULTIPLIER = 2; // Bonus multiplier for the first 30 days uint256 public constant UNSTAKING_PERIOD = 7 days; uint256 public constant PENALTY_MULTIPLIER = 2; // Penalty multiplier for unstaking within 7 days event Staked(address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 stakedAmount, uint256 receivedAmount); constructor(address _navisToken) { navisToken = IERC20(_navisToken); } function stake(uint256 amount) external nonReentrant { require(amount > 0, "Amount must be greater than zero"); // Calculate bonus for early stakers uint256 bonusMultiplier = (block.timestamp.sub(lastStakeTimestamp[msg.sender]) <= BONUS_PERIOD) ? BONUS_MULTIPLIER : 1; uint256 stakingAmount = amount.mul(bonusMultiplier); require(navisToken.transferFrom(msg.sender, address(this), stakingAmount), "Transfer failed"); stakedBalances[msg.sender] = stakedBalances[msg.sender].add(stakingAmount); lastStakeTimestamp[msg.sender] = block.timestamp; emit Staked(msg.sender, stakingAmount); } function withdraw(uint256 amount) external nonReentrant { require(amount > 0, "Amount must be greater than zero"); require(amount <= stakedBalances[msg.sender], "Insufficient staked balance"); uint256 stakedAmount = stakedBalances[msg.sender]; uint256 withdrawalAmount = calculateWithdrawalAmount(stakedAmount, amount); // Apply penalty for early unstaking if (block.timestamp.sub(lastStakeTimestamp[msg.sender]) < UNSTAKING_PERIOD) { uint256 penalty = amount.mul(PENALTY_MULTIPLIER).div(100); withdrawalAmount = withdrawalAmount.sub(penalty); } stakedBalances[msg.sender] = stakedBalances[msg.sender].sub(withdrawalAmount); navisToken.transfer(msg.sender, withdrawalAmount); emit Withdrawn(msg.sender, stakedAmount, withdrawalAmount); } function calculateWithdrawalAmount(uint256 stakedAmount, uint256 requestedAmount) internal view returns (uint256) { // Implement your withdrawal logic, considering any fees or conditions // This function can be customized based on your specific requirements return requestedAmount; } }