    function migrate(IBathToken bathTokenV1) external {
        //////////////// V1 WITHDRAWAL ////////////////
        uint256 bathBalance = bathTokenV1.balanceOf(msg.sender);
        require(bathBalance > 0, "migrate: ZERO AMOUNT");

        /// @dev approve first
        bathTokenV1.transferFrom(msg.sender, address(this), bathBalance);

        // withdraw all tokens from the pool
        uint256 amountWithdrawn = bathTokenV1.withdraw(bathBalance);

        //////////////// V2 DEPOSIT ////////////////
        IERC20 underlying = bathTokenV1.underlyingToken();
        address bathTokenV2 = v1ToV2Pools[address(bathTokenV1)];

        underlying.approve(bathTokenV2, amountWithdrawn);
        require(
            CErc20Interface(bathTokenV2).mint(amountWithdrawn) == 0,
            "migrate: MINT FAILED"
        );
        /// @dev v2 bathTokens shouldn't be sent to this contract from anywhere other than this function
        IERC20(bathTokenV2).transfer(
            msg.sender,
            IERC20(bathTokenV2).balanceOf(address(this))
        );
        ...
    }
    function _withdraw(
        uint256 _shares,
        address receiver
    ) internal returns (uint256 amountWithdrawn) {
        uint256 r = (underlyingBalance().mul(_shares)).div(totalSupply);
        _burn(msg.sender, _shares);
        uint256 _fee = r.mul(feeBPS).div(10000);
        // If FeeTo == address(0) then the fee is effectively accrued by the pool
        if (feeTo != address(0)) {
            underlyingToken.safeTransfer(feeTo, _fee);
        }
        amountWithdrawn = r.sub(_fee);
        underlyingToken.safeTransfer(receiver, amountWithdrawn);
        ...
    }
    function setBathTokenFeeBPS(address bathToken, uint256 newBPS)
        external
        onlyAdmin
    {
        IBathToken(bathToken).setFeeBPS(newBPS);
    }
