From bb849e4593b54d5f813523ce705ce3f26fa1ef36 Mon Sep 17 00:00:00 2001 From: 0xMasayoshi <0xmasayoshi@protonmail.com> Date: Tue, 20 Jun 2023 15:27:15 +0700 Subject: [PATCH] feat(apps/swap): use fiat value from AMM in CurrencyInput --- apps/_root/lib/swap/usePctChange.ts | 14 +-- .../ui/swap/widget/SwapCurrencyOutput.tsx | 3 +- .../Web3Input/Currency/CurrencyInput.tsx | 7 +- .../Web3Input/Currency/PricePanel.tsx | 14 +-- .../hooks/pools/actions/getAllPoolsCodeMap.ts | 2 +- .../hooks/pools/hooks/usePoolsCodeMap.ts | 2 +- .../src/future/hooks/trade/hooks/index.ts | 1 + .../future/hooks/trade/hooks/useUSDCPrice.ts | 97 +++++++++++++++++++ 8 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 packages/wagmi/src/future/hooks/trade/hooks/useUSDCPrice.ts diff --git a/apps/_root/lib/swap/usePctChange.ts b/apps/_root/lib/swap/usePctChange.ts index a7a9657bde..e42d7e6636 100644 --- a/apps/_root/lib/swap/usePctChange.ts +++ b/apps/_root/lib/swap/usePctChange.ts @@ -1,21 +1,23 @@ import { useMemo } from 'react' import { ZERO } from '@sushiswap/math' import { useSwapState } from '../../ui/swap/trade/TradeProvider' -import { usePrice } from '@sushiswap/react-query' +import { useUSDCPrice } from '@sushiswap/wagmi/future/hooks' import { useTrade } from './useTrade' export const usePctChange = () => { const { token1, token0, network0, network1, amount } = useSwapState() - const { data: price0 } = usePrice({ chainId: network0, address: token0?.wrapped?.address }) - const { data: price1 } = usePrice({ chainId: network1, address: token1?.wrapped?.address }) + const { data: price0 } = useUSDCPrice({ currency: token0, chainId: network0 }) + const { data: price1 } = useUSDCPrice({ currency: token1, chainId: network1 }) const { data: trade } = useTrade({ crossChain: network0 !== network1 }) return useMemo(() => { if (!trade?.priceImpact) return undefined - const inputUSD = amount && price0 ? amount.multiply(price0.asFraction) : undefined - const outputUSD = trade?.amountOut && price1 ? trade.amountOut.multiply(price1.asFraction) : undefined - return inputUSD && outputUSD && inputUSD?.greaterThan(ZERO) + const inputUSD = amount && price0 ? price0.quote(amount) : undefined + const outputUSD = + trade?.amountOut && price1 ? price1.quote(trade.amountOut) : undefined + + return inputUSD && outputUSD && inputUSD.greaterThan(ZERO) ? ((Number(outputUSD?.toExact()) - Number(inputUSD?.toExact())) / Number(inputUSD?.toExact())) * 100 : undefined }, [trade?.priceImpact, trade?.amountOut, amount, price0, price1]) diff --git a/apps/_root/ui/swap/widget/SwapCurrencyOutput.tsx b/apps/_root/ui/swap/widget/SwapCurrencyOutput.tsx index 0c3ceecbce..02bbd5fae0 100644 --- a/apps/_root/ui/swap/widget/SwapCurrencyOutput.tsx +++ b/apps/_root/ui/swap/widget/SwapCurrencyOutput.tsx @@ -24,8 +24,7 @@ export const SwapCurrencyOutput: FC = () => { onSelect={setToken1} value={trade?.amountOut?.toSignificant() ?? ''} currency={token1} - usdPctChange={undefined} - // usdPctChange={trade?.route?.status === 'NoWay' ? undefined : usdPctChange} + usdPctChange={trade?.route?.status === 'NoWay' ? undefined : usdPctChange} loading={Boolean(isLoading && +value > 0) || isFetching || tokensLoading} disableMaxButton currencyLoading={tokensLoading} diff --git a/packages/wagmi/src/future/components/Web3Input/Currency/CurrencyInput.tsx b/packages/wagmi/src/future/components/Web3Input/Currency/CurrencyInput.tsx index fdd804b6a5..2dd697b457 100644 --- a/packages/wagmi/src/future/components/Web3Input/Currency/CurrencyInput.tsx +++ b/packages/wagmi/src/future/components/Web3Input/Currency/CurrencyInput.tsx @@ -11,8 +11,7 @@ import { useAccount } from 'wagmi' import { TokenSelector } from '../../TokenSelector/TokenSelector' import { BalancePanel } from './BalancePanel' import { PricePanel } from './PricePanel' -import { usePrice } from '@sushiswap/react-query' -import { useBalanceWeb3 } from '../../../hooks' +import { useBalanceWeb3, useUSDCPrice } from '../../../hooks' import dynamic from 'next/dynamic' export interface CurrencyInputProps { @@ -63,9 +62,9 @@ export const Component: FC = ({ currency, }) - const { data: price, isInitialLoading: isPriceLoading } = usePrice({ + const { data: price, isInitialLoading: isPriceLoading } = useUSDCPrice({ chainId: currency?.chainId, - address: currency?.wrapped?.address, + currency }) const _value = useMemo(() => tryParseAmount(value, currency), [value, currency]) diff --git a/packages/wagmi/src/future/components/Web3Input/Currency/PricePanel.tsx b/packages/wagmi/src/future/components/Web3Input/Currency/PricePanel.tsx index 8a2fc05ed5..49fc2f03ed 100644 --- a/packages/wagmi/src/future/components/Web3Input/Currency/PricePanel.tsx +++ b/packages/wagmi/src/future/components/Web3Input/Currency/PricePanel.tsx @@ -1,19 +1,19 @@ -import { tryParseAmount } from '@sushiswap/currency' +import { Price, Type, tryParseAmount } from '@sushiswap/currency' import { classNames } from '@sushiswap/ui' import { Skeleton } from '@sushiswap/ui/future/components/skeleton' import { FC, useMemo } from 'react' - import { CurrencyInputProps } from './CurrencyInput' -import { Fraction, ZERO } from '@sushiswap/math' +import { ZERO } from '@sushiswap/math' type PricePanel = Pick & { error?: string - price: Fraction | undefined + price: Price | undefined } export const PricePanel: FC = ({ loading, price, currency, value, usdPctChange, error }) => { const parsedValue = useMemo(() => tryParseAmount(value, currency), [currency, value]) - const [big, portion] = (parsedValue && price ? `${parsedValue.multiply(price.asFraction).toFixed(2)}` : '0.00').split( + + const [big, portion] = (parsedValue && price ? `${price.quote(parsedValue).toFixed(2)}` : '0.00').split( '.' ) @@ -37,7 +37,7 @@ export const PricePanel: FC = ({ loading, price, currency, value, us $ {big}.{portion} )} - {!(!loading && price?.equalTo(ZERO)) && usdPctChange && usdPctChange !== 0 && ( + {!(!loading && price?.equalTo(ZERO)) && usdPctChange && usdPctChange !== 0 ? ( = ({ loading, price, currency, value, us usdPctChange?.toFixed(2) === '0.00' ? '' : `${usdPctChange?.toFixed(2)}%)` }`} - )} + ) : null}

) } diff --git a/packages/wagmi/src/future/hooks/pools/actions/getAllPoolsCodeMap.ts b/packages/wagmi/src/future/hooks/pools/actions/getAllPoolsCodeMap.ts index 12f71ecad2..4a0afc6a05 100644 --- a/packages/wagmi/src/future/hooks/pools/actions/getAllPoolsCodeMap.ts +++ b/packages/wagmi/src/future/hooks/pools/actions/getAllPoolsCodeMap.ts @@ -36,7 +36,7 @@ export const getAllPoolsCodeMap = async ({ currencyA, currencyB, chainId }: Omit const testLiquidityProviders = [...sushiLiquidityProviders] - const dataFetcher = DataFetcher.onChain(chainId) + const dataFetcher = new DataFetcher(chainId) console.log('IS TEST', isTest) dataFetcher.startDataFetching(isTest ? testLiquidityProviders : liquidityProviders) await dataFetcher.fetchPoolsForToken(currencyA, currencyB) diff --git a/packages/wagmi/src/future/hooks/pools/hooks/usePoolsCodeMap.ts b/packages/wagmi/src/future/hooks/pools/hooks/usePoolsCodeMap.ts index 55aa5c7b37..a24dbed04d 100644 --- a/packages/wagmi/src/future/hooks/pools/hooks/usePoolsCodeMap.ts +++ b/packages/wagmi/src/future/hooks/pools/hooks/usePoolsCodeMap.ts @@ -5,7 +5,7 @@ import { getAllPoolsCodeMap } from '../actions/getAllPoolsCodeMap' export const usePoolsCodeMap = ({ enabled = true, ...variables }: UsePoolsParams) => { const { chainId, currencyA, currencyB } = variables return useQuery({ - queryKey: ['usePools', { chainId, currencyA, currencyB }], + queryKey: ['usePoolsCodeMap', { chainId, currencyA, currencyB }], queryFn: async () => await getAllPoolsCodeMap(variables), refetchInterval: 10000, enabled, diff --git a/packages/wagmi/src/future/hooks/trade/hooks/index.ts b/packages/wagmi/src/future/hooks/trade/hooks/index.ts index 7cb6893edf..63c9b6a526 100644 --- a/packages/wagmi/src/future/hooks/trade/hooks/index.ts +++ b/packages/wagmi/src/future/hooks/trade/hooks/index.ts @@ -1 +1,2 @@ export * from './useClientTrade' +export * from './useUSDCPrice' \ No newline at end of file diff --git a/packages/wagmi/src/future/hooks/trade/hooks/useUSDCPrice.ts b/packages/wagmi/src/future/hooks/trade/hooks/useUSDCPrice.ts new file mode 100644 index 0000000000..cf950d4a8f --- /dev/null +++ b/packages/wagmi/src/future/hooks/trade/hooks/useUSDCPrice.ts @@ -0,0 +1,97 @@ +import { useMemo } from 'react' +import { useFeeData } from 'wagmi' +import { Amount, Price, Type, USDC } from '@sushiswap/currency' +import { ChainId } from '@sushiswap/chain' +import { useQuery } from '@tanstack/react-query' +import { usePoolsCodeMap } from '../../pools' +import { Router } from '@sushiswap/router' +import { ZERO } from '@sushiswap/math' +import { parseUnits } from 'ethers/lib/utils.js' + +export const useUSDCPrice = ({ + currency, + chainId, + enabled = true, +}: { + currency: Type | undefined + chainId: ChainId | undefined + enabled?: boolean +}) => { + const { usdc, usdcIn } = useMemo(() => { + const usdc = + chainId && chainId in USDC + ? USDC[chainId as keyof typeof USDC] + : undefined + + return { + usdc, + usdcIn: usdc ? parseUnits('1000', usdc.decimals) : undefined, + } + }, [chainId]) + + const { data: feeData } = useFeeData({ chainId: chainId }) + + const _chainId = chainId || 1 + + const { data: poolsCodeMap } = usePoolsCodeMap({ + chainId: _chainId, + currencyA: usdc, + currencyB: currency, + enabled: Boolean(chainId && usdc && currency), + withBentoPools: true, + }) + + return useQuery({ + queryKey: [ + 'useUSDCPrice', + { + chainId, + currency, + poolsCodeMap, + }, + ], + queryFn: async () => { + if ( + !chainId || + !poolsCodeMap || + !usdc || + !usdcIn || + !currency || + !feeData?.gasPrice + ) + return null + + if (currency.equals(usdc)) { + const amount = Amount.fromRawAmount(usdc, usdcIn.toString()) + return new Price({ baseAmount: amount, quoteAmount: amount }) + } + + const route = Router.findBestRoute( + poolsCodeMap, + chainId, + usdc, + usdcIn, + currency, + feeData.gasPrice.toNumber(), + ) + + if (route) { + const amountOut = Amount.fromRawAmount( + currency, + route.amountOutBN.toString(), + ) + const amountIn = Amount.fromRawAmount(usdc, route.amountInBN.toString()) + + return amountOut.greaterThan(ZERO) + ? new Price({ baseAmount: amountOut, quoteAmount: amountIn }) + : null + } + + return null + }, + refetchInterval: 10000, + enabled: Boolean( + enabled && chainId && poolsCodeMap && feeData && usdcIn && currency, + ), + }) +}