const { AlphaRouter } = require('@uniswap/smart-order-router');
const { Token, CurrencyAmount, TradeType, Percent } = require('@uniswap/sdk-core');
const { ethers, BigNumber } = require('ethers');
const JSBI = require('jsbi'); // jsbi@3.2.5
const { computePoolAddress } = require('@uniswap/v3-sdk');
const IUniswapV3PoolABI = require('@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json');
const Quoter = requirE('@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json');

const V3_SWAP_ROUTER_ADDRESS = '0xE592427A0AEce92De3Edee1F18E0157C05861564';
const WALLET_ADDRESS = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
const WALLET_SECRET = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
const INFURA_TEST_URL = 'https://mainnet.infura.io/v3/<TRUFFLEHOG_REDACTED_INFURA>';
const QUOTER_CONTRACT_ADDRESS = '0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6';

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

const chainId = 1;
const router = new AlphaRouter({ chainId: chainId, provider: web3Provider });

const name0 = 'Wrapped Ether';
const symbol0 = 'WETH';
const decimals0 = 18;
const address0 = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';

const name1 = 'Uniswap Token';
const symbol1 = 'UNI';
const decimals1 = 18;
const address1 = '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984';

async function main() {
  const currentPoolAddress = computePoolAddress({
    factoryAddress: POOL_FACTORY_CONTRACT_ADDRESS,
    tokenA: address0,
    tokenB: address1,
    fee: 300,
  });

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

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

  const quoterContract = new ethers.Contract(QUOTER_CONTRACT_ADDRESS, Quoter.abi, provider);

  const quotedAmountOut = await quoterContract.callStatic.quoteExactInputSingle(token0, token1, fee, fromReadableAmount(0.001, 18).toString(), 0);

  const poolInfo = await getPoolInfo();

  const pool = new Pool(address0, address1, CurrentConfig.tokens.poolFee, poolInfo.sqrtPriceX96.toString(), poolInfo.liquidity.toString(), poolInfo.tick);
  const swapRoute = new Route([pool], address0, address1);
  const amountOut = await getOutputQuote(swapRoute);

  const { calldata } = await SwapQuoter.quoteCallParameters(route, CurrencyAmount.fromRawAmount(address0, fromReadableAmount(0.001, 18)), TradeType.EXACT_INPUT, {
    useQuoterV2: true,
  });

  const quoteCallReturnData = await provider.call({
    to: QUOTER_CONTRACT_ADDRESS,
    data: calldata,
  });

  const quoteReturn = ethers.utils.defaultAbiCoder.decode(['uint256'], quoteCallReturnData);

  const uncheckedTrade = Trade.createUncheckedTrade({
    route: swapRoute,
    inputAmount: CurrencyAmount.fromRawAmount(address0, fromReadableAmount(0.001, 18).toString()),
    outputAmount: CurrencyAmount.fromRawAmount(address1, JSBI.BigInt(amountOut)),
    tradeType: TradeType.EXACT_INPUT,
  });

  const tokenApproval = await getTokenTransferApproval(address0);

  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
    recipient: walletAddress,
  };

  const methodParameters = SwapRouter.swapCallParameters([trade], options);

  const tx = {
    data: methodParameters.calldata,
    to: SWAP_ROUTER_ADDRESS,
    value: methodParameters.value,
    from: walletAddress,
    maxFeePerGas: MAX_FEE_PER_GAS,
    maxPriorityFeePerGas: MAX_PRIORITY_FEE_PER_GAS,
  };

  const res = await sendTransaction(tx);
}

main();
 i managed to build this by following the uniswap guide, can i get some finetuning and some better code