Failed when call the contract/

I created the contract and used Remix to deploy it for arbitrage purposes. Almost all functions—executeFlashSwap, swapOnSushiSwap, and swapOnUniswap—succeed when I call them independently. However, when I combine them into a single code, it fails and raises the following error:

"Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? Cannot read properties of undefined (reading 'includes')"

I hope you can help me resolve this issue. Thank you so much!
Here is my code.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Callee.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
// import "@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol";

contract ArbitrageBot is IUniswapV2Callee {
    IUniswapV2Factory private factory;
    IUniswapV2Router02 private sushiSwapRouter;
    IUniswapV2Router02 private uniswapRouter;
    IERC20 private tokenA;
    IERC20 private tokenB;

    address private pair;
    uint256 public amountToRepay;

    constructor(address _factory, address _sushiSwapRouter, address _uniswapRouter, address _tokenA, address _tokenB) {
        factory = IUniswapV2Factory(_factory);
        sushiSwapRouter = IUniswapV2Router02(_sushiSwapRouter);
        uniswapRouter = IUniswapV2Router02(_uniswapRouter);
        tokenA = IERC20(_tokenA);
        tokenB = IERC20(_tokenB);
        
        pair = factory.getPair(address(tokenA), address(tokenB));
    }

    // Initiate the flashswap
    function executeFlashSwap(uint256 amountTokenA) external {
        require(pair != address(0), "Pair doesn't exist");

        bytes memory data = abi.encode(tokenA, msg.sender);
        IUniswapV2Pair(pair).swap(0, amountTokenA, address(this), data);
    }

    // This is the callback function triggered by the flashswap
    function uniswapV2Call(
        address sender,
        uint256 amount0,
        uint256 amount1,
        bytes calldata data
    ) external override {
        require(msg.sender == pair, "Invalid pair caller");
        require(sender == address(this), "Invalid sender");

        (address tokenBorrow, address initiator) = abi.decode(data, (address, address));

        uint256 amountBorrowed = amount1; // Assuming tokenA is the borrowed token
        uint256 fee = (amountBorrowed * 3) / 997 + 1; // Flash swap fee
        amountToRepay = amountBorrowed + fee;

        // Step 1: Swap token A (borrowed) to token B on SushiSwap
        uint256 amountTokenB = swapOnSushiSwap(tokenA, tokenB, amountBorrowed);

        // Step 2: Swap token B back to token A on Uniswap
        uint256 amountTokenAReceived = swapOnUniswap(tokenB, tokenA, amountTokenB);

        // Step 3: Check for profit and repay
        require(amountTokenAReceived > amountToRepay, "No arbitrage profit");

        tokenA.transfer(pair, amountToRepay); // Repay the flashloan
        tokenA.transfer(initiator, amountTokenAReceived - amountToRepay); // Profit
    }

    // Helper function to swap tokens on SushiSwap
    function swapOnSushiSwap(
        IERC20 _tokenIn,
        IERC20 _tokenOut,
        uint256 amountIn
    ) internal returns (uint256) {
        _tokenIn.approve(address(sushiSwapRouter), amountIn);
        address[] memory path = new address[](2);
        path[0] = address(_tokenIn);
        path[1] = address(_tokenOut);

        uint256[] memory amountsOut = sushiSwapRouter.swapExactTokensForTokens(
            amountIn,
            1, // minimum amount out (can be adjusted)
            path,
            address(this),
            block.timestamp + 1200 // 20 minute deadline
        );

        return amountsOut[1]; // amount of token B received
    }

    // Helper function to swap tokens on Uniswap
    function swapOnUniswap(
        IERC20 _tokenIn,
        IERC20 _tokenOut,
        uint256 amountIn
    ) internal returns (uint256) {
        _tokenIn.approve(address(uniswapRouter), amountIn);
        address[] memory path = new address[](2);
        path[0] = address(_tokenIn);
        path[1] = address(_tokenOut);

        uint256[] memory amountsOut = uniswapRouter.swapExactTokensForTokens(
            amountIn,
            1, // minimum amount out (can be adjusted)
            path,
            address(this),
            block.timestamp + 1200 // 20 minute deadline
        );

        return amountsOut[1]; // amount of token A received
    }
}

Hi, welcome to the community! :wave:

You can simulate the transaction to debug the transaction.
Maybe Hardhat, Foundry, Tenderly or whatever you want to fork a network to test.