const ethers = require('ethers');
const { computePoolAddress } = require('@uniswap/v3-sdk');
const { Token } = require('@uniswap/sdk-core');

// Ethereum network configuration
const provider = new ethers.JsonRpcProvider('http://127.0.0.1:8545/');

// Uniswap V3 contract configuration
const uniswapV3SwapRouterAddress = '0xE592427A0AEce92De3Edee1F18E0157C05861564';
const PoolFactoryContractAddress = '0x1F98431c8aD98523631AE4a59f267346ea31F984';
const quoterContractAddress = '0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6';
const uniswapV3SwapRouterABI = require('@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json').abi;
const uniswapV3PoolABI =
  require('@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json').abi;
const uniswapV3QuoterAbi = require('@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json').abi;

const privateKey1 = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
const token0Address1 = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const token1Address1 = '0xdAC17F958D2ee523a2206206994597C13D831ec7';

// Load the Uniswap V3 contract
const maxFeePerGas = ethers.parseUnits('50', 'gwei');
const maxPriorityFeePerGas = ethers.parseUnits('2', 'gwei');

exports.executeTrade = async function executeTrade(token0Address, token1Address, privateKey, amount) {
  try {
    let swapped;
    let received;

    const wallet = new ethers.Wallet(privateKey, provider);
    const uniswapV3SwapRouterContract = new ethers.Contract(uniswapV3SwapRouterAddress, uniswapV3SwapRouterABI, wallet);

    const token0Properties = await getTokenProperties(token0Address);
    const token1Properties = await getTokenProperties(token1Address);
    const token0Instance = new Token(
      1,
      token0Address,
      Number(token0Properties.decimals),
      token0Properties.symbol,
      token0Properties.name
    );
    const token1Instance = new Token(
      1,
      token1Address,
      Number(token1Properties.decimals),
      token1Properties.symbol,
      token1Properties.name
    );
    const swapAmount = ethers.parseUnits(amount.toString(), token0Properties.decimals);

    const currentPoolAddress = computePoolAddress({
      factoryAddress: PoolFactoryContractAddress,
      tokenA: token0Instance,
      tokenB: token1Instance,
      fee: 3000,
    });

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

    poolContract.on('Swap', (sender, recipient, amount0, amount1) => {
      swapped = `Amount Swapped (${token0Properties.name}): ${ethers.formatUnits(-amount0, token0Properties.decimals)}`;
      received = `Amount Received (${token1Properties.name}): ${ethers.formatUnits(
        amount1,
        token1Properties.decimals
      )}`;
    });

    const [token0, token1, fee] = await Promise.all([poolContract.token0(), poolContract.token1(), poolContract.fee()]);

    const quoterContract = new ethers.Contract(quoterContractAddress, uniswapV3QuoterAbi, provider);

    const data = quoterContract.interface.encodeFunctionData('quoteExactInputSingle', [
      token0,
      token1,
      fee,
      swapAmount.toString(),
      0,
    ]);
    const quotedAmountOut = await provider.call({ to: quoterContractAddress, data });
    const humanReadableAmountOut = ethers.formatUnits(quotedAmountOut, token0Properties.decimals);
    console.log('Estimated amount out:', humanReadableAmountOut, token1Properties.name);

    // Approve Uniswap V3 SwapRouter to spend token0Instance
    console.log('Approving token spend by SwapRouter…');
    const tokenToSwapContract = new ethers.Contract(
      token0Address,
      ['function approve(address spender, uint256 amount) external returns (bool)'],
      wallet
    );
    const approvalTx = await tokenToSwapContract.approve(uniswapV3SwapRouterAddress, swapAmount, {
      maxFeePerGas,
      maxPriorityFeePerGas,
      gasLimit: 25000000,
    });

    await approvalTx.wait();
    console.log('Token spend approval transaction confirmed.');

    console.log(wallet.address);
    const swapParams = {
      tokenIn: token0Address,
      tokenOut: token1Address,
      fee: 3000,
      recipient: wallet.address,
      deadline: Math.floor(Date.now() / 1000) + 60 * 20,
      amountIn: swapAmount,
      amountOutMinimum: 0,
      sqrtPriceLimitX96: 0,
    };

    console.log('Sending swap transaction…');
    const swapTx = await uniswapV3SwapRouterContract.exactInputSingle(swapParams, {
      maxFeePerGas: maxFeePerGas,
      maxPriorityFeePerGas: maxPriorityFeePerGas,
      gasLimit: 25000000,
    });

    console.log('Swap transaction hash:', swapTx.hash);

    // Wait for transaction confirmation
    console.log('Waiting for swap transaction confirmation…');
    await swapTx.wait();
    console.log('Swap transaction confirmed!');
    return { swapped, received };
  } catch (e) {
    console.log(e);
    return null;
  }
};

async function getTokenProperties(tokenAddress) {
  const erc20ABI = [
    'function name() view returns (string)',
    'function symbol() view returns (string)',
    'function decimals() view returns (uint8)',
  ];
  const tokenContract = new ethers.Contract(tokenAddress, erc20ABI, provider);
  const [name, symbol, decimals] = await Promise.all([
    tokenContract.name(),
    tokenContract.symbol(),
    tokenContract.decimals(),
  ]);
  return {
    name,
    symbol,
    decimals,
  };
}
 2 problems with this code,first this     poolContract.on('Swap', (sender, recipient, amount0, amount1) => {
      swapped = `Amount Swapped (${token0Properties.name}): ${ethers.formatUnits(-amount0, token0Properties.decimals)}`;
      received = `Amount Received (${token1Properties.name}): ${ethers.formatUnits(
        amount1,
        token1Properties.decimals
      )}`;
    }); doesn't return the true amounts, and the code takes the tokens but isn't returning any of other type