contract RelayerManager is PaymentDeposit {

    mapping(address => bool) public relayers;

    event RelayerInstalled(address relayer);
    event RelayerUninstalled(address relayer);

    modifier onlyRelayer {
        require(relayers[msg.sender], "Only relayer can call this function.");
        _;
    }

    /** 
     * @param newOwner Owner of contract
     * @dev Owner cannot be a relayer or this contract.
     */
    function transferOwnership(address newOwner) public override onlyOwner { 
        require(!relayers[newOwner], "Relayer cannot be an owner.");
        require(newOwner != address(this), "Contract cannot own itself.");
        _transferOwnership(newOwner);
    }

    /**
     * @param _relayer New relayer address
     * @dev Only the owner can install a new relayer
     */
    function installRelayer(address _relayer) onlyOwner public {
        require(!relayers[_relayer], "Relayer is already installed.");
        require(_relayer != address(this), "The relay contract cannot be installed as a relayer.");
        require(_relayer != owner(), "Avoid mixing relayer and owner roles.");

        relayers[_relayer] = true;
        emit RelayerInstalled(_relayer);
    }

    /** 
     * @param _relayer New relayer address
     * @dev Only the owner can uninstall a new relayer
     */ 
    function uninstallRelayer(address _relayer) onlyOwner public {
        require(relayers[_relayer], "Relayer must be installed.");

        relayers[_relayer] = false;
        emit RelayerUninstalled(_relayer);
    }


    /** 
     * @param _recipient Receiver of the topup
     * @param _maxBalance Maximum topup to send 
     * Called by a relayer to perform a relative top up.
     * Only sends enough funds for relayer to reach max balance. 
     */  
    function relativeTopUp(address payable _recipient, uint256 _maxBalance) public onlyRelayer {
        require(relayers[_recipient], "Recipient must be a relayer to receive a top up.");
        uint256 relayerBalance = address(_recipient).balance;

        // The contract or relayer must be pre-collateralized with the
        // max balance in advance. So if maxBalance = 3 ETH, then a new relayer
        // should have a balance at or greater than 3 ETH.
        if (_maxBalance > relayerBalance) {
            uint256 toTopUp = _maxBalance - relayerBalance;
            withdraw(msg.sender, _recipient, toTopUp);
        }
    }

    /**
     * @param _recipient Receiver of the topup
     * @param _topUp Funds to send
     * Called by a relayer to perform an "absolute" top up.
     * It can exceed the expected max balance of a relayer.
     */ 
    function absoluteTopUp(address payable _recipient, uint256 _topUp) public onlyRelayer {
        require(relayers[_recipient], "Recipient must be a relayer to receive an emergency topup.");
        withdraw(msg.sender, _recipient, _topUp);
    }
}
/**
 * @author Patrick McCorry & Chris Buckland (ITX)
 * @title Relayer Manager contract
 * @notice  Manage relayers and issue topups 
 */
function relativeTopUp(address payable _recipient, uint256 _maxBalance) public onlyRelayer {
    require(relayers[_recipient], "Recipient must be a relayer to receive a top up.");
    uint256 relayerBalance = address(_recipient).balance;

    // The contract or relayer must be pre-collateralized with the
    // max balance in advance. So if maxBalance = 3 ETH, then a new relayer
    // should have a balance at or greater than 3 ETH.
    if (_maxBalance > relayerBalance) {
        uint256 toTopUp = _maxBalance - relayerBalance;
        withdraw(msg.sender, _recipient, toTopUp);
    }
}

/** 
 * @param _recipient Receiver of the topup
 * @param _maxBalance Maximum topup to send 
 * Called by a relayer to perform a relative top up.
 * Only sends enough funds for relayer to reach max balance. 
 */