// Contract: CrowdfundingWithReferral
// Target function: function claimAirdrop() external nonReentrant
 serviceFee = _serviceFee;
        serviceFeeReceiver = _serviceFeeReceiver;
    }

    function setLaunchPrice(uint256 _launchPriceUSDTRate) external onlyOwner {
        require(_launchPriceUSDTRate > 0, "Price must be greater than 0");
        launchPriceUSDTRate = _launchPriceUSDTRate;
    }

    function _startNewRound() internal {
        require(totalContributionRounds > 0, "No round exists yet!");

        if (purchasedDBTTRound > 0) {
            purchasedDBTTRound = 0;
        }

        priceUSDTRate = contributionRound[currentRound].priceUSDTRate;
        saleCapDBTT = contributionRound[currentRound].saleCapDBTT;
        if (contributionRound[currentRound + 1].priceUSDTRate > 0) {
            nextPriceUSDTRate = contributionRound[currentRound + 1]
                .priceUSDTRate;
        } else {
            nextPriceUSDTRate = 0;
        }

        currentRound++;
    }

    function addNewRound(
        uint256 _saleCapDBTT,
        uint256 _priceUSDTRate
    ) external onlyOwner {
        require(
            !isPresaleOpened && !isPresaleSuccess && !isPresaleCancelled,
            "Presale is already started"
        );
        require(
            _saleCapDBTT > 0 && _priceUSDTRate > 0,
            "Sale cap and price must be greater than 0"
        );

        totalContributionRounds++;
        contributionRound[totalContributionRounds - 1].saleCapDBTT =
            _saleCapDBTT *
            10 ** 18;
        contributionRound[totalContributionRounds - 1]
            .priceUSDTRate = _priceUSDTRate;
    }

    /////////////////////////////// MAIN ///////////////////////////////

    function contributeWithETH(address referrer) external payable nonReentrant {
        require(!isPresaleSuccess && !isPresaleCancelled, "Presale is ended");
        require(isPresaleOpened, "Presale is closed");

        if (minETHContribution > 0) {
            require(
                msg.value >= minETHContribution,
                "Amount must be greater than min contribution"
            );
        } else {
            require(msg.value > 1000, "Amount must be greater than 1000 wei");
        }

        require(msg.value > 0, "Amount must be greater than 0");
        weth.deposit{value: msg.value}();

        users[msg.sender].totalContributionETH += msg.value;

        if (purchasedDBTTRound == saleCapDBTT) {
            if (currentRound < totalContributionRounds) {
                _startNewRound();
            } else {
                revert("Sale cap reached");
            }
        }

        uint256 allocation = ((msg.value * getETHPrice()) / priceUSDTRate) /
            10 ** 2;

        // maybe not here
        if (maxDBTTAllocation > 0) {
            require(
                users[msg.sender].totalPurchasedTokens + allocation <=
                    maxDBTTAllocation,
                "Amount must be less than max allocation"
            );
        }

        if (purchasedDBTTRound + allocation > saleCapDBTT) {
            if (currentRound < totalContributionRounds) {
                uint256 currentRoundDBTT = saleCapDBTT - purchasedDBTTRound;
                uint256 getSpent = (currentRoundDBTT * priceUSDTRate) /
                    10 ** 18;
                uint256 getUSDTInitial = (msg.value * getETHPrice()) / 10 ** 20;
                _startNewRound();
                uint256 remainingDBTT = ((getUSDTInitial - getSpent) *
                    10 ** 18) / priceUSDTRate;
                allocation = currentRoundDBTT + remainingDBTT;
                purchasedDBTTRound += remainingDBTT;
                require(purchasedDBTTRound <= saleCapDBTT, "Sale cap reached");
            } else {
                revert("Sale cap reached");
            }
        } else if (purchasedDBTTRound + allocation == saleCapDBTT) {
            if (currentRound < totalContributionRounds) {
                _startNewRound();
            } else {
                purchasedDBTTRound += allocation;
            }
        } else {
            purchasedDBTTRound += allocation;
        }

        users[msg.sender].totalPurchasedTokens += allocation;
        totalPurchasedDBTT += allocation;
        totalRaisedETH += msg.value;

        if (referrer != address(0)) {
            setReferrer(msg.sender, referrer);
        }

        // Distribute commissions (if applicable)
        if (referralDepth > 0) {
            distributeCommissions(msg.sender, WETH, msg.value);
        }

        emit NewContribution(msg.sender, msg.value, referrer);
    }

    // Function to contribute with ERC20 tokens
    function contributeWithToken(
        address token,
        uint256 amount,
        address referrer
    ) external nonReentrant {
        require(!isPresaleSuccess && !isPresaleCancelled, "Presale is ended");
        require(isPresaleOpened, "Presale is closed");

        if (minUSDTContribution > 0 && token == USDT) {
            require(
                amount >= minUSDTContribution,
                "Amount must be greater than min contribution"
            );
        } else if (token == USDT) {
            require(amount > 1000, "Amount must be greater than 1000 wei");
        }
        if (minETHContribution > 0 && token == WETH) {
            require(
                amount >= minETHContribution,
                "Amount must be greater than min contribution"
            );
        } else if (token == WETH) {
            require(amount > 1000, "Amount must be greater than 1000 wei");
        }
        require(amount > 0, "Amount must be greater than 0");
        require(
            IERC20(token).allowance(msg.sender, address(this)) >= amount,
            "Token allowance too low"
        );
        require(token == USDT || token == WETH, "ERC20 token not valid");

        if (token == USDT) {
            // Transfer tokens to this contract
            IERC20USDT(token).transferFrom(
                msg.sender,
                address(this),
                amount
            );
        } else {
            // Transfer tokens to this contract
            bool sent = IERC20(token).transferFrom(
                msg.sender,
                address(this),
                amount
            );
            require(sent, "Token transfer failed");
        }

        if (purchasedDBTTRound == saleCapDBTT) {
            if (currentRound < totalContributionRounds) {
                _startNewRound();
            } else {
                revert("Sale cap reached");
            }
        }

        uint256 allocation;
        if (token == USDT) {
            users[msg.sender].totalContributionUSDT += amount;
            allocation = (amount * 10 ** (18)) / priceUSDTRate;
            totalRaisedUSDT += amount;
        } else {
            users[msg.sender].totalContributionETH += amount;
            allocation = ((amount * getETHPrice()) / priceUSDTRate) / 10 ** 2;
            totalRaisedETH += amount;
        }

        if (maxDBTTAllocation > 0) {
            require(
                users[msg.sender].totalPurchasedTokens + allocation <=
                    maxDBTTAllocation,
                "Amount must be less than max allocation"
            );
        }

        if (purchasedDBTTRound + allocation > saleCapDBTT) {
            if (currentRound < totalContributionRounds) {
                uint256 currentRoundDBTT = saleCapDBTT - purchasedDBTTRound;
                uint256 getSpent = (currentRoundDBTT * priceUSDTRate) /
                    10 ** 18;
                uint256 getUSDTInitial;
                if (token == USDT) {
                    getUSDTInitial = amount;
                } else {
                    getUSDTInitial = (amount * getETHPrice()) / 10 ** 20;
                }
                _startNewRound();
                uint256 remainingDBTT = ((getUSDTInitial - getSpent) *
                    10 ** 18) / priceUSDTRate;
                allocation = currentRoundDBTT + remainingDBTT;
                purchasedDBTTRound += remainingDBTT;
                require(purchasedDBTTRound <= saleCapDBTT, "Sale cap reached");
            } else {
                revert("Sale cap reached");
            }
        } else if (purchasedDBTTRound + allocation == saleCapDBTT) {
            if (currentRound < totalContributionRounds) {
                _startNewRound();
            } else {
                purchasedDBTTRound += allocation;
            }
        } else {
            purchasedDBTTRound += allocation;
        }

        users[msg.sender].totalPurchasedTokens += allocation;
        totalPurchasedDBTT += allocation;

        if (referrer != address(0)) {
            setReferrer(msg.sender, referrer);
        }

        // Distribute commissions (if applicable)
        if (referralDepth > 0) {
            distributeCommissions(msg.sender, token, amount);
        }

        emit NewContribution(msg.sender, amount, referrer);
    }

    // Internal function to handle commission distribution
    function distributeCommissions(
        address contributor,
        address token,
        uint256 amount
    ) internal {
        address currentReferrer = users[contributor].referrer;

        for (uint256 i = 0; i < referralDepth; i++) {
            if (currentReferrer == address(0)) {
                break;
            }

            if (currentReferrer == contributor) {
                break;
            }

            uint256 commission = (amount * commissionRates[i]) / 1000;

            if (isCommissionDBTT && token == USDT) {
                uint256 commissionDBTT = (commission * 10 ** 18) /
                    priceUSDTRate;
                users[currentReferrer].totalCommissionDBTT += commissionDBTT;
                globalCommissionDBTT += commissionDBTT;
            } else if (isCommissionDBTT) {
                uint256 commissionDBTT = (commission * getETHPrice()) /
                    priceUSDTRate /
                    10 ** 2;
                users[currentReferrer].totalCommissionDBTT += commissionDBTT;
                globalCommissionDBTT += commissionDBTT;
            } else if (token == USDT) {
                users[currentReferrer].totalCommissionUSDT += commission;
                globalCommissionUSDT += commission;
            } else {
                users[currentReferrer].totalCommissionETH += commission;
                globalCommissionETH += commission;
            }

            // Move to the next referrer
            currentReferrer = users[currentReferrer].referrer;
        }
    }

    // Function to withdraw commissions
    function withdrawCommissions() external nonReentrant {
        require(isPresaleSuccess, "Claim not active");
        require(
            users[msg.sender].totalCommissionUSDT > 0 ||
                users[msg.sender].totalCommissionETH > 0 ||
                users[msg.sender].totalCommissionDBTT > 0,
            "No commissions to claim"
        );

        _withdrawCommissions();
    }

    // Function to withdraw commissions
    function _withdrawCommissions() internal {
        uint256 amountUSDT = users[msg.sender].totalCommissionUSDT;
        if (amountUSDT > 0) {
            users[msg.sender].totalCommissionUSDT = 0;
            IERC20USDT(USDT).transfer(msg.sender, amountUSDT);
            globalCommissionUSDTPaid += amountUSDT;
        }
        uint256 amountETH = users[msg.sender].totalCommissionETH;
        if (amountETH > 0) {
            users[msg.sender].totalCommissionETH = 0;
            bool sent = IERC20(WETH).transfer(msg.sender, amountETH);
            require(sent, "Token transfer failed");
            globalCommissionETHPaid += amountETH;
        }
        uint256 amountDBTT = users[msg.sender].totalCommissionDBTT;
        if (amountDBTT > 0) {
            users[msg.sender].totalCommissionDBTT = 0;
            bool sent = IERC20(DBTT).transfer(msg.sender, amountDBTT);
            require(sent, "Token transfer failed");
            globalCommissionDBTTPaid += amountDBTT;
        }
    }

    // Function to withdraw purchased tokens
    function claimTokens() external nonReentrant {
        require(isPresaleSuccess, "Claim not active");
        require(users[msg.sender].totalPurchasedTokens > 0, "Nothing to claim");
        _claimTokens();
    }

    function _claimTokens() internal {
        uint256 amount = users[msg.sender].totalPurchasedTokens;
        users[msg.sender].totalPurchasedTokens = 0;

        bool sent = IERC20(DBTT).transfer(msg.sender, amount);
        require(sent, "Token transfer failed");
        totalPurchasedDBTTClaimed += amount;
    }

    // Function to withdraw ETH
    function withdrawETH(uint256 _amount) external onlyOwner nonReentrant {
        uint256 amount = IERC20(WETH).balanceOf(address(this));
        require(amount >= _amount, "Not enough ETH to withdraw");
        require(
            amount - _amount >= globalCommissionETH - globalCommissionETHPaid,
            "Not enough ETH to withdraw"
        );

        if (serviceFeeReceiver != address(0) && serviceFee > 0) {
            uint256 serviceFeeAmount = (_amount * serviceFee) / 1000;
            bool sentFees = IERC20(WETH).transfer(
                serviceFeeReceiver,
                serviceFeeAmount
            );
            require(sentFees, "ETH Token transfer failed");
            _amount -= serviceFeeAmount;
        }

        bool sent = IERC20(WETH).transfer(msg.sender, _amount);
        require(sent, "ETH Token transfer failed");
    }

    // Function to withdraw USDT
    function withdrawUSDT(uint256 _amount) external onlyOwner nonReentrant {
        uint256 amount = IERC20(USDT).balanceOf(address(this));
        require(amount >= _amount, "Not enough USDT to withdraw");
        require(
            amount - _amount >= globalCommissionUSDT - globalCommissionUSDTPaid,
            "Not enough USDT to withdraw"
        );

        if (serviceFeeReceiver != address(0) && serviceFee > 0) {
            uint256 serviceFeeAmount = (_amount * serviceFee) / 1000;
            IERC20USDT(USDT).transfer(
                serviceFeeReceiver,
                serviceFeeAmount
            );
            _amount -= serviceFeeAmount;
        }

        IERC20USDT(USDT).transfer(msg.sender, _amount);
    }

    // Function to withdraw all USDT and all WETH
    function withdrawAll() external onlyOwner nonReentrant {
        require(isPresaleSuccess, "Presale is not completed");
        uint256 amountUSDT = IERC20(USDT).balanceOf(address(this));
        uint256 amountETH = IERC20(WETH).balanceOf(address(this));
        require(
            amountUSDT >= globalCommissionUSDT - globalCommissionUSDTPaid,
            "Not enough USDT to withdraw"
        );
        require(
            amountETH >= globalCommissionETH - globalCommissionETHPaid,
            "Not enough ETH to withdraw"
        );

        amountUSDT -= globalCommissionUSDT - globalCommissionUSDTPaid;
        amountETH -= globalCommissionETH - globalCommissionETHPaid;

        if (serviceFeeReceiver != address(0) && serviceFee > 0) {
            uint256 serviceFeeAmountUSDT = (amountUSDT * serviceFee) / 1000;
            uint256 serviceFeeAmountETH = (amountETH * serviceFee) / 1000;
            IERC20USDT(USDT).transfer(
                serviceFeeReceiver,
                serviceFeeAmountUSDT
            );
            bool sentFeesETH = IERC20(WETH).transfer(
                serviceFeeReceiver,
                serviceFeeAmountETH
            );
            require(sentFeesETH, "ETH Token transfer failed");
            amountUSDT -= serviceFeeAmountUSDT;
            amountETH -= serviceFeeAmountETH;
        }

        IERC20USDT(USDT).transfer(msg.sender, amountUSDT);
        bool sentETH = IERC20(WETH).transfer(msg.sender, amountETH);
        require(sentETH, "ETH Token transfer failed");
    }

    // Function to withdraw DBTT
    function withdrawDBTT() external onlyOwner nonReentrant {
        uint256 amount = IERC20(DBTT).balanceOf(address(this));
        if (isPresaleSuccess) {
            require(
                amount >
                    globalCommissionDBTT +
                        totalPurchasedDBTT +
                        globalTotalAirdrop -
                        globalCommissionDBTTPaid -
                        totalPurchasedDBTTClaimed -
                        globalTotalAirdropClaimed,
                "Not enough DBTT to withdraw"
            );
            amount -=
                globalCommissionDBTT +
                totalPurchasedDBTT +
                globalTotalAirdrop -
                globalCommissionDBTTPaid -
                totalPurchasedDBTTClaimed -
                globalTotalAirdropClaimed;
            bool sent = IERC20(DBTT).transfer(msg.sender, amount);
            require(sent, "DBTT Token transfer failed");
        } else if (isPresaleCancelled && amount > 0) {
            bool sent = IERC20(DBTT).transfer(msg.sender, amount);
            require(sent, "DBTT Token transfer failed");
        } else revert("No DBTT to withdraw");
    }

    // refund USDT or WETH to user
    function refund() external nonReentrant {
        require(isPresaleCancelled, "Presale has not been cancelled");
        uint256 amountUSDT = users[msg.sender].totalContributionUSDT;
        uint256 amountETH = users[msg.sender].totalContributionETH;
        require(
            amountUSDT > 0 || amountETH > 0,
            "Amount must be greater than 0"
        );
        users[msg.sender].totalContributionUSDT = 0;
        users[msg.sender].totalContributionETH = 0;
        if (amountUSDT > 0) {
            IERC20USDT(USDT).transfer(msg.sender, amountUSDT);
        }
        if (amountETH > 0) {
            bool sent = IERC20(WETH).transfer(msg.sender, amountETH);
            require(sent, "ETH Token transfer failed");
        }
    }