Uniswap / v3-core

🦄 🦄 🦄 Core smart contracts of Uniswap v3
https://uniswap.org
Other
4.33k stars 2.65k forks source link

Unable to execute token swap on Uniswap using custom tokens on Mumbai Network #657

Open Shivamycodee opened 1 year ago

Shivamycodee commented 1 year ago

I'm currently working on a project that involves creating two custom tokens on the Mumbai testnet and performing a swap operation for these tokens on Uniswap. However, I'm encountering an issue when trying to execute the trade.

I've already managed to create the tokens and the liquidity pool, but the trading operation fails. Here's my code:

const {
  Pool,
  Route,
  SwapOptions,
  FeeAmount,
  computePoolAddress,
  SwapQuoter,
  SwapRouter,
  Trade,
} = require("@uniswap/v3-sdk");

const {
  Token,
  CurrencyAmount,
  TradeType,
  Percent,
} = require("@uniswap/sdk-core");
const JSBI = require("jsbi");

const Quoter = require("@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json");
const IUniswapV3PoolABI = require("@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json");

const provider = new ethers.providers.JsonRpcProvider(
  process.env.POLYGON_MUMBAI
);

const YING_TOKEN = new Token(80001, process.env.YING_ADDRESS, 18, "YING", "ying");
const YANG_TOKEN = new Token(80001, process.env.YANG_ADDRESS, 18, "YANG", "yang");

let Amount = "54321";

async function createTrade(){

  const poolConstants = await getPoolConstants();

  const pool = new Pool(
    YING_TOKEN,
    YANG_TOKEN,
    FeeAmount.MEDIUM,
    poolConstants.sqrtPriceX96.toString(),
    poolConstants.liquidity.toString(),
    poolConstants.tick
  );

  const swapRoute = new Route(
    [pool],
    YING_TOKEN,
    YANG_TOKEN
  );

  const temp = await quote();
  let amountOut = JSBI.BigInt(temp);

  JSBI.toNumber(amountOut),JSBI.toNumber(amountOut))

  let numAmt = JSBI.toNumber(amountOut);  

  const val = ethers.utils.parseUnits(Amount, YING_TOKEN.decimals);

  const uncheckedTrade = Trade.createUncheckedTrade({
    route: swapRoute,
    inputAmount: CurrencyAmount.fromRawAmount(YING_TOKEN, val.toString()),
    outputAmount: CurrencyAmount.fromRawAmount(
      YANG_TOKEN,
      numAmt
    ),
    tradeType: TradeType.EXACT_INPUT,
  });

  return uncheckedTrade;

}

// Execute trade function...

async function executeTrade(trade){

   // Give approval to the router to spend the token
   const tokenApproval = await getTokenTransferApproval(
     YING_TOKEN
   );

   if (tokenApproval == "no") return;

   const options = {
     slippageTolerance: new Percent(900, 1000),
     deadline: Math.floor(Date.now() / 1000) + 60 * 20, // 20 minutes from the current Unix time
     recipient: process.env.PUB_KEY,
   };

   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 wallet.sendTransaction(tx);
   return res;

}

async function quote() {

  const poolConstants = await getPoolConstants();

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

  const amountIn = ethers.utils.parseUnits(Amount, YING_TOKEN.decimals);

  const quotedAmountOut = await quoterContract.callStatic.quoteExactInputSingle(
    poolConstants.token0,
    poolConstants.token1,
    poolConstants.fee,
    amountIn.toString(),
    0
  );

  console.log("Pure quote : ",quotedAmountOut.toString());
  return quotedAmountOut.toString();
}

async function getTokenTransferApproval(token){

  try {

  const inVal = ethers.utils.parseUnits(
    TOKEN_AMOUNT_TO_APPROVE_FOR_TRANSFER,
    token.decimals
  );

    const tokenContract = new ethers.Contract(
      token.address,
      ERC20_ABI,
      provider
    );

    const transaction = await tokenContract.populateTransaction.approve(
      process.env.uniSwapUniversal,
      inVal.toString()
    );

     const txRes = await wallet.sendTransaction(transaction);
     console.log(txRes);
     return "yes"

  } catch (e) {
    return "no"
  }
}

async function getPoolConstants() {
  const currentPoolAddress = process.env.YING_YANG_POOL;
  // console.log("Current Pool Address : ",currentPoolAddress);

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

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

  return {
    token0,
    token1,
    fee,
    tickSpacing,
    liquidity,
    sqrtPriceX96: slot0[0],
    tick: slot0[1],
  };
}

async function main(){

  const trade = await createTrade()
  const res = executeTrade(trade);
  console.log(res);

}
main();

Error I GOT:

D:\trading bot\0xArbi-bot\node_modules\@uniswap\sdk-core\dist\sdk-core.cjs.development.js:82
    throw new Error('Could not parse fraction');
          ^

Error: Could not parse fraction
    at Function.tryParseFraction (D:\trading bot\0xArbi-bot\node_modules\@uniswap\sdk-core\dist\sdk-core.cjs.development.js:82:11)
    at Percent.lessThan (D:\trading bot\0xArbi-bot\node_modules\@uniswap\sdk-core\dist\sdk-core.cjs.development.js:113:32)
    at Trade.minimumAmountOut (D:\trading bot\0xArbi-bot\node_modules\@uniswap\v3-sdk\dist\v3-sdk.cjs.development.js:3027:25)
    at D:\trading bot\0xArbi-bot\node_modules\@uniswap\v3-sdk\dist\v3-sdk.cjs.development.js:3977:28
    at Array.reduce (<anonymous>)
    at Function.swapCallParameters (D:\trading bot\0xArbi-bot\node_modules\@uniswap\v3-sdk\dist\v3-sdk.cjs.development.js:3976:33)
    at executeTrade (D:\trading bot\0xArbi-bot\uniswapCustom.js:143:40)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

This error seems to occur when calling SwapRouter.swapCallParameters with the trade and options parameters:

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

I've tried adjusting the output amount (numAmt) in different formats when creating the UncheckedTrade, but the error persists. I can't seem to identify the cause of this issue. My guess is that it has something to do with the calculation of the output amount or slippage, but I'm unsure.

Shivamycodee commented 1 year ago

@danrobinson @grabbou @NoahZinsmeister @vm

Shivamycodee commented 1 year ago

constant values like maxFeePerGas , wallet has been removed form the question to decrease the line of code but do exist in real code.