LOW severity: `CollateralMigrator` reverts when pre-existing funds are used for flash loan fees. **Description:** The flow for migrating collateral between two markets is as follows:

1. The end user calls `CollateralMigrator::migrateCollateral` with the required swap parameters.
2. `CollateralMigrator` takes a flash loan from a Trader Joe liquidity pair.
3. Using the flash loan,...

Vulnerable code:
uint256 contractBalanceBF = IERC20(trgMarketConfig.flashData.baseToken).balanceOf(address(this));

// Swap the underlying asset from the source market to the target market
_swap(
    ...
);

// Return the flash loaned amount to the liquidity book pair
uint256 flashAmountWithFee = flashAmount +
    (trgMarketConfig.flashData.isTokenX ? totalFees.decodeX() : totalFees.decodeY());

// IEIP20NonStandard(flashData.baseToken).transfer(address(flashData.liquidityBookPair), flashAmountWithFee);
IERC20(trgMarketConfig.flashData.baseToken).safeTransfer(
    address(trgMarketConfig.flashData.liquidityBookPair),
    flashAmountWithFee
);

// Return the remaining underlying asset to the market
uint256 contractBalanceAF = IERC20(trgMarketConfig.flashData.baseToken).balanceOf(address(this));
// @audit if existing funds were used to pay fees, this will underflow
uint256 remainingAmount = contractBalanceAF - contractBalanceAF - contractBalanceBF;

it("Migrate will not work when existing balance is used for fees", async function () {
    const { user, collateralMigrator, swapRouter, qiUSDT, qiDAI, USDT, DAI, usdtDaiLBPair } = await loadFixture(setupEnv);

    const fromMarket = qiUSDT.address;
    const toMarket = qiDAI.address;

    const fromAsset = USDT.address;
    const toAsset = DAI.address;
    const migrationAmount = parseEther("200");

    await usdtDaiLBPair.connect(user).setFeeBps(1000); // 10%

    await USDT.connect(user).mint(user.address, migrationAmount);
    await DAI.connect(user).mint(collateralMigrator.address, parseEther("20"));

    // we simulate that we need the amount of a flash loan for all 100% of the position (exchange rate 1:1)
    const flashAmount = parseEther("200");

    const data = swapRouter.interface.encodeFunctionData("swap", [
        fromAsset,
        toAsset,
        parseEther("200"),
        parseEther("200")
    ]);

    const swapParams = {
        fromAsset,
        toAsset,
        fromAssetAmount: parseEther("200"),
        minToAssetAmount: parseEther("200"),
        data: data
    };

    // approve the collateral migrator to spend the collateral
    await USDT.connect(user).approve(qiUSDT.address, MaxUint256);
    await qiUSDT.connect(user).mint(migrationAmount);

    await qiUSDT.connect(user).approve(collateralMigrator.address, migrationAmount);

    await expect(
        collateralMigrator
            .connect(user)
            .migrateCollateral(fromMarket, toMarket, migrationAmount, flashAmount, swapParams)
        ).to.be.reverted; // revert on underflow
});

diff --git a/contracts/mocks/MockLBPair.sol b/contracts/mocks/MockLBPair.sol
index 6074fa2..a1d28bd 100644
--- a/contracts/mocks/MockLBPair.sol
+++ b/contracts/mocks/MockLBPair.sol
@@ -16,6 +16,8 @@ contract MockLBPair {
     uint16 private _binStep;
     address private _factory;

+    uint128 feeBps;
+
     constructor(address tokenX, address tokenY, uint16 binStep, address factory) {
         _tokenX = tokenX;
         _tokenY = tokenY;
@@ -42,15 +44,21 @@ contract MockLBPair {
     function flashLoan(ILBFlashLoanCallback receiver, bytes32 amounts, bytes calldata data) external {
         (uint amountX, uint amountY) = amounts.decode();

+        bytes32 fees;
+
         if (amountX > 0 && amountY == 0) {
             IERC20(_tokenX).transfer(address(receiver), amountX);
+            uint128 feeX = uint128(amountX) * feeBps / 10000;
+            fees = feeX.encode(0);
         } else if (amountX == 0 && amountY > 0) {
             IERC20(_tokenY).transfer(address(receiver), amountY);
+            uint128 feeY = uint128(amountY) * feeBps / 10000;
+            fees = uint128(0).encode(feeY);
         } else {
             revert("MockLBPair: INVALID_AMOUNTS");
         }

-        receiver.LBFlashLoanCallback(msg.sender, _tokenX, _tokenY, amounts, 0, data);
+        receiver.LBFlashLoanCallback(msg.sender, _tokenX, _tokenY, amounts, fees, data);
     }

     function encodeAmounts(uint128 amountX, uint128 amountY) external pure returns (bytes32) {
@@ -86,4 +94,8 @@ contract MockLBPair {
     function getFactory() external view returns (address factory) {
         return _factory;
     }
+
+    function setFeeBps(uint128 _feeBps) external {
+        feeBps = _feeBps;
+    }
 }