const { ethers } = require('ethers');
const { Token, CurrencyAmount, Percent, TradeType } = require('@uniswap/sdk-core');
const { Pool, Route, Trade, SwapRouter } = require('@uniswap/v3-sdk');
const IUniswapV3PoolABI = require('@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json').abi;
const Quoter = require('@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json').abi;
const IERC20 = require('@uniswap/v2-periphery/build/IERC20.json');

const SWAP_ROUTER_ADDRESS = '0xe592427a0aece92de3edee1f18e0157c05861564';
const WALLET_ADDRESS = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
const WALLET_SECRET = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
const INFURA_TEST_URL = 'https://mainnet.infura.io/v3/2d5bc62bb8d748cebfc64763e719cb4f';
const POOL_FACTORY_CONTRACT_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984';
const QUOTER_CONTRACT_ADDRESS = '0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6';

const provider = new ethers.providers.JsonRpcProvider(INFURA_TEST_URL);
const chainId = 1;

const wallet = new ethers.Wallet(WALLET_SECRET, provider);

const token0 = new Token(chainId, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH', 'Wrapped Ether');
const token1 = new Token(chainId, '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', 18, 'UNI', 'Uniswap Token');

const fee = 3000; // Change the fee tier as required (500 for low, 3000 for medium, and 10000 for high)

async function main() {
  try {
    const poolInfo = await getPoolInfo();

    const pool = new Pool(token0, token1, fee, poolInfo.sqrtPriceX96.toString(), poolInfo.liquidity.toString(), poolInfo.tick);

    const swapRoute = new Route([pool], token0, token1);
    const amountIn = fromReadableAmount('0.001', 18);
    const quotedAmountOut = await getOutputQuote(amountIn);

    const uncheckedTrade = Trade.createUncheckedTrade({
      route: swapRoute,
      inputAmount: CurrencyAmount.fromRawAmount(token0, amountIn),
      outputAmount: CurrencyAmount.fromRawAmount(token1, quotedAmountOut.toString()),
      tradeType: TradeType.EXACT_INPUT,
    });

    await getTokenTransferApproval(token0.address);

    const options = {
      slippageTolerance: new Percent(50, 10_000), // 50 bips, or 0.50%
      deadline: Math.floor(Date.now() / 1000) + 60 * 20, // 20 minutes from the current Unix time
    };

    const methodParameters = SwapRouter.swapCallParameters(uncheckedTrade, options);
    console.log('Address to validate:', methodParameters.address);

    const tx = {
      data: methodParameters.calldata,
      to: methodParameters.address,
      value: methodParameters.value,
      gasLimit: ethers.BigNumber.from('100000'), // Add a suitable value for the gas limit
      gasPrice: await provider.getGasPrice(),
    };

    const res = await sendTransaction(tx);
    console.log(res);
  } catch (e) {
    console.log(e);
  }
}
main();

async function getPoolInfo() {
  try {
    // Fixed from here
    const currentPoolAddress = Pool.getAddress(token0, token1, fee);

    const poolContract = new ethers.Contract(currentPoolAddress, IUniswapV3PoolABI, provider);

    const [poolToken0, poolToken1, poolFee, tickSpacing, liquidity, slot0] = await Promise.all([
      poolContract.token0(),
      poolContract.token1(),
      poolContract.fee(),
      poolContract.tickSpacing(),
      poolContract.liquidity(),
      poolContract.slot0(),
    ]);

    return {
      token0: poolToken0,
      token1: poolToken1,
      fee: poolFee,
      tickSpacing,
      liquidity,
      sqrtPriceX96: slot0[0],
      tick: slot0[1],
    };
  } catch (e) {
    console.log(e);
  }
}

async function getOutputQuote(amountIn) {
  try {
    const quoterContract = new ethers.Contract(QUOTER_CONTRACT_ADDRESS, Quoter, provider);

    const quotedAmountOut = await quoterContract.callStatic.quoteExactInputSingle(token0.address, token1.address, fee, amountIn, 0);
    return quotedAmountOut;
  } catch (e) {
    console.log(e);
  }
}

function fromReadableAmount(amount, decimals) {
  try {
    const value = ethers.utils.parseUnits(amount, decimals);
    return value.toString();
  } catch (e) {
    console.log(e);
  }
}

async function getTokenTransferApproval(tokenAddress) {
  try {
    const tokenContract = new ethers.Contract(tokenAddress, IERC20.abi, wallet);

    const spender = SWAP_ROUTER_ADDRESS;
    const approvalAmount = ethers.constants.MaxUint256;
    const connectedTokenContract = tokenContract.connect(wallet);
    // Approve the spender (swap router) to spend the tokens on behalf of the user
    const approvalTx = await connectedTokenContract.approve(spender, approvalAmount);

    // Wait for the approval transaction to be mined
    const approvalReceipt = await approvalTx.wait();
    // Check if the approval transaction was successful
    if (approvalReceipt.status !== 1) {
      throw new Error('Token transfer approval failed');
    }

    // Return the approval transaction hash or any other relevant information
    return approvalReceipt.transactionHash;
  } catch (e) {
    console.log(e);
  }
}

async function sendTransaction(tx) {
  try {
    // Sign the transaction with the wallet's private key
    const signedTx = await wallet.signTransaction(tx);

    // Send the signed transaction
    const txResponse = await provider.sendTransaction(signedTx);

    // Wait for the transaction to be mined
    const txReceipt = await txResponse.wait();

    // Check if the transaction was successful
    if (txReceipt.status !== 1) {
      throw new Error('Transaction failed');
    }

    // Return the transaction hash or any other relevant information
    return txReceipt.transactionHash;
  } catch (e) {
    console.log(e);
  }
} this code with this error PS C:\Users\lidor\Desktop\Trade Bot> node .
<ref *1> Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (error={"reason":"cannot estimate gas; transaction may fail or may require manual gas limit","code":"UNPREDICTABLE_GAS_LIMIT","error":{"reason":"processing response error","code":"SERVER_ERROR","body":"{\"jsonrpc\":\"2.0\",\"id\":58,\"error\":{\"code\":-32000,\"message\":\"gas required exceeds allowance (0)\"}}","error":{"code":-32000},"requestBody":"{\"method\":\"eth_estimateGas\",\"params\":[{\"type\":\"0x2\",\"maxFeePerGas\":\"0xc96f3bba8\",\"maxPriorityFeePerGas\":\"0x59682f00\",\"from\":\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\"to\":\"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\"data\":\"0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"}],\"id\":58,\"jsonrpc\":\"2.0\"}","requestMethod":"POST","url":"https://mainnet.infura.io/v3/2d5bc62bb8d748cebfc64763e719cb4f"},"method":"estimateGas","transaction":{"from":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","maxPriorityFeePerGas":{"type":"BigNumber","hex":"0x59682f00"},"maxFeePerGas":{"type":"BigNumber","hex":"0x0c96f3bba8"},"to":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","data":"0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","type":2,"accessList":null}}, tx={"data":"0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","to":{},"from":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","type":2,"maxFeePerGas":{"type":"BigNumber","hex":"0x0c96f3bba8"},"maxPriorityFeePerGas":{"type":"BigNumber","hex":"0x59682f00"},"nonce":{},"gasLimit":{},"chainId":{}}, code=UNPREDICTABLE_GAS_LIMIT, version=abstract-signer/5.7.0)   
    at Logger.makeError (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\logger\lib\index.js:238:21)
    at Logger.throwError (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\logger\lib\index.js:247:20)
    at C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\abstract-signer\lib\index.js:365:47
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Promise.all (index 7) {
  reason: 'cannot estimate gas; transaction may fail or may require manual gas limit',
  code: 'UNPREDICTABLE_GAS_LIMIT',
  error: Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (error={"reason":"processing response error","code":"SERVER_ERROR","body":"{\"jsonrpc\":\"2.0\",\"id\":58,\"error\":{\"code\":-32000,\"message\":\"gas required exceeds allowance (0)\"}}","error":{"code":-32000},"requestBody":"{\"method\":\"eth_estimateGas\",\"params\":[{\"type\":\"0x2\",\"maxFeePerGas\":\"0xc96f3bba8\",\"maxPriorityFeePerGas\":\"0x59682f00\",\"from\":\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\"to\":\"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\"data\":\"0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"}],\"id\":58,\"jsonrpc\":\"2.0\"}","requestMethod":"POST","url":"https://mainnet.infura.io/v3/2d5bc62bb8d748cebfc64763e719cb4f"}, method="estimateGas", transaction={"from":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","maxPriorityFeePerGas":{"type":"BigNumber","hex":"0x59682f00"},"maxFeePerGas":{"type":"BigNumber","hex":"0x0c96f3bba8"},"to":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","data":"0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","type":2,"accessList":null}, code=UNPREDICTABLE_GAS_LIMIT, version=providers/5.7.2)
      at Logger.makeError (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\logger\lib\index.js:238:21)
      at Logger.throwError (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\logger\lib\index.js:247:20)
      at checkError (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:175:16)
      at JsonRpcProvider.<anonymous> (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:751:47)
      at step (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:48:23)
      at Object.throw (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:29:53)
      at rejected (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:21:65)
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
    reason: 'cannot estimate gas; transaction may fail or may require manual gas limit',
    code: 'UNPREDICTABLE_GAS_LIMIT',
    error: Error: processing response error (body="{\"jsonrpc\":\"2.0\",\"id\":58,\"error\":{\"code\":-32000,\"message\":\"gas required exceeds allowance (0)\"}}", error={"code":-32000}, requestBody="{\"method\":\"eth_estimateGas\",\"params\":[{\"type\":\"0x2\",\"maxFeePerGas\":\"0xc96f3bba8\",\"maxPriorityFeePerGas\":\"0x59682f00\",\"from\":\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\"to\":\"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\"data\":\"0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"}],\"id\":58,\"jsonrpc\":\"2.0\"}", requestMethod="POST", url="https://mainnet.infura.io/v3/2d5bc62bb8d748cebfc64763e719cb4f", code=SERVER_ERROR, version=web/5.7.1)
        at Logger.makeError (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\logger\lib\index.js:238:21)
        at Logger.throwError (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\logger\lib\index.js:247:20)
        at C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\web\lib\index.js:313:32
        at step (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\web\lib\index.js:33:23)
        at Object.next (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\web\lib\index.js:14:53)
        at fulfilled (C:\Users\lidor\Desktop\Trade Bot\node_modules\@ethersproject\web\lib\index.js:5:58)
        at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
      reason: 'processing response error',
      code: 'SERVER_ERROR',
      body: '{"jsonrpc":"2.0","id":58,"error":{"code":-32000,"message":"gas required exceeds allowance (0)"}}',
      error: [Error],
      requestBody: '{"method":"eth_estimateGas","params":[{"type":"0x2","maxFeePerGas":"0xc96f3bba8","maxPriorityFeePerGas":"0x59682f00","from":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","to":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","data":"0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}],"id":58,"jsonrpc":"2.0"}',
      requestMethod: 'POST',
      url: 'https://mainnet.infura.io/v3/2d5bc62bb8d748cebfc64763e719cb4f'
    },
    method: 'estimateGas',
    transaction: {
      from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
      maxPriorityFeePerGas: [BigNumber],
      maxFeePerGas: [BigNumber],
      to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
      data: '0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
      type: 2,
      accessList: null
    }
  },
  tx: {
    data: '0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
    to: Promise { '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' },
    from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
    type: 2,
    maxFeePerGas: BigNumber { _hex: '0x0c96f3bba8', _isBigNumber: true },
    maxPriorityFeePerGas: BigNumber { _hex: '0x59682f00', _isBigNumber: true },
    nonce: Promise { 467 },
    gasLimit: Promise { <rejected> [Circular *1] },
    chainId: Promise { 1 }
  }
}
Error: undefined is not a valid address.
    at Object.validateAndParseAddress (C:\Users\lidor\Desktop\Trade Bot\node_modules\@uniswap\sdk-core\dist\sdk-core.cjs.development.js:527:11)
    at Function.swapCallParameters (C:\Users\lidor\Desktop\Trade Bot\node_modules\@uniswap\v3-sdk\dist\v3-sdk.cjs.development.js:3994:29)    at main (C:\Users\lidor\Desktop\Trade Bot\index.js:49:41)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
PS C:\Users\lidor\Desktop\Trade Bot> 
