Uniswap / v3-sdk

🛠 An SDK for building applications on top of Uniswap V3
MIT License
551 stars 428 forks source link

error: no tick data provider was given #184

Open s-pcode opened 1 year ago

s-pcode commented 1 year ago

I'm creating a pool instance using the Pool class where it mentions that the ticks are optional but if i donot pass ticks then it throws an error of "error: no tick data provider was given".

Please help me.

Florian-S-A-W commented 1 year ago

This error is not thrown by the constructor but by functions that require Tickdata on Pools that are initialized without ticks. If you want to use tick data from the Pool's TickDataProvider e.g. by calling nextInitializedTickWithinOneWord or getTick you need to initialize it with Ticks. What are you trying to do?

s-pcode commented 1 year ago

Hey @Florian-S-A-W

I'm trying to swap tokens using the uniswap universal router - 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD. I have shared my code snippet below, Any help is useful to me as I'm new to this and can't figure out where I'm going wrong.

Also, I have a query whether this universal router can execute transactions on v2,v3 and mixed routes ? I'm referring a YT video for this - https://www.youtube.com/watch?v=LfJImqRQUkI&pp=ygUYdW5pc3dhcCB1bml2ZXJzYWwgcm91dGVy


function buildTrade(trades: any[]) {
  return new RouterTrade({
    v2Routes: trades
      .filter((trade) => trade instanceof V2Trade)
      .map((trade) => ({
        routev2: trade.route,
        inputAmount: trade.inputAmount,
        outputAmount: trade.outputAmount,
      })),
    v3Routes: trades
      .filter((trade) => trade instanceof V3Trade)
      .map((trade) => ({
        routev3: trade.route,
        inputAmount: trade.inputAmount,
        outputAmount: trade.outputAmount,
      })),
    mixedRoutes: trades
      .filter((trade) => trade instanceof MixedRouteTrade)
      .map((trade) => ({
        mixedRoute: trade.route,
        inputAmount: trade.inputAmount,
        outputAmount: trade.outputAmount,
      })),
    tradeType: trades[0].tradeType,
  });
}

const pool = new Pool(
        tokenA,
        tokenB,
        poolFee,
        JSBI.BigInt(sqrtRatioX96.toString()),
        JSBI.BigInt(liquidity.toString()),
        +tickCurrent
      );

 const trade = await V3Trade.fromRoute(
        new RouteV3([pool], tokenA, tokenB),
        CurrencyAmount.fromRawAmount(tokenA, amount),
        TradeType.EXACT_INPUT
      );

      const routerTrade = buildTrade([trade]);

      const opts = swapOptions({}, address);

      const params = SwapRouter.swapERC20CallParameters(routerTrade, opts);
Florian-S-A-W commented 1 year ago

Take a look at the universal router sdk: https://github.com/Uniswap/universal-router-sdk I will try to add a proper guide on this topic to the docs.

s-pcode commented 1 year ago

Also, I have a query whether this universal router can execute transactions on v2,v3 and mixed routes ? Can I use the uniswap API to fetch the quote and universal router to swap the tokens ?

Is there any working example which I can refer to ?

Florian-S-A-W commented 1 year ago

Yes, the universal router can make trades on both V2, V3 and also the NFT marketplace. The routing-api is an AWS deployment of the smart-order-router. I have never used it with AWS personally but it should work the same as the smart-order-router package if you prefer it.

Have you looked at this guide which uses the smart-order-router? The function AlphaRouter.route returns a route that can include both V2 and V3 pools. After you got the route you can execute it with the SwapRouter02, which the guide uses. You can also execute it with the Universal Router if you prefer that.

Something I just realised can be quite confusing is that the V3SwapRouter is just named SwapRouter in the docs several times, so you would think SwapRouter02 is version 2 of it. It's not, it's a combination of the V2 and V3 SwapRouter that supports both protocols. It also has this confusing name in the guide.

You could also look at tests in the sdk-repo (just one example here).

The universal router is used in the interface and the swap widget, you could look at that as well. Both are rather big projects though.

I would place my focus on understanding the smart-order-router and the universal-router-sdk packages for your issue. It's not part of the v3-sdk unfortunately.

s-pcode commented 1 year ago

Yes, there seems to be a bit of confusion. Currently I'm going through the universal-router tests to understand the flow. I want to build a small swap interface using uniswap. Currently I'm using the quote api directly - https://api.uniswap.org/v2/quote.

There are two universal router as far as I can see in their deployed-addresses folder Universal router 2 - 0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B Universal router - 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD Do you have any idea which one to use or both will result in same transactions ? I followed the exact path as their test file for a v3 trade but my transaction didn't succed.

Florian-S-A-W commented 1 year ago

I recently asked the same question and the answer is that both are fine. I would still use the newer version, so 0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B. You switched them in your comment.

s-pcode commented 1 year ago

Thanks for the clarification mate. Is there any issue if I use uniswap quote api directly ?

Florian-S-A-W commented 1 year ago

I think that is an internal API that Uniswap Labs uses. It's not public.

s-pcode commented 1 year ago

Ok. I just implemented the universal router sdk and tried to swap following the code given in their test file. But my transaction failed, here is the hash. Can you help me debug this ?

I see this - image

Below is my code snippet.

const tokenA = new Token(chainId, tokenIn.address, +tokenIn.decimals);
      const tokenB = new Token(chainId, tokenOut.address, +tokenOut.decimals);

      const pool = await getPool(tokenA, tokenB, poolFee, provider);

      const trade = await V3Trade.fromRoute(
        new RouteV3([pool], tokenA, tokenB),
        CurrencyAmount.fromRawAmount(tokenA, amount),
        TradeType.EXACT_INPUT
      );

      const routerTrade = buildTrade([trade]);

      const opts = swapOptions({}, address);

      const params = SwapRouter.swapCallParameters(
        new UniswapTrade(routerTrade, opts)
      );

      const signer = provider.getSigner();

      const tx = await signer.sendTransaction({
        data: params.calldata,
        to: UNISWAP_UNIVERSAL_ROUTER_ADDRESS[chainId],
        value: params.value,
        from: address,
        gasLimit: DEFAULT_GAS_LIMIT,
      });

      const receipt = await tx.wait();
      console.log("---------------------------- SUCCESS?");
      console.log("status", receipt.status);
      return receipt;
Florian-S-A-W commented 1 year ago

Are the call parameters created for the correct router? Did you use the class from universal-router-sdk as there are so many across the sdks with that name. I would try replaying or simulating the transaction in Tenderly to see what exactly fails.

s-pcode commented 1 year ago

yes i'm importing the below classes

import {
  SwapOptions,
  SwapRouter,
  UniswapTrade,
} from "@uniswap/universal-router-sdk";

below is an instance of my calldata being created

{
    "calldata": "0x24856bc30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c3cd0171dfdd36cb1d77efc07578b69252d652060000000000000000000000000000000000000000000000001de4c54b192f9ac8000000000000000000000000000000000000000000000000000000000011d1be00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002b0d500b1d8e8ef31e21c99d1db9a6444d3adf12700001f42791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000000000000000000000",
    "value": "0x00"
}

Am I making any mistake for the sendTransaction function ?

Florian-S-A-W commented 1 year ago

The Permit2 allowance is expired. Otherwise this seems to be correct. You can see the details on Tenderly. You can analyse any failed tx there.

I suggest playing around with Tenderly a bit. Its a very useful tool. I'm not affiliated or anything I just really like it.

s-pcode commented 1 year ago

Ya @Florian-S-A-W i agree Tenderly is very useful tool in simulating transactions. Thanks for sharing.

I could not understand the "Permit2 allowance is expired" ? What exactly do I need to do ? I was swapping MATIC with USDC, do I need to perform MATIC.approve(permit2Address, totalAmount); tx. Can you please guide me what to do with the Permit2 ?

Florian-S-A-W commented 1 year ago

Take a look at the documentation: https://docs.uniswap.org/contracts/permit2/overview Uniswap also has an SDK for it (unfortunately not documented yet): https://github.com/Uniswap/permit2-sdk It should be understandable with the other resources though.

s-pcode commented 1 year ago

Hey @Florian-S-A-W , tenderly helped me a lot, I also implemented permit2 sdk. But I get the following error - hash, which I'm unable to debug using tenderly. Can you help me out please ?