contract WalletProxyFactory is Ownable {

    /**
     * @dev Emits when a new wallet with address `wallet` for `class` at `index`
     * is created.
     */
    event CreateWallet(uint256 class, uint256 index, address wallet);

    address public beacon;  // Proxy beacon contract address
    address public DAO;  // The Gnosis Safe multisig wallet
    address public merge;  // Merge contract address
    address public router;  // Router contract address
    address public manager;  // Mangaer contract address

    uint256 public constant NUM_OF_CLASSES = 100;  // Number of classes

    /**
     * @dev Sets `beacon_`, `DAO_`, `manager_` and `merge_` smart contract addresses.
     */
    constructor(
        address beacon_,
        address DAO_,
        address manager_,
        address merge_)
    {
        require(beacon_ != address(0), "Invalid beacon");
        require(IBeacon(beacon_).implementation() != address(0), "Invalid implementation");
        if (DAO_ == address(0) ||
            manager_ == address(0) ||
            merge_ == address(0)) revert("Invalid inputs");

        beacon = beacon_;
        DAO = DAO_;
        manager = manager_;
        merge = merge_;
    }

    /**
     * @dev Sets the router contract address.
     */
    function init(address router_) public onlyOwner {
        router = router_;
    }

    /**
     * @dev A modifier that only allows the router contract access.
     */
    modifier onlyRouter {
        require(_msgSender() == router, "Only Router");
        _;
    }

    /**
     * @dev Create the wallet for `classId` when the existing ones have reached
     * the soft cap
     */
    function createWallet(uint256 classId) public onlyRouter returns (address wallet) {
        require(classId < NUM_OF_CLASSES, "Invalid classId");
        WalletProxy walletProxy = new WalletProxy(beacon, DAO, merge, manager);
        wallet = address(walletProxy);
        IWalletProxyManager(manager).setWallet(classId, wallet);
        uint256 index = IWalletProxyManager(manager).currentIndex(classId);
        emit CreateWallet(classId, index, wallet);
    }
}
function init(address router_) public onlyOwner {
    router = router_;
}

/**
 * @dev Sets the router contract address.
 */