// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; contract SellTixICO is Ownable, ReentrancyGuard { using SafeMath for uint256; IERC20 public token; uint256 public constant TEAM_ALLOCATION = 15_000_000 * 10**18; // 15% uint256 public constant PUBLIC_SALE = 30_000_000 * 10**18; // 30% uint256 public constant PLATFORM_DEV = 20_000_000 * 10**18; // 20% uint256 public constant MARKETING = 15_000_000 * 10**18; // 15% uint256 public constant COMMUNITY_REWARDS = 10_000_000 * 10**18; // 10% uint256 public constant LIQUIDITY = 10_000_000 * 10**18; // 10% uint256 public icoStartTime; uint256 public icoEndTime; uint256 public tokenPrice; // in wei mapping(address => uint256) public teamVesting; mapping(address => uint256) public publicSaleVesting; mapping(address => uint256) public platformVesting; mapping(address => uint256) public marketingVesting; event TokensPurchased(address buyer, uint256 amount); event TokensVested(address beneficiary, uint256 amount); constructor(address _token, uint256 _tokenPrice) { token = IERC20(_token); tokenPrice = _tokenPrice; } function startICO(uint256 _duration) external onlyOwner { icoStartTime = block.timestamp; icoEndTime = block.timestamp.add(_duration); } function buyTokens() external payable nonReentrant { require(block.timestamp >= icoStartTime && block.timestamp <= icoEndTime, "ICO not active"); require(msg.value > 0, "Invalid amount"); uint256 tokens = msg.value.mul(10**18).div(tokenPrice); require(tokens <= PUBLIC_SALE, "Exceeds available tokens"); // 40% unlocked immediately uint256 unlockedTokens = tokens.mul(40).div(100); uint256 vestedTokens = tokens.sub(unlockedTokens); token.transfer(msg.sender, unlockedTokens); publicSaleVesting[msg.sender] = publicSaleVesting[msg.sender].add(vestedTokens); emit TokensPurchased(msg.sender, tokens); } function claimVestedTokens() external nonReentrant { uint256 claimableAmount = getClaimableTokens(msg.sender); require(claimableAmount > 0, "No tokens to claim"); if (publicSaleVesting[msg.sender] > 0) { publicSaleVesting[msg.sender] = 0; } token.transfer(msg.sender, claimableAmount); emit TokensVested(msg.sender, claimableAmount); } function getClaimableTokens(address _beneficiary) public view returns (uint256) { if (block.timestamp < icoEndTime.add(180 days)) { return 0; } return publicSaleVesting[_beneficiary]; } }