Skip to content

Example about querying the price of USDT to USDC on Ethereum is wrong #14

Description

@shuzhiwen

As the title describes, I changed part of the code in the example and got the wrong value.

image

import { ChainId, CurrencyAmount, Percent, TradeType } from '@pancakeswap/sdk'
import { SMART_ROUTER_ADDRESSES, SmartRouter, SmartRouterTrade, SwapRouter } from '@pancakeswap/smart-router'
import { ethereumTokens } from '@pancakeswap/tokens'
import { GraphQLClient } from 'graphql-request'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { createPublicClient, hexToBigInt, http } from 'viem'
import { mainnet as chain } from 'viem/chains'
import {
  WagmiConfig,
  createConfig,
  mainnet,
  useAccount,
  useConnect,
  useNetwork,
  useSendTransaction,
  useSwitchNetwork,
} from 'wagmi'
import { MetaMaskConnector } from 'wagmi/connectors/metaMask'

import './App.css'

const chainId = ChainId.ETHEREUM
const swapFrom = ethereumTokens.usdt
const swapTo = ethereumTokens.usdc

const publicClient = createPublicClient({
  chain: chain,
  transport: http(mainnet.rpcUrls.default.http[0]),
  batch: {
    multicall: {
      batchSize: 1024 * 200,
    },
  },
})

const config = createConfig({
  autoConnect: true,
  connectors: [new MetaMaskConnector({ chains: [chain] })],
  publicClient,
})

const v3SubgraphClient = new GraphQLClient('https://thegraph.com/hosted-service/subgraph/pancakeswap/exchange-v3-eth')
const v2SubgraphClient = new GraphQLClient('https://api.thegraph.com/subgraphs/name/pancakeswap/exhange-eth')

const quoteProvider = SmartRouter.createQuoteProvider({
  onChainProvider: () => publicClient,
})

function calculateGasMargin(value: bigint, margin = 1000n): bigint {
  return (value * (10000n + margin)) / 10000n
}

export function SmartRouterExample() {
  return (
    <WagmiConfig config={config}>
      <Main />
    </WagmiConfig>
  )
}

function Main() {
  const { chain } = useNetwork()
  const { address, isConnected } = useAccount()
  const { connect, connectors } = useConnect()
  const { switchNetwork } = useSwitchNetwork()
  const { sendTransactionAsync } = useSendTransaction()

  const [trade, setTrade] = useState<SmartRouterTrade<TradeType> | null>(null)
  const amount = useMemo(() => CurrencyAmount.fromRawAmount(swapFrom, 10 ** 16), [])
  const getBestRoute = useCallback(async () => {
    const [v2Pools, v3Pools] = await Promise.all([
      SmartRouter.getV2CandidatePools({
        onChainProvider: () => publicClient,
        v2SubgraphProvider: () => v2SubgraphClient,
        v3SubgraphProvider: () => v3SubgraphClient,
        currencyA: amount.currency,
        currencyB: swapTo,
      }),
      SmartRouter.getV3CandidatePools({
        onChainProvider: () => publicClient,
        subgraphProvider: () => v3SubgraphClient,
        currencyA: amount.currency,
        currencyB: swapTo,
        subgraphFallback: false,
      }),
    ])
    const pools = [...v2Pools, ...v3Pools]
    const trade = await SmartRouter.getBestTrade(amount, swapTo, TradeType.EXACT_INPUT, {
      gasPriceWei: () => publicClient.getGasPrice(),
      maxHops: 2,
      maxSplits: 2,
      poolProvider: SmartRouter.createStaticPoolProvider(pools),
      quoteProvider,
      quoterOptimization: true,
    })
    setTrade(trade)
  }, [amount])

  const swapCallParams = useMemo(() => {
    if (!trade) {
      return null
    }
    const { value, calldata } = SwapRouter.swapCallParameters(trade, {
      recipient: address,
      slippageTolerance: new Percent(1),
    })
    return {
      address: SMART_ROUTER_ADDRESSES[chainId],
      calldata,
      value,
    }
  }, [trade, address])

  const swap = useCallback(async () => {
    if (!swapCallParams || !address) {
      return
    }

    const { value, calldata, address: routerAddress } = swapCallParams

    const tx = {
      account: address,
      to: routerAddress,
      data: calldata,
      value: hexToBigInt(value),
    }
    const gasEstimate = await publicClient.estimateGas(tx)
    await sendTransactionAsync({
      account: address,
      chainId,
      to: routerAddress,
      data: calldata,
      value: hexToBigInt(value),
      gas: calculateGasMargin(gasEstimate),
    })
  }, [swapCallParams, address, sendTransactionAsync])

  useEffect(() => {
    if (isConnected && chain?.id !== chainId) {
      switchNetwork?.(chainId)
    }
  }, [isConnected, switchNetwork, chain])

  return (
    <div className="App">
      <header className="App-header">
        <p>Pancakeswap Smart Router Example.</p>
        <p>
          Get best quote swapping from {amount.toExact()} {amount.currency.symbol} to{' '}
          {trade?.outputAmount.toExact() || '?'} {swapTo.symbol}
        </p>
        <p>
          {isConnected ? (
            address
          ) : (
            <button onClick={() => connect({ connector: connectors[0] })}>Connect wallet</button>
          )}
        </p>
        <p>{!trade ? <button onClick={getBestRoute}>Get Quote</button> : <button onClick={swap}>Swap</button>}</p>
      </header>
    </div>
  )
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions