Manager

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{"Address.sol":{"content":"// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn\u0027t rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length \u003e 0;
    }

    /**
     * @dev Replacement for Solidity\u0027s `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance \u003e= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance \u003e= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn\u0027t, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length \u003e 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
"},"Context.sol":{"content":"// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
"},"IERC20.sol":{"content":"// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller\u0027s account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender\u0027s allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller\u0027s
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
"},"IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "./Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}"},"PresaleManager.sol":{"content":"// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./Address.sol";
import "./Context.sol";
import "./SafeMath.sol";
import "./Ownable.sol";
import "./IERC20.sol";
import "./IERC20Metadata.sol";
import "./SafeERC20.sol";

contract Proxy {
    // masterCopy always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
    // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`

    constructor(address _masterCopy) {
        require(
            _masterCopy != address(0),
            "Invalid master copy address provided"
        );
        bytes32 slot = _IMPLEMENTATION_SLOT;

        // solhint-disable-next-line no-inline-assembly
        assembly {
            sstore(slot, _masterCopy)
        }
    }

    bytes32 private constant _IMPLEMENTATION_SLOT =
        0x6b75c6e3b92dbabf77414617df2d64d6a835b7a3fb3409b21218efb3ac232a7f;

    receive() external payable {}

    /// @dev Fallback function forwards all transactions and returns all received return data.
    fallback() external payable {
        bytes32 slot = _IMPLEMENTATION_SLOT;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let _masterCopy := and(
                sload(slot),
                0xffffffffffffffffffffffffffffffffffffffff
            )
            // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
            if eq(
                calldataload(0),
                0xa619486e00000000000000000000000000000000000000000000000000000000
            ) {
                mstore(0, _masterCopy)
                return(0, 0x20)
            }
            calldatacopy(0, 0, calldatasize())
            let success := delegatecall(
                gas(),
                _masterCopy,
                0,
                calldatasize(),
                0,
                0
            )
            returndatacopy(0, 0, returndatasize())
            if eq(success, 0) {
                revert(0, returndatasize())
            }
            return(0, returndatasize())
        }
    }
}

interface ILaunchpad {
    function initOwner() external;

    function initializePresale(
        address,
        address,
        uint256,
        uint256,
        uint256,
        uint256,
        uint256,
        uint256,
        uint256
    ) external;

    function initializeLock(
        uint256,
        uint256,
        uint256,
        uint256,
        uint256,
        address,
        address,
        address,
        address,
        bool
    ) external;

    function endInit() external;

    function transferOwnership(address) external;

    function updateInfo(string[] memory) external;

    function enableWhiteList(uint256) external;

    function presaleType() external view returns (string memory);

    function logoUrl() external view returns (string memory);

    function token() external view returns (address);

    function buyToken() external view returns (address);

    function total() external view returns (uint256);

    function rate() external view returns (uint256);

    function softCap() external view returns (uint256);

    function hardCap() external view returns (uint256);

    function maxBuy() external view returns (uint256);

    function whiteListEnableTime() external view returns (uint256);

    function totalDepositedBalance() external view returns (uint256);

    function liquidity() external view returns (uint256);

    function lockPeriod() external view returns (uint256);

    function presaleStartTimestamp() external view returns (uint256);

    function presaleEndTimestamp() external view returns (uint256);

    function refundable() external view returns (bool);

    function claimable() external view returns (bool);

    function whitelist() external view returns (string memory);

    function starred() external view returns (bool);

    function isLive() external view returns(bool);
}

interface IFairLaunch {
    function initOwner() external;

    function initializePresale(
        address,
        address,
        uint256,
        uint256,
        uint256,
        uint256,
        uint256
    ) external;

    function initializeLock(
        uint256,
        uint256,
        uint256,
        uint256,
        address,
        address,
        address,
        bool
    ) external;

    function endInit() external;

    function transferOwnership(address) external;

    function updateInfo(string[] memory) external;

    function enableWhiteList(uint256) external;
}

contract Manager is Ownable {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    uint256 public constant FEE_PERCENT_DIVIDOR = 1000;
    uint256 public constant VESTING_PERCENT_DIVIDOR = 10000;
    uint256 public DEFAULT_MAIN_FEE_OPTION_1 = 50;
    uint256 public DEFAULT_TOKEN_FEE_OPTION_1 = 0;
    uint256 public DEFAULT_MAIN_FEE_OPTION_2 = 20;
    uint256 public DEFAULT_TOKEN_FEE_OPTION_2 = 20;

    address payable public feeAddress;
    uint256 public serviceFee = 1 ether;
    uint256 public starredFee = 0.1 ether;
    mapping(address =\u003e bool) public routers;
    address public presale;
    address public fairPresale;
    address public locker;

    struct Contribution {
        address addr;
        address owner;
        address token;
        uint256 createTime;
        bool isLaunchpad;
    }

    struct LaunchpadInfo {
        string presaleType;
        address addr;
        string logoUrl;
        address token;
        address buyToken;
        uint256 total;
        uint256 rate;
        uint256 softCap;
        uint256 hardCap;
        uint256 maxBuy;
        uint256 amount;
        uint256 liquidity;
        uint256 lockTime;
        uint256 startTime;
        uint256 endTime;
        string whitelist;
        uint256 whiteListEnableTime;
        bool refundable;
        bool claimable;
        bool starred;
        bool isLive;
    }

    Contribution[] public contributions;
    mapping(address =\u003e Contribution[]) public userContributions;

    event NewLaunchpadCreated(address indexed user, address indexed launchpad);

    constructor(
        address payable _feeAddress,
        address _presale,
        address _fairPresale,
        address _locker
    ) {
        feeAddress = _feeAddress;
        presale = _presale;
        fairPresale = _fairPresale;
        locker = _locker;
    }

    // _values[0] = startTime,
    // _values[1] = endTime,
    // _values[2] = softCap,
    // _values[3] = hardCap,
    // _values[4] = minBuy,
    // _values[5] = maxBuy,
    // _values[6] = rate,
    // _values[7] = listingRate,
    // _values[8] = liquidity,
    // _values[9] = lockPeriod,
    // _values[10] = mainFee,
    // _values[11] = tokenFee,
    // _addresses[0] = token,
    // _addresses[1] = buyToken,
    // _addresses[2] = router,
    // _addresses[3] = backAddress,
    // _strings[0] = _info,
    // _strings[1] = _logoUrl,
    // _strings[2] = _website,
    // _strings[3] = _facebook,
    // _strings[4] = _twitter,
    // _strings[5] = _github,
    // _strings[6] = _telegram,
    // _strings[7] = _instagram,
    // _strings[8] = _discord,
    // _strings[9] = _reddit,
    // _strings[10] = _youtube,
    // _strings[11] = _whitelist
    // _options[0] = whitelistOption
    // _options[1] = feeOption
    // _options[2] = listingOption
    // _options[3] = starred

    function createNewStandardLaunch(
        uint256[] memory _values,
        address[] memory _addresses,
        string[] memory _strings,
        bool[] memory _options
    ) public payable returns (address) {
        uint256 totalFee = _options[3] ? serviceFee + starredFee : serviceFee;
        require(msg.value \u003e= totalFee, "should pay creation fee");
        Address.sendValue(feeAddress, totalFee);
        if (msg.value \u003e totalFee)
            Address.sendValue(payable(msg.sender), msg.value - totalFee);

        bytes32 salt = keccak256(
            abi.encodePacked(_addresses[0], msg.sender, block.timestamp)
        );
        Proxy newContract = new Proxy{salt: salt}(presale);
        address launchpad = address(newContract);

        uint256[] memory values = _values;
        address[] memory addresses = _addresses;
        string[] memory strings = _strings;

        // check input param\u0027s validation
        require(
            !_options[2] || routers[addresses[2]],
            "router is not registered"
        );
        require(
            values[0] \u003e block.timestamp,
            "startTime should be after than now"
        );
        require(
            values[0] \u003c values[1],
            "startTime should be before than endTime"
        );
        require(values[2] \u003c values[3], "softcap should be less than hardcap");
        require(
            values[2] \u003e= values[3] / 4,
            "softcap must be greater than or equal 25% of hardcap"
        );
        require(values[4] \u003e 0, "minBuy should be greater than 0");
        require(values[4] \u003c values[5], "minBuy should be less than maxBuy");
        require(values[6] \u003e 0, "presale rate can\u0027t be zero");
        require(!_options[2] || values[7] \u003e 0, "listing rate can\u0027t be zero");
        require(
            !_options[2] || values[8] \u003e= 500,
            "liquidity must be more than 50%"
        );
        require(
            !_options[2] || values[8] \u003c= 1000,
            "liquidity must be less than 100%"
        );
        require(
            !_options[2] || values[9] \u003e= 30 days,
            "lock time must be longer than 30 days"
        );

        uint256 tokenAmount = values[3]
            .mul(values[6])
            .mul(FEE_PERCENT_DIVIDOR + values[11])
            .div(FEE_PERCENT_DIVIDOR) +
            values[3]
                .mul(values[7])
                .mul(FEE_PERCENT_DIVIDOR - values[10])
                .div(FEE_PERCENT_DIVIDOR)
                .mul(values[8])
                .div(FEE_PERCENT_DIVIDOR);

        uint256 beforeBalance = IERC20(addresses[0]).balanceOf(launchpad);
        uint256 decimals = 18;
        if (addresses[1] != address(0)) {
            decimals = IERC20Metadata(addresses[1]).decimals();
        }
        IERC20(addresses[0]).safeTransferFrom(
            msg.sender,
            launchpad,
            tokenAmount.div(10**decimals)
        );
        require(
            IERC20(addresses[0]).balanceOf(launchpad) - beforeBalance \u003e=
                tokenAmount.div(10**decimals),
            "invalid token transfer"
        );

        ILaunchpad(launchpad).initOwner();
        ILaunchpad(launchpad).initializePresale(
            addresses[0],
            addresses[1],
            values[0],
            values[1],
            values[2],
            values[3],
            values[4],
            values[5],
            values[6]
        );
        bool star = _options[3];
        ILaunchpad(launchpad).initializeLock(
            values[7],
            values[9],
            values[10],
            values[11],
            values[8],
            addresses[2],
            locker,
            feeAddress,
            addresses[3],
            star
        );
        ILaunchpad(launchpad).updateInfo(strings);
        // if whitelist option enabled
        if (_options[0]) ILaunchpad(launchpad).enableWhiteList(values[1]);
        // if fee option is mainfee = 5 and tokenfee = 0
        if (_options[1])
            require(
                values[10] == DEFAULT_MAIN_FEE_OPTION_1 \u0026\u0026
                    values[11] == DEFAULT_TOKEN_FEE_OPTION_1,
                "invalid fee value"
            );
        else
            require(
                values[10] == DEFAULT_MAIN_FEE_OPTION_2 \u0026\u0026
                    values[11] == DEFAULT_TOKEN_FEE_OPTION_2,
                "invalid fee values"
            );

        ILaunchpad(launchpad).endInit();

        ILaunchpad(launchpad).transferOwnership(msg.sender);
        contributions.push(
            Contribution({
                addr: launchpad,
                owner: msg.sender,
                token: addresses[0],
                createTime: block.timestamp,
                isLaunchpad: true
            })
        );
        userContributions[msg.sender].push(
            Contribution({
                addr: launchpad,
                owner: msg.sender,
                token: addresses[0],
                createTime: block.timestamp,
                isLaunchpad: true
            })
        );

        emit NewLaunchpadCreated(msg.sender, launchpad);

        return launchpad;
    }

    // _values[0] = startTime,
    // _values[1] = endTime,
    // _values[2] = softCap,
    // _values[3] = total,
    // _values[4] = liquidity,
    // _values[5] = lockPeriod,
    // _values[6] = mainFee,
    // _values[7] = tokenFee,
    // _values[8] = maxBuy,
    // _addresses[0] = token,
    // _addresses[1] = buyToken,
    // _addresses[2] = router,
    // _strings[0] = _info,
    // _strings[1] = _logoUrl,
    // _strings[2] = _website,
    // _strings[3] = _facebook,
    // _strings[4] = _twitter,
    // _strings[5] = _github,
    // _strings[6] = _telegram,
    // _strings[7] = _instagram,
    // _strings[8] = _discord,
    // _strings[9] = _reddit,
    // _strings[10] = _youtube,
    // _strings[11] = _whitelist,
    // _options[0] = feeOption
    // _options[1] = whitelistOption
    // _options[2] = starred

    function createNewFairLaunch(
        uint256[] memory _values,
        address[] memory _addresses,
        string[] memory _strings,
        bool[] memory _options
    ) public payable returns (address) {
        bool[] memory options = _options;
        uint256 totalFee = options[2] ? serviceFee + starredFee : serviceFee;
        require(msg.value \u003e= totalFee, "should pay creation fee");
        Address.sendValue(feeAddress, totalFee);
        if (msg.value \u003e totalFee)
            Address.sendValue(payable(msg.sender), msg.value - totalFee);

        bytes32 salt = keccak256(
            abi.encodePacked(_addresses[0], msg.sender, block.timestamp)
        );
        Proxy newContract = new Proxy{salt: salt}(fairPresale);
        address launchpad = address(newContract);

        uint256[] memory values = _values;
        address[] memory addresses = _addresses;

        require(routers[addresses[2]], "router is not registered");
        require(
            values[0] \u003e block.timestamp,
            "startTime should be after than now"
        );
     
        require(
            values[0] \u003c values[1],
            "startTime should be before than endTime"
        );
        require(values[3] \u003e 0, "total can\u0027t be zero");
        require(values[4] \u003e= 500, "liquidity must be more than 50%");
        require(values[4] \u003c= 1000, "liquidity must be less than 100%");
        require(values[5] \u003e= 30 days, "lock time must be longer than 30 days");

        IFairLaunch(launchpad).initOwner();
        IFairLaunch(launchpad).initializePresale(
            addresses[0],
            addresses[1],
            values[0],
            values[1],
            values[2],
            values[3],
            values[8]
        );
        IFairLaunch(launchpad).initializeLock(
            values[5],
            values[6],
            values[7],
            values[4],
            addresses[2],
            locker,
            feeAddress,
            options[2]
        );
        IFairLaunch(launchpad).updateInfo(_strings);
        // if fee option is mainfee = 5 and tokenfee = 0
        if (options[0])
            require(
                values[6] == DEFAULT_MAIN_FEE_OPTION_1 \u0026\u0026
                    values[7] == DEFAULT_TOKEN_FEE_OPTION_1,
                "invalid fee value"
            );
        else
            require(
                values[6] == DEFAULT_MAIN_FEE_OPTION_2 \u0026\u0026
                    values[7] == DEFAULT_TOKEN_FEE_OPTION_2,
                "invalid fee values"
            );

        // if whitelist option enabled
        if (options[1]) ILaunchpad(launchpad).enableWhiteList(values[1]);

        uint256 tokenAmount = values[3] +
            values[3]
                .mul(
                    (FEE_PERCENT_DIVIDOR - values[6]).mul(values[4]) +
                        values[7].mul(FEE_PERCENT_DIVIDOR)
                )
                .div(FEE_PERCENT_DIVIDOR * FEE_PERCENT_DIVIDOR);

        uint256 beforeBalance = IERC20(addresses[0]).balanceOf(launchpad);
        IERC20(addresses[0]).safeTransferFrom(
            msg.sender,
            launchpad,
            tokenAmount
        );
        require(
            IERC20(addresses[0]).balanceOf(launchpad) - beforeBalance \u003e=
                tokenAmount,
            "invalid token transfer"
        );

        IFairLaunch(launchpad).endInit();

        IFairLaunch(launchpad).transferOwnership(msg.sender);
        contributions.push(
            Contribution({
                addr: launchpad,
                owner: msg.sender,
                token: _addresses[0],
                createTime: block.timestamp,
                isLaunchpad: false
            })
        );
        userContributions[msg.sender].push(
            Contribution({
                addr: launchpad,
                owner: msg.sender,
                token: _addresses[0],
                createTime: block.timestamp,
                isLaunchpad: false
            })
        );

        emit NewLaunchpadCreated(msg.sender, launchpad);

        return launchpad;
    }

    function setPresaleAddress(address _presale) public onlyOwner {
        require(_presale != address(0), "cannot be zero address");
        presale = _presale;
    }

    function setFairPresaleAddress(address _fairPresale) public onlyOwner {
        require(_fairPresale != address(0), "cannot be zero address");
        fairPresale = _fairPresale;
    }

    function setLockerAddress(address _addr) public onlyOwner {
        locker = _addr;
    }

    function setFeeAddress(address payable _addr) public onlyOwner {
        feeAddress = _addr;
    }

    function setServiceFee(uint256 _fee) public onlyOwner {
        serviceFee = _fee;
    }

    function setStarredFee(uint256 _fee) public onlyOwner {
        starredFee = _fee;
    }

    function updateConfig(
        uint256 mainFee_1,
        uint256 mainFee_2,
        uint256 tokenFee_1,
        uint256 tokenFee_2
    ) public onlyOwner {
        DEFAULT_MAIN_FEE_OPTION_1 = mainFee_1;
        DEFAULT_TOKEN_FEE_OPTION_1 = tokenFee_1;
        DEFAULT_MAIN_FEE_OPTION_2 = mainFee_2;
        DEFAULT_TOKEN_FEE_OPTION_2 = tokenFee_2;
    }

    function setRouterAddress(address _addr, bool _en) public onlyOwner {
        routers[_addr] = _en;
    }

    function getUserContributionsLength(address user)
        external
        view
        returns (uint256)
    {
        return userContributions[user].length;
    }

    function getLaunchpads(uint256 size, uint256 cursor)
        public
        view
        returns (LaunchpadInfo[] memory)
    {
        uint256 length = size;

        if (length \u003e contributions.length - cursor) {
            length = contributions.length - cursor;
        }

        LaunchpadInfo[] memory launchpads = new LaunchpadInfo[](length);

        for (uint256 i = 0; i \u003c length; i++) {
            launchpads[i].presaleType = ILaunchpad(
                contributions[cursor + i].addr
            ).presaleType();
            launchpads[i].addr = contributions[cursor + i].addr;
            launchpads[i].logoUrl = ILaunchpad(contributions[cursor + i].addr)
                .logoUrl();
            launchpads[i].token = ILaunchpad(contributions[cursor + i].addr)
                .token();
            launchpads[i].buyToken = ILaunchpad(contributions[cursor + i].addr)
                .buyToken();
            launchpads[i].total = ILaunchpad(contributions[cursor + i].addr)
                .total();
            launchpads[i].rate = ILaunchpad(contributions[cursor + i].addr)
                .rate();
            launchpads[i].hardCap = ILaunchpad(contributions[cursor + i].addr)
                .hardCap();
            launchpads[i].softCap = ILaunchpad(contributions[cursor + i].addr)
                .softCap();
            launchpads[i].maxBuy = ILaunchpad(contributions[cursor + i].addr)
                .maxBuy();
            launchpads[i].amount = ILaunchpad(contributions[cursor + i].addr)
                .totalDepositedBalance();
            launchpads[i].liquidity = ILaunchpad(contributions[cursor + i].addr)
                .liquidity();
            launchpads[i].lockTime = ILaunchpad(contributions[cursor + i].addr)
                .lockPeriod();
            launchpads[i].startTime = ILaunchpad(contributions[cursor + i].addr)
                .presaleStartTimestamp();
            launchpads[i].endTime = ILaunchpad(contributions[cursor + i].addr)
                .presaleEndTimestamp();
            launchpads[i].refundable = ILaunchpad(
                contributions[cursor + i].addr
            ).refundable();
            launchpads[i].claimable = ILaunchpad(contributions[cursor + i].addr)
                .claimable();
            launchpads[i].whiteListEnableTime = ILaunchpad(
                contributions[cursor + i].addr
            ).whiteListEnableTime();
            launchpads[i].whitelist = ILaunchpad(contributions[cursor + i].addr)
                .whitelist();
            launchpads[i].starred = ILaunchpad(contributions[cursor + i].addr)
                .starred();
            launchpads[i].isLive = ILaunchpad(contributions[cursor + i].addr)
                .isLive();
        }
        return launchpads;
    }

    function getContributionsLength() external view returns (uint256) {
        return contributions.length;
    }
}
"},"SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // \u0027safeIncreaseAllowance\u0027 and \u0027safeDecreaseAllowance\u0027
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance \u003e= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity\u0027s return data size checking mechanism, since
        // we\u0027re implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length \u003e 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}
"},"SafeMath.sol":{"content":"// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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\u0027s built in overflow checks.

/**
 * @dev Wrappers over Solidity\u0027s 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 \u003c a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction 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 \u003e 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 \u0027a\u0027 not being zero, but the
            // benefit is lost if \u0027b\u0027 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\u0027s `+` 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\u0027s `-` 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\u0027s `*` 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\u0027s `/` 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\u0027s `%` 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\u0027s `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b \u003c= 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\u0027s `/` 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 \u003e 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\u0027s `%` 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 \u003e 0, errorMessage);
            return a % b;
        }
    }
}"}}

Tags:
ERC20, Multisig, Liquidity, Upgradeable, Multi-Signature, Factory|addr:0xbe4687733dce54dee614abb34d995152b551b1b1|verified:true|block:23667558|tx:0xbaaa66ada6d8a8525328e3eb8a62d92d1386b4e9c8cc92fe4a7d6816617a3b8f|first_check:1761566207

Submitted on: 2025-10-27 12:56:48

Comments

Log in to comment.

No comments yet.