docs icon indicating copy to clipboard operation
docs copied to clipboard

Referencing the Quoter contract and getting a quote added for QuoterV2 as well

Open kritik-sah opened this issue 11 months ago • 1 comments

Referencing the Quoter contract and getting a quote

To get quotes for trades, Uniswap has deployed a Quoter Contract. We will use this contract to fetch the output amount we can expect for our trade, without actually executing the trade. Check out the full code for the following snippets in quote.ts

Like we did for the Pool contract, we need to construct an instance of an ethers Contract for our Quoter contract in order to interact with it:

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

We get access to the contract's ABI through the @uniswap/v3-periphery package, which holds the periphery smart contracts of the Uniswap V3 protocol:

import Quoter from '@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json'

We get the QUOTE_CONTRACT_ADDRESS for our chain from Github.

We can now use our Quoter contract to obtain the quote.

In an ideal world, the quoter functions would be view functions, which would make them very easy to query on-chain with minimal gas costs. However, the Uniswap V3 Quoter contracts rely on state-changing calls designed to be reverted to return the desired data. This means calling the quoter will be very expensive and should not be called on-chain.

To get around this difficulty, we can use the callStatic method provided by the ethers.js Contract instances. This is a useful method that submits a state-changing transaction to an Ethereum node, but asks the node to simulate the state change, rather than to execute it. Our script can then return the result of the simulated state change:

const quotedAmountOut = await quoterContract.callStatic.quoteExactInputSingle(
  token0,
  token1,
  fee,
  fromReadableAmount(
    CurrentConfig.tokens.amountIn,
    CurrentConfig.tokens.in.decimals
  ).toString(),
  0
)

The fromReadableAmount() function creates the amount of the smallest unit of a token from the full unit amount and the decimals.

The result of the call is the number of output tokens you'd receive for the quoted swap.

It should be noted that quoteExactInputSingle is only 1 of 4 different methods that the quoter offers:

  1. quoteExactInputSingle - given the amount you want to swap, produces a quote for the amount out for a swap of a single pool
  2. quoteExactInput - given the amount you want to swap, produces a quote for the amount out for a swap over multiple pools
  3. quoteExactOutputSingle - given the amount you want to get out, produces a quote for the amount in for a swap over a single pool
  4. quoteExactOutput - given the amount you want to get out, produces a quote for the amount in for a swap over multiple pools

If we want to trade two tokens that do not share a pool with each other, we will need to make swaps over multiple pools. This is where the quoteExactInput and quoteExactOutput methods come in. We will dive deeper into routing in the routing guide.

For the exactOutput and exactOutputSingle methods, we need to keep in mind that a pool can not give us more than the amount of Tokens it holds. If we try to get a quote on an output of 100 WETH from a Pool that only holds 50 WETH, the function call will fail.

Referencing the QuoterV2 contract and getting a quote

const quoterV2Contract = new ethers.Contract(
  QUOTER_V2_CONTRACT_ADDRESS,
  QuoterV2.abi,
  getProvider()
)

We get the QUOTE_V2_CONTRACT_ADDRESS for our chain from V3 refrence deployments.

We get access to the contract's ABI through the @uniswap/v3-periphery package, which holds the periphery smart contracts of the Uniswap V3 protocol:

import Quoter as QuoterV2 from '@uniswap/v3-periphery/artifacts/contracts/lens/QuoterV2.sol/QuoterV2.json'

Let's get the quote for our tokens, where "Quoter" takes multiple arguments in quoteExactInputSingle(), QuoterV2 takes only one argument in the form of an object

const quote = await quoterContract.callStatic.quoteExactInputSingle(
  {
    tokenIn: tokenIn.address, // tokenIn is of type Token
    tokenOut: tokenOut.address, // tokenOut is of type Token
    fee: fee, // eg. 3000
    amountIn: fromReadableAmount(amountIn, tokenIn.decimals).toString(),
    sqrtPriceLimitX96: 0,
  }
);
console.log(quote.amountOut);

This will return you "amountOut" , "gasEstimate", "initializedTicksCrossed" and "sqrtPriceX96After"

  1. AmountOut: The tokens or cryptocurrency received in a Uniswap swap transaction.

  2. Gas Estimate: Estimated amount of gas required for executing a Uniswap transaction on the Ethereum network.

  3. InitializedTicksCrossed: In Uniswap V3, indicates whether liquidity has crossed certain price thresholds within a liquidity range.

  4. SqrtPriceX96After: Square root of the price after a Uniswap V3 transaction, essential for determining pricing accuracy.

kritik-sah avatar Mar 05 '24 15:03 kritik-sah