feat: adding currency conversion hook to useUSDPrice (#7251)
* feat: adding currency conversion hook * 5m cache policy * conversion rate hook * usd check in outer hook * converting usd price to localcurrencyprice * checking usd manually
This commit is contained in:
parent
60acc689ee
commit
5951d0c40c
@ -1,7 +1,7 @@
|
|||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||||
import Column, { AutoColumn } from 'components/Column'
|
import Column, { AutoColumn } from 'components/Column'
|
||||||
import { useUSDPrice } from 'hooks/useUSDPrice'
|
import { useLocalCurrencyPrice } from 'hooks/useLocalCurrencyPrice'
|
||||||
import { InterfaceTrade } from 'state/routing/types'
|
import { InterfaceTrade } from 'state/routing/types'
|
||||||
import { Field } from 'state/swap/actions'
|
import { Field } from 'state/swap/actions'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
@ -26,8 +26,8 @@ export default function SwapModalHeader({
|
|||||||
inputCurrency?: Currency
|
inputCurrency?: Currency
|
||||||
allowedSlippage: Percent
|
allowedSlippage: Percent
|
||||||
}) {
|
}) {
|
||||||
const fiatValueInput = useUSDPrice(trade.inputAmount)
|
const fiatValueInput = useLocalCurrencyPrice(trade.inputAmount)
|
||||||
const fiatValueOutput = useUSDPrice(trade.postTaxOutputAmount)
|
const fiatValueOutput = useLocalCurrencyPrice(trade.postTaxOutputAmount)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderContainer gap="sm">
|
<HeaderContainer gap="sm">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import { Currency, Price } from '@uniswap/sdk-core'
|
import { Currency, Price } from '@uniswap/sdk-core'
|
||||||
import { useUSDPrice } from 'hooks/useUSDPrice'
|
import { useLocalCurrencyPrice } from 'hooks/useLocalCurrencyPrice'
|
||||||
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
||||||
import { useCallback, useMemo, useState } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
@ -31,7 +31,9 @@ export default function TradePrice({ price }: TradePriceProps) {
|
|||||||
const [showInverted, setShowInverted] = useState<boolean>(false)
|
const [showInverted, setShowInverted] = useState<boolean>(false)
|
||||||
|
|
||||||
const { baseCurrency, quoteCurrency } = price
|
const { baseCurrency, quoteCurrency } = price
|
||||||
const { data: usdPrice } = useUSDPrice(tryParseCurrencyAmount('1', showInverted ? baseCurrency : quoteCurrency))
|
const { data: usdPrice } = useLocalCurrencyPrice(
|
||||||
|
tryParseCurrencyAmount('1', showInverted ? baseCurrency : quoteCurrency)
|
||||||
|
)
|
||||||
|
|
||||||
const formattedPrice = useMemo(() => {
|
const formattedPrice = useMemo(() => {
|
||||||
try {
|
try {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Currency } from 'graphql/data/__generated__/types-and-hooks'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -22,29 +23,29 @@ import {
|
|||||||
} from './localCurrencyIcons'
|
} from './localCurrencyIcons'
|
||||||
|
|
||||||
export const SUPPORTED_LOCAL_CURRENCIES = [
|
export const SUPPORTED_LOCAL_CURRENCIES = [
|
||||||
'USD',
|
Currency.Usd,
|
||||||
'AUD',
|
Currency.Aud,
|
||||||
'BRL',
|
Currency.Brl,
|
||||||
'CAD',
|
Currency.Cad,
|
||||||
'EUR',
|
Currency.Eur,
|
||||||
'GBP',
|
Currency.Gbp,
|
||||||
'HKD',
|
Currency.Hkd,
|
||||||
'IDR',
|
Currency.Idr,
|
||||||
'INR',
|
Currency.Inr,
|
||||||
'JPY',
|
Currency.Jpy,
|
||||||
'NGN',
|
Currency.Ngn,
|
||||||
'PKR',
|
Currency.Pkr,
|
||||||
'RUB',
|
Currency.Rub,
|
||||||
'SGD',
|
Currency.Sgd,
|
||||||
'THB',
|
Currency.Thb,
|
||||||
'TRY',
|
Currency.Try,
|
||||||
'UAH',
|
Currency.Uah,
|
||||||
'VND',
|
Currency.Vnd,
|
||||||
]
|
] as const
|
||||||
|
|
||||||
export type SupportedLocalCurrency = (typeof SUPPORTED_LOCAL_CURRENCIES)[number]
|
export type SupportedLocalCurrency = (typeof SUPPORTED_LOCAL_CURRENCIES)[number]
|
||||||
|
|
||||||
export const DEFAULT_LOCAL_CURRENCY: SupportedLocalCurrency = 'USD'
|
export const DEFAULT_LOCAL_CURRENCY: SupportedLocalCurrency = Currency.Usd
|
||||||
|
|
||||||
// some currencies need to be forced to use the narrow symbol and others need to be forced to use symbol
|
// some currencies need to be forced to use the narrow symbol and others need to be forced to use symbol
|
||||||
// for example: when CAD is set to narrowSymbol it is displayed as $ which offers no differentiation from USD
|
// for example: when CAD is set to narrowSymbol it is displayed as $ which offers no differentiation from USD
|
||||||
@ -73,41 +74,41 @@ export const LOCAL_CURRENCY_SYMBOL_DISPLAY_TYPE: Record<SupportedLocalCurrency,
|
|||||||
|
|
||||||
export function getLocalCurrencyIcon(localCurrency: SupportedLocalCurrency, size = 20): ReactNode {
|
export function getLocalCurrencyIcon(localCurrency: SupportedLocalCurrency, size = 20): ReactNode {
|
||||||
switch (localCurrency) {
|
switch (localCurrency) {
|
||||||
case 'USD':
|
case Currency.Usd:
|
||||||
return <USD_ICON width={size} height={size} />
|
return <USD_ICON width={size} height={size} />
|
||||||
case 'EUR':
|
case Currency.Eur:
|
||||||
return <EUR_ICON width={size} height={size} />
|
return <EUR_ICON width={size} height={size} />
|
||||||
case 'RUB':
|
case Currency.Rub:
|
||||||
return <RUB_ICON width={size} height={size} />
|
return <RUB_ICON width={size} height={size} />
|
||||||
case 'INR':
|
case Currency.Inr:
|
||||||
return <INR_ICON width={size} height={size} />
|
return <INR_ICON width={size} height={size} />
|
||||||
case 'GBP':
|
case Currency.Gbp:
|
||||||
return <GBP_ICON width={size} height={size} />
|
return <GBP_ICON width={size} height={size} />
|
||||||
case 'JPY':
|
case Currency.Jpy:
|
||||||
return <JPY_ICON width={size} height={size} />
|
return <JPY_ICON width={size} height={size} />
|
||||||
case 'VND':
|
case Currency.Vnd:
|
||||||
return <VND_ICON width={size} height={size} />
|
return <VND_ICON width={size} height={size} />
|
||||||
case 'SGD':
|
case Currency.Sgd:
|
||||||
return <SGD_ICON width={size} height={size} />
|
return <SGD_ICON width={size} height={size} />
|
||||||
case 'BRL':
|
case Currency.Brl:
|
||||||
return <BRL_ICON width={size} height={size} />
|
return <BRL_ICON width={size} height={size} />
|
||||||
case 'HKD':
|
case Currency.Hkd:
|
||||||
return <HKD_ICON width={size} height={size} />
|
return <HKD_ICON width={size} height={size} />
|
||||||
case 'CAD':
|
case Currency.Cad:
|
||||||
return <CAD_ICON width={size} height={size} />
|
return <CAD_ICON width={size} height={size} />
|
||||||
case 'IDR':
|
case Currency.Idr:
|
||||||
return <IDR_ICON width={size} height={size} />
|
return <IDR_ICON width={size} height={size} />
|
||||||
case 'TRY':
|
case Currency.Try:
|
||||||
return <TRY_ICON width={size} height={size} />
|
return <TRY_ICON width={size} height={size} />
|
||||||
case 'NGN':
|
case Currency.Ngn:
|
||||||
return <NGN_ICON width={size} height={size} />
|
return <NGN_ICON width={size} height={size} />
|
||||||
case 'AUD':
|
case Currency.Aud:
|
||||||
return <AUD_ICON width={size} height={size} />
|
return <AUD_ICON width={size} height={size} />
|
||||||
case 'PKR':
|
case Currency.Pkr:
|
||||||
return <PKR_ICON width={size} height={size} />
|
return <PKR_ICON width={size} height={size} />
|
||||||
case 'UAH':
|
case Currency.Uah:
|
||||||
return <UAH_ICON width={size} height={size} />
|
return <UAH_ICON width={size} height={size} />
|
||||||
case 'THB':
|
case Currency.Thb:
|
||||||
return <THB_ICON width={size} height={size} />
|
return <THB_ICON width={size} height={size} />
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
|
29
src/graphql/data/ConversionRate.ts
Normal file
29
src/graphql/data/ConversionRate.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { SupportedLocalCurrency } from 'constants/localCurrencies'
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
import ms from 'ms'
|
||||||
|
import { getFetchPolicyForKey } from 'utils/getFetchPolicyForKey'
|
||||||
|
|
||||||
|
import { useConvertQuery } from './__generated__/types-and-hooks'
|
||||||
|
|
||||||
|
gql`
|
||||||
|
query Convert($toCurrency: Currency!) {
|
||||||
|
convert(fromAmount: { currency: USD, value: 1.0 }, toCurrency: $toCurrency) {
|
||||||
|
id
|
||||||
|
value
|
||||||
|
currency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export function useLocalCurrencyConversionRate(localCurrency: SupportedLocalCurrency, skip?: boolean) {
|
||||||
|
const { data, loading } = useConvertQuery({
|
||||||
|
variables: { toCurrency: localCurrency },
|
||||||
|
fetchPolicy: getFetchPolicyForKey(`convert-${localCurrency}`, ms('5m')),
|
||||||
|
skip,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: data?.convert?.value,
|
||||||
|
isLoading: loading,
|
||||||
|
}
|
||||||
|
}
|
27
src/hooks/useLocalCurrencyPrice.ts
Normal file
27
src/hooks/useLocalCurrencyPrice.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { Currency } from 'graphql/data/__generated__/types-and-hooks'
|
||||||
|
import { useLocalCurrencyConversionRate } from 'graphql/data/ConversionRate'
|
||||||
|
|
||||||
|
import { useActiveLocalCurrency } from './useActiveLocalCurrency'
|
||||||
|
import { useUSDPrice } from './useUSDPrice'
|
||||||
|
|
||||||
|
type useUSDPriceParameters = Parameters<typeof useUSDPrice>
|
||||||
|
|
||||||
|
export function useLocalCurrencyPrice(...useUSDPriceParameters: useUSDPriceParameters) {
|
||||||
|
const activeLocalCurrency = useActiveLocalCurrency()
|
||||||
|
const activeLocalCurrencyIsUSD = activeLocalCurrency === Currency.Usd
|
||||||
|
|
||||||
|
const { data: usdPrice, isLoading: isUSDPriceLoading } = useUSDPrice(...useUSDPriceParameters)
|
||||||
|
const { data: localCurrencyConversionRate, isLoading: isLocalCurrencyConversionRateLoading } =
|
||||||
|
useLocalCurrencyConversionRate(activeLocalCurrency, activeLocalCurrencyIsUSD)
|
||||||
|
|
||||||
|
if (activeLocalCurrencyIsUSD) {
|
||||||
|
return { data: usdPrice, isLoading: isUSDPriceLoading }
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLoading = isUSDPriceLoading || isLocalCurrencyConversionRateLoading
|
||||||
|
if (!usdPrice || !localCurrencyConversionRate) {
|
||||||
|
return { data: undefined, isLoading }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data: usdPrice * localCurrencyConversionRate, isLoading: false }
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { formatEther } from '@ethersproject/units'
|
import { formatEther } from '@ethersproject/units'
|
||||||
import { ChainId } from '@uniswap/sdk-core'
|
import { ChainId } from '@uniswap/sdk-core'
|
||||||
import { useUSDPrice } from 'hooks/useUSDPrice'
|
import { useLocalCurrencyPrice } from 'hooks/useLocalCurrencyPrice'
|
||||||
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
||||||
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
||||||
import { GenieAsset } from 'nft/types'
|
import { GenieAsset } from 'nft/types'
|
||||||
@ -8,7 +8,7 @@ import { GenieAsset } from 'nft/types'
|
|||||||
export const useNativeUsdPrice = (chainId: number = ChainId.MAINNET): number => {
|
export const useNativeUsdPrice = (chainId: number = ChainId.MAINNET): number => {
|
||||||
const nativeCurrency = useNativeCurrency(chainId)
|
const nativeCurrency = useNativeCurrency(chainId)
|
||||||
const parsedAmount = tryParseCurrencyAmount('1', nativeCurrency)
|
const parsedAmount = tryParseCurrencyAmount('1', nativeCurrency)
|
||||||
const usdcValue = useUSDPrice(parsedAmount)?.data ?? 0
|
const usdcValue = useLocalCurrencyPrice(parsedAmount)?.data ?? 0
|
||||||
return usdcValue
|
return usdcValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,12 +34,12 @@ import { asSupportedChain, isSupportedChain } from 'constants/chains'
|
|||||||
import { getSwapCurrencyId, TOKEN_SHORTHANDS } from 'constants/tokens'
|
import { getSwapCurrencyId, TOKEN_SHORTHANDS } from 'constants/tokens'
|
||||||
import { useCurrency, useDefaultActiveTokens } from 'hooks/Tokens'
|
import { useCurrency, useDefaultActiveTokens } from 'hooks/Tokens'
|
||||||
import { useIsSwapUnsupported } from 'hooks/useIsSwapUnsupported'
|
import { useIsSwapUnsupported } from 'hooks/useIsSwapUnsupported'
|
||||||
|
import { useLocalCurrencyPrice } from 'hooks/useLocalCurrencyPrice'
|
||||||
import { useMaxAmountIn } from 'hooks/useMaxAmountIn'
|
import { useMaxAmountIn } from 'hooks/useMaxAmountIn'
|
||||||
import usePermit2Allowance, { AllowanceState } from 'hooks/usePermit2Allowance'
|
import usePermit2Allowance, { AllowanceState } from 'hooks/usePermit2Allowance'
|
||||||
import usePrevious from 'hooks/usePrevious'
|
import usePrevious from 'hooks/usePrevious'
|
||||||
import { SwapResult, useSwapCallback } from 'hooks/useSwapCallback'
|
import { SwapResult, useSwapCallback } from 'hooks/useSwapCallback'
|
||||||
import { useSwitchChain } from 'hooks/useSwitchChain'
|
import { useSwitchChain } from 'hooks/useSwitchChain'
|
||||||
import { useUSDPrice } from 'hooks/useUSDPrice'
|
|
||||||
import useWrapCallback, { WrapErrorText, WrapType } from 'hooks/useWrapCallback'
|
import useWrapCallback, { WrapErrorText, WrapType } from 'hooks/useWrapCallback'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
import { formatSwapQuoteReceivedEventProperties } from 'lib/utils/analytics'
|
import { formatSwapQuoteReceivedEventProperties } from 'lib/utils/analytics'
|
||||||
@ -313,8 +313,8 @@ export function Swap({
|
|||||||
[independentField, parsedAmount, showWrap, trade]
|
[independentField, parsedAmount, showWrap, trade]
|
||||||
)
|
)
|
||||||
|
|
||||||
const fiatValueInput = useUSDPrice(parsedAmounts[Field.INPUT], currencies[Field.INPUT] ?? undefined)
|
const fiatValueInput = useLocalCurrencyPrice(parsedAmounts[Field.INPUT], currencies[Field.INPUT] ?? undefined)
|
||||||
const fiatValueOutput = useUSDPrice(parsedAmounts[Field.OUTPUT], currencies[Field.OUTPUT] ?? undefined)
|
const fiatValueOutput = useLocalCurrencyPrice(parsedAmounts[Field.OUTPUT], currencies[Field.OUTPUT] ?? undefined)
|
||||||
const showFiatValueInput = Boolean(parsedAmounts[Field.INPUT])
|
const showFiatValueInput = Boolean(parsedAmounts[Field.INPUT])
|
||||||
const showFiatValueOutput = Boolean(parsedAmounts[Field.OUTPUT])
|
const showFiatValueOutput = Boolean(parsedAmounts[Field.OUTPUT])
|
||||||
|
|
||||||
@ -327,9 +327,9 @@ export function Swap({
|
|||||||
[trade, tradeState]
|
[trade, tradeState]
|
||||||
)
|
)
|
||||||
|
|
||||||
const fiatValueTradeInput = useUSDPrice(trade?.inputAmount)
|
const fiatValueTradeInput = useLocalCurrencyPrice(trade?.inputAmount)
|
||||||
const fiatValueTradeOutput = useUSDPrice(trade?.postTaxOutputAmount)
|
const fiatValueTradeOutput = useLocalCurrencyPrice(trade?.postTaxOutputAmount)
|
||||||
const preTaxFiatValueTradeOutput = useUSDPrice(trade?.outputAmount)
|
const preTaxFiatValueTradeOutput = useLocalCurrencyPrice(trade?.outputAmount)
|
||||||
const [stablecoinPriceImpact, preTaxStablecoinPriceImpact] = useMemo(
|
const [stablecoinPriceImpact, preTaxStablecoinPriceImpact] = useMemo(
|
||||||
() =>
|
() =>
|
||||||
routeIsSyncing || !isClassicTrade(trade)
|
routeIsSyncing || !isClassicTrade(trade)
|
||||||
|
16
src/utils/getFetchPolicyForKey.ts
Normal file
16
src/utils/getFetchPolicyForKey.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { WatchQueryFetchPolicy } from '@apollo/client'
|
||||||
|
|
||||||
|
const keys = new Map<string, number>()
|
||||||
|
|
||||||
|
export const getFetchPolicyForKey = (key: string, expirationMs: number): WatchQueryFetchPolicy => {
|
||||||
|
const lastFetchTimestamp = keys.get(key)
|
||||||
|
const diffFromNow = lastFetchTimestamp ? Date.now() - lastFetchTimestamp : Number.MAX_SAFE_INTEGER
|
||||||
|
let fetchPolicy: WatchQueryFetchPolicy = 'cache-first'
|
||||||
|
|
||||||
|
if (diffFromNow > expirationMs) {
|
||||||
|
keys.set(key, Date.now())
|
||||||
|
fetchPolicy = 'network-only'
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetchPolicy
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user