contract MixinExchangeManager is
    IStakingEvents,
    MixinStorage
{
    /// @dev Asserts that the call is coming from a valid exchange.
    modifier onlyExchange() {
        if (!validExchanges[msg.sender]) {
            LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableByExchangeError(
                msg.sender
            ));
        }
        _;
    }

    /// @dev Adds a new exchange address
    /// @param addr Address of exchange contract to add
    function addExchangeAddress(address addr)
        external
        onlyAuthorized
    {
        if (validExchanges[addr]) {
            LibRichErrors.rrevert(LibStakingRichErrors.ExchangeManagerError(
                LibStakingRichErrors.ExchangeManagerErrorCodes.ExchangeAlreadyRegistered,
                addr
            ));
        }
        validExchanges[addr] = true;
        emit ExchangeAdded(addr);
    }

    /// @dev Removes an existing exchange address
    /// @param addr Address of exchange contract to remove
    function removeExchangeAddress(address addr)
        external
        onlyAuthorized
    {
        if (!validExchanges[addr]) {
            LibRichErrors.rrevert(LibStakingRichErrors.ExchangeManagerError(
                LibStakingRichErrors.ExchangeManagerErrorCodes.ExchangeNotRegistered,
                addr
            ));
        }
        validExchanges[addr] = false;
        emit ExchangeRemoved(addr);
    }
}
function addExchangeAddress(address addr)
    external
    onlyAuthorized
{
    if (validExchanges[addr]) {
        LibRichErrors.rrevert(LibStakingRichErrors.ExchangeManagerError(
            LibStakingRichErrors.ExchangeManagerErrorCodes.ExchangeAlreadyRegistered,
            addr
        ));
    }
    validExchanges[addr] = true;
    emit ExchangeAdded(addr);
}

/// @dev Adds a new exchange address
/// @param addr Address of exchange contract to add