abstract contract LiquidityPoolConverter is ConverterBase {
    /**
      * @dev triggered after liquidity is added
      *
      * @param  _provider       liquidity provider
      * @param  _reserveToken   reserve token address
      * @param  _amount         reserve token amount
      * @param  _newBalance     reserve token new balance
      * @param  _newSupply      pool token new supply
    */
    event LiquidityAdded(
        address indexed _provider,
        IERC20Token indexed _reserveToken,
        uint256 _amount,
        uint256 _newBalance,
        uint256 _newSupply
    );

    /**
      * @dev triggered after liquidity is removed
      *
      * @param  _provider       liquidity provider
      * @param  _reserveToken   reserve token address
      * @param  _amount         reserve token amount
      * @param  _newBalance     reserve token new balance
      * @param  _newSupply      pool token new supply
    */
    event LiquidityRemoved(
        address indexed _provider,
        IERC20Token indexed _reserveToken,
        uint256 _amount,
        uint256 _newBalance,
        uint256 _newSupply
    );

    /**
      * @dev initializes a new LiquidityPoolConverter instance
      *
      * @param  _anchor             anchor governed by the converter
      * @param  _registry           address of a contract registry contract
      * @param  _maxConversionFee   maximum conversion fee, represented in ppm
    */
    constructor(
        IConverterAnchor _anchor,
        IContractRegistry _registry,
        uint32 _maxConversionFee
    )
        ConverterBase(_anchor, _registry, _maxConversionFee)
        internal
    {
    }

    /**
      * @dev accepts ownership of the anchor after an ownership transfer
      * also activates the converter
      * can only be called by the contract owner
      * note that prior to version 28, you should use 'acceptTokenOwnership' instead
    */
    function acceptAnchorOwnership() public virtual override {
        // verify that the converter has at least 2 reserves
        require(reserveTokenCount() > 1, "ERR_INVALID_RESERVE_COUNT");
        super.acceptAnchorOwnership();
    }
}
/**
 * @dev Liquidity Pool Converter
 *
 * The liquidity pool converter is the base contract for specific types of converters that
 * manage liquidity pools.
 *
 * Liquidity pools have 2 reserves or more and they allow converting between them.
 *
 * Note that TokenRateUpdate events are dispatched for pool tokens as well.
 * The pool token is the first token in the event in that case.
 */
function acceptAnchorOwnership() public virtual override {
    // verify that the converter has at least 2 reserves
    require(reserveTokenCount() > 1, "ERR_INVALID_RESERVE_COUNT");
    super.acceptAnchorOwnership();
}

/**
 * @dev accepts ownership of the anchor after an ownership transfer
 * also activates the converter
 * can only be called by the contract owner
 * note that prior to version 28, you should use 'acceptTokenOwnership' instead
 */