Repository: CryptoBlades/cryptoblades
File: contracts/Launchpad.sol (Solidity)

Code before:
        require(duration > 0);
        require(launchPeriodicVestingsPercentages[launchId].length == 0, "Periodic vesting enabled");
        uint256 totalLaunchRaised = launchTotalRaised[launchId].add(launchTotalRaised[launchId + 1]);
        uint256 contractBalance = IERC20(launchTokenAddress[launchId]).balanceOf(address(this));
        uint256 decimals = ERC20(launchTokenAddress[launchId]).decimals();
        if(decimals > 18) {
            contractBalance = contractBalance.mul(10**uint(decimals - 18));
        } else {
            contractBalance = contractBalance.div(10**uint(18 - decimals));
        }
        require(contractBalance >= totalLaunchRaised.mul(1e18).div(launchTokenPrice[launchId]), "Not enough balance");

        launchLinearVestingsDurations[launchId] = duration;
        launchLinearVestingsStartTimestamps[launchId] = block.timestamp;

        emit LinearVestingEnabled(launchId, block.timestamp);
    }

    // WHITELISTING

    function setEligibleUsersData(uint256 launchId, address[] calldata users, uint256[] calldata stakedAmounts) external onlyPhase1(launchId) restricted {
        require(nextLaunchId >= launchId, "Wrong ID");
        require(users.length == stakedAmounts.length, "Bad input");
        require(launchStartTime[launchId] > block.timestamp, "Launch started");

        uint totalWeight = 0;
        for(uint i = 0; i < users.length; i++) {
            if(!launchEligibleUsersSnapshot[launchId].add(users[i])) continue;
            launchUserStakedAmountSnapshot[launchId][users[i]] = stakedAmounts[i];
            totalWeight += tierAllocationWeight[getTierForStakedAmount(stakedAmounts[i])];
        }
        launchBaseAllocation[launchId] = launchFundsToRaise[launchId].div(totalWeight);
    }

    // WITHDRAW RAISED FUNDS

    function withdrawRaisedFunds(uint256 launchId) external onlyPhase1(launchId) {
        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Not owner");
        require(
            block.timestamp > launchStartTime[launchId] + vars[VAR_FUNDING_PERIOD_PHASE_1] &&
            block.timestamp > launchStartTime[launchId + 1] + vars[VAR_FUNDING_PERIOD_PHASE_2],
            "Launch not finished"
        );

        uint256 raisedFunds = launchTotalRaised[launchId].add(launchTotalRaised[launchId + 1]);

        IERC20(launches[launchId].fundingTokenAddress).safeTransfer(msg.sender, raisedFunds);
        emit FundsWithdrawn(launchId, raisedFunds);
    }

    // VARS SETTERS

Review comment (performance):
This needs to be assigned with `launchFundsToRaise[launchId].div(launchBaseAllocation[launchId])` to allow for calling this function in batches. I think thousands of entries per array in arguments can hit the gas limits.

Code after:
    }

    // WHITELISTING

    function setEligibleUsersData(uint256 launchId, address[] calldata users, uint256[] calldata stakedAmounts) external onlyPhase1(launchId) restricted {
        require(nextLaunchId >= launchId, "Wrong ID");
        require(users.length > 0 && users.length == stakedAmounts.length, "Bad input");
        require(launchStartTime[launchId] > block.timestamp, "Launch started");

        uint totalWeight = launchBaseAllocation[launchId] == 0 ? 0 : launchFundsToRaise[launchId].div(launchBaseAllocation[launchId]);
        for(uint i = 0; i < users.length; i++) {
            if(!launchEligibleUsersSnapshot[launchId].add(users[i])) continue;
            launchUserStakedAmountSnapshot[launchId][users[i]] = stakedAmounts[i];
            totalWeight += tierAllocationWeight[getTierForStakedAmount(stakedAmounts[i])];
        }
        launchBaseAllocation[launchId] = launchFundsToRaise[launchId].div(totalWeight);
    }

    // WITHDRAW RAISED FUNDS

    function withdrawRaisedFunds(uint256 launchId) external onlyPhase1(launchId) {
        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Not owner");
        require(
            block.timestamp > launchStartTime[launchId] + vars[VAR_FUNDING_PERIOD_PHASE_1] &&
            block.timestamp > launchStartTime[launchId + 1] + vars[VAR_FUNDING_PERIOD_PHASE_2],
            "Launch not finished"
        );

        uint256 raisedFunds = launchTotalRaised[launchId].add(launchTotalRaised[launchId + 1]);

        IERC20(launches[launchId].fundingTokenAddress).safeTransfer(msg.sender, raisedFunds);
        emit FundsWithdrawn(launchId, raisedFunds);
    }

    // VARS SETTERS

    function setVar(uint256 varField, uint256 value) external restricted {
        vars[varField] = value;
    }

    function setVars(uint256[] calldata varFields, uint256[] calldata values) external restricted {
        for (uint256 i = 0; i < varFields.length; i++) {
            vars[varFields[i]] = values[i];
        }
    }

    function setSkillPrice(uint256 price) external restricted {
        skillPrice = price;
    }

    // USER FUNCTIONS