contract ProxyBeacon is Context, UpgradeableBeacon {
    event LogProxyDeployerUpdated(address indexed oldProxyDeployer, address indexed newProxyDeployer);

    // Only allow one address to call `deployProxy`.
    address private _proxyDeployer;

    modifier onlyProxyDeployer() {
        address proxyDeployer_ = getProxyDeployer();
        require(
            proxyDeployer_ != address(0x0) && _msgSender() == proxyDeployer_,
            "ProxyBeacon: caller is not the proxy deployer"
        );
        _;
    }

    constructor(address implementation_, address contractOwner) UpgradeableBeacon(implementation_) {
        transferOwnership(contractOwner);
    }

    // GETTERS /////////////////////////////////////////////////////////////////

    function getProxyDeployer() public view returns (address) {
        return _proxyDeployer;
    }

    // GOVERNANCE //////////////////////////////////////////////////////////////

    function updateProxyDeployer(address newProxyDeployer) public onlyOwner {
        require(newProxyDeployer != address(0x0), "ProxyBeacon: invalid proxy deployer");
        address oldProxyDeployer = _proxyDeployer;
        _proxyDeployer = newProxyDeployer;
        emit LogProxyDeployerUpdated(oldProxyDeployer, newProxyDeployer);
    }

    // RESTRICTED //////////////////////////////////////////////////////////////

    /// @notice Deploy a proxy that fetches its implementation from this
    /// ProxyBeacon.
    function deployProxy(bytes32 create2Salt, bytes calldata encodedParameters)
        external
        onlyProxyDeployer
        returns (address)
    {
        // Deploy without initialization code so that the create2 address isn't
        // based on the initialization parameters.
        address proxy = address(new BeaconProxy{salt: create2Salt}(address(this), ""));

        Address.functionCall(address(proxy), encodedParameters);

        return proxy;

    }
}
function deployProxy(bytes32 create2Salt, bytes calldata encodedParameters)
    external
    onlyProxyDeployer
    returns (address)
{
    // Deploy without initialization code so that the create2 address isn't
    // based on the initialization parameters.
    address proxy = address(new BeaconProxy{salt: create2Salt}(address(this), ""));

    Address.functionCall(address(proxy), encodedParameters);

    return proxy;

}

/// @notice Deploy a proxy that fetches its implementation from this
/// ProxyBeacon.