// File: @openzeppelin/contracts/utils/math/SafeMath.sol


// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

// File: contracts/ALLUmain/ALLUmain2.sol/ALLUmain2.sol



pragma solidity ^0.8.0;


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);
}

contract ALLUTokenSale {
    using SafeMath for uint256;

    address public owner;
    uint256 public totalTokens;
    IERC20 public alluToken;

    mapping(address => uint256) public purchasedTokens;
    uint256 public capPerSale;
    uint256 public individualPurchaseCap;
    bool public paused;

    uint256 public constant TOKEN_DECIMALS = 18; // Number of decimal places in the token
    uint256 public constant TOKEN_PRICE = 1200000000000000; // 0.0000012 ETH per token

    address public spendingAccount1;
    address public spendingAccount2;

    event TokensPurchased(address buyer, uint256 amount, uint256 price, string currency);
    event TokensTransferred(address to, uint256 amount);
    event SalePaused();
    event SaleResumed();
    event CapPerSaleUpdated(uint256 newCapPerSale);
    event IndividualPurchaseCapUpdated(uint256 newIndividualPurchaseCap);
    event SpendingAccountsUpdated(address account1, address account2);

    modifier onlyOwner() {
        require(msg.sender == owner, "Only the contract owner can call this function.");
        _;
    }

    modifier whenNotPaused() {
        require(!paused, "Token sale is paused.");
        _;
    }

    constructor(address tokenAddress, address account1, address account2) {
        owner = msg.sender;
        totalTokens = 8_000_000_000_000 * (10 ** TOKEN_DECIMALS); // 8 trillion ALLU tokens
        alluToken = IERC20(tokenAddress);
        capPerSale = 10_000 ether;
        individualPurchaseCap = 5_000 ether;
        paused = false;
        spendingAccount1 = account1;
        spendingAccount2 = account2;
    }

    function buyTokens(uint256 amount, uint256 payment) external payable whenNotPaused {
        require(amount > 0, "Amount should be greater than zero.");
        require(totalTokens >= amount, "Insufficient tokens available");
        require(payment >= TOKEN_PRICE.mul(amount).div(10 ** TOKEN_DECIMALS), "Insufficient payment");

        require(purchasedTokens[msg.sender].add(amount) <= individualPurchaseCap, "Exceeded individual purchase cap");
        require(purchasedTokens[msg.sender].add(amount) <= capPerSale, "Exceeded cap per sale");

        totalTokens = totalTokens.sub(amount);
        purchasedTokens[msg.sender] = purchasedTokens[msg.sender].add(amount);

        alluToken.transfer(msg.sender, amount);

        uint256 paymentSplit = msg.value.div(2);
        if (spendingAccount1 != address(0) && spendingAccount2 != address(0)) {
            (bool success1, ) = payable(spendingAccount1).call{value: paymentSplit}("");
            (bool success2, ) = payable(spendingAccount2).call{value: paymentSplit}("");
            require(success1 && success2, "Failed to transfer Ether");
        }

        emit TokensPurchased(msg.sender, amount, TOKEN_PRICE, "ETH");
    }

    function updateSpendingAccounts(address account1, address account2) external onlyOwner {
        require(account1 != address(0) && account2 != address(0), "Spending accounts cannot be zero address");
        spendingAccount1 = account1;
        spendingAccount2 = account2;
        emit SpendingAccountsUpdated(account1, account2);
    }

    function withdraw(uint256 amount) external onlyOwner {
        require(amount <= address(this).balance, "Insufficient contract balance");
        payable(owner).transfer(amount);
    }

    function contractBalance() external view returns (uint256) {
        return address(this).balance;
    }

    function transferTokens(address to, uint256 amount) external onlyOwner {
        require(amount > 0, "Amount should be greater than zero.");
        require(amount <= totalTokens, "Insufficient tokens available");

        totalTokens = totalTokens.sub(amount);
        alluToken.transfer(to, amount);

        emit TokensTransferred(to, amount);
    }

    function updateCapPerSale(uint256 newCap) external onlyOwner {
        capPerSale = newCap;
        emit CapPerSaleUpdated(newCap);
    }

    function updateIndividualPurchaseCap(uint256 newCap) external onlyOwner {
        individualPurchaseCap = newCap;
        emit IndividualPurchaseCapUpdated(newCap);
    }

    function pauseSale() external onlyOwner {
        paused = true;
        emit SalePaused();
    }

    function resumeSale() external onlyOwner {
        paused = false;
        emit SaleResumed();
    }
}