contract PaymentMaster {
	using SafeERC20 for IERC20;

	address public owner;

	// payment handler logic contract address
	address public handlerLogicAddress ;

	// A list of handler addresses for retrieval
  address[] public handlerList;

	// A mapping of handler addresses for lookups
	mapping(address => bool) public handlerMap;

	// Events triggered for listeners
	event HandlerCreated(address indexed _addr);
	event EthPaymentReceived(address indexed _to, address indexed _from, uint256 _amount);
	event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

	bool initialized = false;

	function initialize(address _owner, address _handlerLogicAddress) public {
		require(initialized == false, "Already initialized");
		initialized = true;

		handlerLogicAddress = _handlerLogicAddress;
		owner = _owner;
	}

	/**
	 * Anyone can call the function to deploy a new payment handler.
	 * The new contract will be created, added to the list, and an event fired.
	 */
	function deployNewHandler() public {
		// Deploy the new Proxy contract with the handler logic address
		Proxy createdProxy = new Proxy(handlerLogicAddress);

		// instantiate a PaymentHandler contract at the created Proxy address
		PaymentHandler proxyHandler = PaymentHandler(address(createdProxy));

		// initialize the Proxy with this contract's address
		proxyHandler.initialize(this);

		// Add it to the list and the mapping
		handlerList.push(address(createdProxy));
		handlerMap[address(createdProxy)] = true;

		// Emit event to let watchers know that a new handler was created
		emit HandlerCreated(address(createdProxy));
	}

	/**
	 * Allows caller to determine how long the handler list is for convenience
	 */
	function getHandlerListLength() public view returns (uint) {
		return handlerList.length;
	}

	/**
	 * This function is called by handlers when they receive ETH payments.
	 */
	function firePaymentReceivedEvent(address to, address from, uint256 amount) public {
		// Verify the call is coming from a handler
		require(handlerMap[msg.sender], "Only payment handlers are allowed to trigger payment events.");

		// Emit the event
		emit EthPaymentReceived(to, from, amount);
	}

	/**
	 * Allows a caller to sweep multiple handlers in one transaction
	 */
	function multiHandlerSweep(address[] memory handlers, IERC20 tokenContract) public {
		for (uint i = 0; i < handlers.length; i++) {

			// Whitelist calls to only handlers
			require(handlerMap[handlers[i]], "Only payment handlers are valid sweep targets.");

			// Trigger sweep
			PaymentHandler(address(uint160(handlers[i]))).sweepTokens(tokenContract);
		}
	}

	/**
	 * Safety function to allow sweep of ERC20s if accidentally sent to this contract
	 */
	function sweepTokens(IERC20 token) public {
		// Get the current balance
		uint balance = token.balanceOf(address(this));

		// Transfer to the owner
		token.safeTransfer(owner, balance);
	}

	function transferOwnership(address newOwner) public {
		require(msg.sender == owner, "Not owner");
		owner = newOwner;
		emit OwnershipTransferred(msg.sender, newOwner);
	}
}
/**
 * The PaymentMaster sits above the payment handler contracts.
 * It deploys and keeps track of all the handlers.
 * It can trigger events by child handlers when they receive ETH.
 * It allows ERC20 tokens to be swept in bulk to the owner account.
 */
function multiHandlerSweep(address[] memory handlers, IERC20 tokenContract) public {
	for (uint i = 0; i < handlers.length; i++) {

		// Whitelist calls to only handlers
		require(handlerMap[handlers[i]], "Only payment handlers are valid sweep targets.");

		// Trigger sweep
		PaymentHandler(address(uint160(handlers[i]))).sweepTokens(tokenContract);
	}
}

/**
 	 * Allows a caller to sweep multiple handlers in one transaction
 	 */