// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Import ERC20 interface and other necessary contracts import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract VPNIDGenerator is Ownable { IERC20 public sVPNToken; uint256 public nextID; uint256 constant public IDLength = 15; uint256 public paymentAmountMonthly = 200000; // Default monthly payment amount uint256 public paymentAmountYearly = 2200000; // Default yearly payment amount, assuming some discount or different rate event IDGenerated(address indexed payer, string indexed generatedID, string paymentType); event TokenContractUpdated(address indexed newTokenContract); event MonthlyPaymentAmountUpdated(uint256 newPaymentAmount); event YearlyPaymentAmountUpdated(uint256 newPaymentAmount); mapping(address => string[]) public userIDs; // Mapping to store user IDs against wallet address mapping(string => bool) public usedIDs; // Mapping to track used IDs constructor(address _sVPNTokenAddress, address initialOwner) Ownable(initialOwner) { sVPNToken = IERC20(_sVPNTokenAddress); nextID = 1; } modifier validPayment(uint256 paymentAmount) { require(sVPNToken.allowance(msg.sender, address(this)) >= paymentAmount, "Insufficient allowance"); require(sVPNToken.balanceOf(msg.sender) >= paymentAmount, "Insufficient balance"); _; } function payForUniqueIDMonthly() external validPayment(paymentAmountMonthly) { require(sVPNToken.transferFrom(msg.sender, address(this), paymentAmountMonthly), "Token transfer failed"); string memory generatedID = generateUniqueID(); userIDs[msg.sender].push(generatedID); emit IDGenerated(msg.sender, generatedID, "Monthly"); } function payForUniqueIDYearly() external validPayment(paymentAmountYearly) { require(sVPNToken.transferFrom(msg.sender, address(this), paymentAmountYearly), "Token transfer failed"); string memory generatedID = generateUniqueID(); userIDs[msg.sender].push(generatedID); emit IDGenerated(msg.sender, generatedID, "Yearly"); } function generateUniqueID() internal returns (string memory) { bytes memory characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; bytes memory result = new bytes(IDLength); uint256 rand = uint256(keccak256(abi.encodePacked(block.timestamp, block.difficulty, nextID))) % characters.length; for (uint256 i = 0; i < IDLength; i++) { if (i == IDLength - 1) { result[i] = bytes1(uint8(48 + (rand % 10))); // ASCII code for numbers 0-9 } else { result[i] = characters[rand % characters.length]; } rand = rand / characters.length; } string memory newID = string(result); // Check if the ID already exists, regenerate if necessary while (usedIDs[newID]) { rand = uint256(keccak256(abi.encodePacked(rand))) % characters.length; for (uint256 i = 0; i < IDLength; i++) { if (i == IDLength - 1) { result[i] = bytes1(uint8(48 + (rand % 10))); // ASCII code for numbers 0-9 } else { result[i] = characters[rand % characters.length]; } rand = rand / characters.length; } newID = string(result); } usedIDs[newID] = true; nextID++; return newID; } function getUserIDs(address userAddress) external view returns (string[] memory) { return userIDs[userAddress]; } function withdrawTokens(uint256 _amount) external onlyOwner { require(sVPNToken.transfer(owner(), _amount), "Token transfer failed"); } function updateTokenContract(address _newTokenContract) external onlyOwner { require(_newTokenContract != address(0), "Invalid token contract address"); sVPNToken = IERC20(_newTokenContract); emit TokenContractUpdated(_newTokenContract); } function updateMonthlyPaymentAmount(uint256 _newPaymentAmount) external onlyOwner { require(_newPaymentAmount > 0, "Invalid payment amount"); paymentAmountMonthly = _newPaymentAmount; emit MonthlyPaymentAmountUpdated(_newPaymentAmount); } function updateYearlyPaymentAmount(uint256 _newPaymentAmount) external onlyOwner { require(_newPaymentAmount > 0, "Invalid payment amount"); paymentAmountYearly = _newPaymentAmount; emit YearlyPaymentAmountUpdated(_newPaymentAmount); } }