“Error: Transaction has been reverted by the EVM” <- don’t even know where to start

https://ethereum.stackexchange.com/questions/144998/error-transaction-has-been-reverted-by-the-evm-don-t-even-know-where-to-st

So, first off, I have checked every single question on this topic, and it seems to come down to the particulars of the code. I can’t find a throughline for any of them.

That said, I have a bot that is signing and sending blockchain transactions on behalf of an arbitrage contract. However, when I try to sign and send a transaction, I get the error stack below. What’s going wrong and how can I fix this?

The code:

  if (config.PROJECT_SETTINGS.isDeployed) {
      const tradeData = await arbitrage.methods.executeTrade(startOnUniswap, _token0Contract._address, _token1Contract._address, payOut).encodeABI();
      const nonce = await web3.eth.getTransactionCount(account);
      const gasPrice = await web3.eth.getGasPrice();
      const gasLimit = 200000;
      const rawTransaction = {
         from: account,
         nonce: web3.utils.toHex(nonce),
         gasPrice: web3.utils.toHex(gasPrice),
         gasLimit: web3.utils.toHex(gasLimit),
         to: arbitrage._address,
         data: tradeData,
                };
const signedTransaction = await web3.eth.accounts.signTransaction(rawTransaction, process.env.PRIVATE_KEY);
await web3.eth.sendSignedTransaction(signedTransaction.rawTransaction);
            }

The arbitrage contract:

// SPDX-License-Identifier: MIT
pragma solidity <=0.8.10;
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface Structs {
    struct Val {
        uint256 value;
    }
    enum ActionType {
        Deposit, // supply tokens
        Withdraw, // borrow tokens
        Transfer, // transfer balance between accounts
        Buy, // buy an amount of some token (externally)
        Sell, // sell an amount of some token (externally)
        Trade, // trade tokens against another account
        Liquidate, // liquidate an undercollateralized or expiring account
        Vaporize, // use excess tokens to zero-out a completely negative account
        Call // send arbitrary data to an address
    }
    enum AssetDenomination {
        Wei // the amount is denominated in wei
    }
    enum AssetReference {
        Delta // the amount is given as a delta from the current value
    }
    struct AssetAmount {
        bool sign; // true if positive
        AssetDenomination denomination;
        AssetReference ref;
        uint256 value;
    }
    struct ActionArgs {
        ActionType actionType;
        uint256 accountId;
        AssetAmount amount;
        uint256 primaryMarketId;
        uint256 secondaryMarketId;
        address otherAddress;
        uint256 otherAccountId;
        bytes data;
    }
    struct Info {
        address owner; // The address that owns the account
        uint256 number; // A nonce that allows a single address to control many accounts
    }
    struct Wei {
        bool sign; // true if positive
        uint256 value;
    }
}
abstract contract DyDxPool is Structs {
    function getAccountWei(Info memory account, uint256 marketId)
        public
        view
        virtual
        returns (Wei memory);
    function operate(Info[] memory, ActionArgs[] memory) public virtual;
}
contract DyDxFlashLoan is Structs {
    DyDxPool pool = DyDxPool(0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e);
    address public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    mapping(address => uint256) public currencies;
    constructor() {
        currencies[WETH] = 1;
    }
    modifier onlyPool() {
        require(
            msg.sender == address(pool),
            "FlashLoan: could be called by DyDx pool only"
        );
        _;
    }
    function tokenToMarketId(address token) public view returns (uint256) {
        uint256 marketId = currencies[token];
        require(marketId != 0, "FlashLoan: Unsupported token");
        return marketId - 1;
    }
    // the DyDx will call `callFunction(address sender, Info memory accountInfo, bytes memory data) public` after during `operate` call
    function flashloan(
        address token,
        uint256 amount,
        bytes memory data
    ) internal {
        IERC20(token).approve(address(pool), amount + 1);
        Info[] memory infos = new Info[](1);
        ActionArgs[] memory args = new ActionArgs[](3);
        infos[0] = Info(address(this), 0);
        AssetAmount memory wamt = AssetAmount(
            false,
            AssetDenomination.Wei,
            AssetReference.Delta,
            amount
        );
        ActionArgs memory withdraw;
        withdraw.actionType = ActionType.Withdraw;
        withdraw.accountId = 0;
        withdraw.amount = wamt;
        withdraw.primaryMarketId = tokenToMarketId(token);
        withdraw.otherAddress = address(this);
        args[0] = withdraw;
        ActionArgs memory call;
        call.actionType = ActionType.Call;
        call.accountId = 0;
        call.otherAddress = address(this);
        call.data = data;
        args[1] = call;
        ActionArgs memory deposit;
        AssetAmount memory damt = AssetAmount(
            true,
            AssetDenomination.Wei,
            AssetReference.Delta,
            amount + 1
        );
        deposit.actionType = ActionType.Deposit;
        deposit.accountId = 0;
        deposit.amount = damt;
        deposit.primaryMarketId = tokenToMarketId(token);
        deposit.otherAddress = address(this);
        args[2] = deposit;
        pool.operate(infos, args);
    }
}
contract Arbitrage is DyDxFlashLoan {
    IUniswapV2Router02 public immutable sRouter;
    IUniswapV2Router02 public immutable uRouter;
    address public owner;
    constructor(address _sRouter, address _uRouter) {
        sRouter = IUniswapV2Router02(_sRouter); // Sushiswap
        uRouter = IUniswapV2Router02(_uRouter); // Uniswap
        owner = msg.sender;
    }
    function executeTrade(
        bool _startOnUniswap,
        address _token0,
        address _token1,
        uint256 _flashAmount
    ) external {
        uint256 balanceBefore = IERC20(_token0).balanceOf(address(this));
        bytes memory data = abi.encode(
            _startOnUniswap,
            _token0,
            _token1,
            _flashAmount,
            balanceBefore
        );
        flashloan(_token0, _flashAmount, data); // execution goes to `callFunction`
    }
    function callFunction(
        address, /* sender */
        Info calldata, /* accountInfo */
        bytes calldata data
    ) external onlyPool {
        (
            bool startOnUniswap,
            address token0,
            address token1,
            uint256 flashAmount,
            uint256 balanceBefore
        ) = abi.decode(data, (bool, address, address, uint256, uint256));
        uint256 balanceAfter = IERC20(token0).balanceOf(address(this));
        require(
            balanceAfter - balanceBefore == flashAmount,
            "contract did not get the loan"
        );
        // Use the money here!
        address[] memory path = new address[](2);
        path[0] = token0;
        path[1] = token1;
        if (startOnUniswap) {
            _swapOnUniswap(path, flashAmount, 0);
            path[0] = token1;
            path[1] = token0;
            _swapOnSushiswap(
                path,
                IERC20(token1).balanceOf(address(this)),
                (flashAmount + 1)
            );
        } else {
            _swapOnSushiswap(path, flashAmount, 0);
            path[0] = token1;
            path[1] = token0;
            _swapOnUniswap(
                path,
                IERC20(token1).balanceOf(address(this)),
                (flashAmount + 1)
            );
        }
        IERC20(token0).transfer(
            owner,
            IERC20(token0).balanceOf(address(this)) - (flashAmount + 1)
        );
    }
    // -- INTERNAL FUNCTIONS -- //
    function _swapOnUniswap(
        address[] memory _path,
        uint256 _amountIn,
        uint256 _amountOut
    ) internal {
        require(
            IERC20(_path[0]).approve(address(uRouter), _amountIn),
            "Uniswap approval failed."
        );
        uRouter.swapExactTokensForTokens(
            _amountIn,
            _amountOut,
            _path,
            address(this),
            (block.timestamp + 1200)
        );
    }
    function _swapOnSushiswap(
        address[] memory _path,
        uint256 _amountIn,
        uint256 _amountOut
    ) internal {
        require(
            IERC20(_path[0]).approve(address(sRouter), _amountIn),
            "Sushiswap approval failed."
        );
        sRouter.swapExactTokensForTokens(
            _amountIn,
            _amountOut,
            _path,
            address(this),
            (block.timestamp + 1200)
        );
    }
}

The error:

Error: Transaction has been reverted by the EVM:
{
  "blockHash": "0xeed5773a3228dd01bef285bbb3139f6d2170323058703e8cf30bc8ba6a927342",
  "blockNumber": 16632255,
  "contractAddress": null,
  "cumulativeGasUsed": 24687572,
  "effectiveGasPrice": 28667583352,
  "from": "0xdf58ca0a02bf9b43ce13b8ab5969e4b60f22c0a3",
  "gasUsed": 196577,
  "logs": [],
  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "status": false,
  "to": "0x4a15775657e7720bbd9cb7039484ed0510be6689",
  "transactionHash": "0x5a748a0fd8c21898021823a424da94576f5d794ed9867bd62a7bd3027473ce00",
  "transactionIndex": 301,
  "type": "0x0"
}
    at Object.TransactionError (/Users/TrentKennelly/trading_bot_V2/node_modules/web3-core-helpers/lib/errors.js:87:21)
    at Object.TransactionRevertedWithoutReasonError (/Users/TrentKennelly/trading_bot_V2/node_modules/web3-core-helpers/lib/errors.js:98:21)
    at /Users/TrentKennelly/trading_bot_V2/node_modules/web3-core-method/lib/index.js:396:57
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  receipt: {
    blockHash: '0xeed5773a3228dd01bef285bbb3139f6d2170323058703e8cf30bc8ba6a927342',
    blockNumber: 16632255,
    contractAddress: null,
    cumulativeGasUsed: 24687572,
    effectiveGasPrice: 28667583352,
    from: '0xdf58ca0a02bf9b43ce13b8ab5969e4b60f22c0a3',
    gasUsed: 196577,
    logs: [],
    logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    status: false,
    to: '0x4a15775657e7720bbd9cb7039484ed0510be6689',
    transactionHash: '0x5a748a0fd8c21898021823a424da94576f5d794ed9867bd62a7bd3027473ce00',
    transactionIndex: 301,
    type: '0x0'
  }
}

I’m at a total loss as to what this could be. Any help is GREATLY appreciated!