From ca1c8fdf46e7e209bddcd35493ef506af024ff7b Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 13 Sep 2023 16:18:35 +0700 Subject: [PATCH 01/13] improvement: subscript decimals (#2219) --- package.json | 3 +- .../EarningAreaChart/TooltipContent.tsx | 36 +--- src/components/EarningAreaChart/index.tsx | 49 +---- src/components/EarningAreaChart/utils.ts | 19 -- src/components/EarningPieChart/index.tsx | 39 +--- src/components/Header/web3/SelectNetwork.tsx | 10 +- .../ProAmm/ProAmmPriceRangeConfirm.tsx | 4 +- src/components/SwapForm/TradeSummary.tsx | 16 +- .../YieldPools/FarmingPoolAPRCell.tsx | 13 +- src/components/swapv2/TradePrice.tsx | 3 +- src/constants/index.ts | 9 +- .../AddLiquidityV2/components/NewPoolNote.tsx | 12 +- src/pages/AddLiquidityV2/index.tsx | 43 +++-- src/pages/Bridge/helpers.ts | 1 + .../LeaderBoardSection/index.tsx | 15 +- .../GrantProgram/SingleProgram/Stats.tsx | 17 +- .../ClassicPools/SinglePool/Position.tsx | 41 ++--- .../ClassicPools/SinglePool/index.tsx | 65 +++++-- .../MyEarnings/EarningsBreakdownPanel.tsx | 4 +- .../ElasticPools/SinglePool/index.tsx | 64 +++++-- .../SinglePosition/EarningView.tsx | 15 +- .../SinglePosition/PositionView.tsx | 12 +- src/pages/MyEarnings/HoverDropdown.tsx | 2 +- src/pages/MyEarnings/PoolEarningsSection.tsx | 7 +- src/pages/MyEarnings/ShareModal.tsx | 15 +- .../TotalEarningsAndChainSelect.tsx | 24 +-- src/utils/fee.ts | 8 +- src/utils/firebase.ts | 1 - src/utils/formatCurrencyAmount.tsx | 3 + src/utils/formatTickPrice.ts | 4 +- src/utils/index.ts | 3 + src/utils/numbers.ts | 171 +++++++++++++++++- yarn.lock | 78 +------- 33 files changed, 420 insertions(+), 386 deletions(-) delete mode 100644 src/components/EarningAreaChart/utils.ts diff --git a/package.json b/package.json index cf574679da..c26978d999 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,6 @@ "@types/big.js": "^6.0.0", "@types/crypto-js": "4.1.1", "@types/d3": "^7.1.0", - "@types/jest": "^25.2.1", "@types/mixpanel-browser": "^2.38.0", "@types/multicodec": "^1.0.0", "@types/node": "^13.13.52", @@ -206,4 +205,4 @@ "@lingui/core": "3.14.0", "@lingui/conf": "3.16.0" } -} +} \ No newline at end of file diff --git a/src/components/EarningAreaChart/TooltipContent.tsx b/src/components/EarningAreaChart/TooltipContent.tsx index 1f49820110..f3367de4f2 100644 --- a/src/components/EarningAreaChart/TooltipContent.tsx +++ b/src/components/EarningAreaChart/TooltipContent.tsx @@ -7,26 +7,7 @@ import styled from 'styled-components' import Logo, { NetworkLogo } from 'components/Logo' import useTheme from 'hooks/useTheme' import { EarningStatsTick } from 'types/myEarnings' -import { formattedNum } from 'utils' - -const formatUSDValue = (v: number) => { - if (v === 0) { - return '$0' - } - - if (v < 0.0001) { - return '< $0.0001' - } - - const formatter = Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - notation: 'compact', - maximumSignificantDigits: 4, - }) - - return formatter.format(v) -} +import { formatDisplayNumber } from 'utils/numbers' const TokensWrapper = styled.div` display: flex; @@ -37,10 +18,6 @@ const TokensWrapper = styled.div` font-weight: 500; ` -const formatTokenAmount = (a: number | string) => { - return formattedNum(String(a), false) -} - type TokensProps = { tokens: EarningStatsTick['tokens'] } @@ -102,7 +79,7 @@ const Tokens: React.FC = ({ tokens }) => { lineHeight: '14px', }} > - {formatTokenAmount(token.amount)} + {formatDisplayNumber(token.amount, { significantDigits: 6 })} ) @@ -176,7 +153,8 @@ const TooltipContent: React.FC = ({ dataEntry, setHoverValue }) => { whiteSpace: 'nowrap', }} > - My Total Earnings: {formatUSDValue(dataEntry.totalValue)} + My Total Earnings:{' '} + {formatDisplayNumber(dataEntry.totalValue, { style: 'currency', significantDigits: 6 })} = ({ dataEntry, setHoverValue }) => { whiteSpace: 'nowrap', }} > - Pool Fees: {formatUSDValue(dataEntry.poolFeesValue)} + Pool Fees:{' '} + {formatDisplayNumber(dataEntry.poolFeesValue, { style: 'currency', significantDigits: 6 })} = ({ dataEntry, setHoverValue }) => { whiteSpace: 'nowrap', }} > - Farm Rewards: {formatUSDValue(dataEntry.farmRewardsValue)} + Farm Rewards:{' '} + {formatDisplayNumber(dataEntry.farmRewardsValue, { style: 'currency', significantDigits: 6 })} = { ['7D']: isMobile ? 2 : 1, @@ -36,53 +35,13 @@ const CustomizedLabel = (props: any) => { fill={theme.subText} textAnchor="middle" > - {formatUSDValue(value)} + {formatDisplayNumber(value, { style: 'currency', fractionDigits: 3 })} )} ) } -const subscriptMap: { [key: string]: string } = { - '0': '₀', - '1': '₁', - '2': '₂', - '3': '₃', - '4': '₄', - '5': '₅', - '6': '₆', - '7': '₇', - '8': '₈', - '9': '₉', -} - -const formatter = (value: string) => { - const num = parseFloat(value) - const numberOfZero = -Math.floor(Math.log10(num) + 1) - - if (num > 0 && num < 1 && numberOfZero > 2) { - const temp = Number(toFixed(num).split('.')[1]).toString() - - return `$0.0${numberOfZero - .toString() - .split('') - .map(item => subscriptMap[item]) - .join('')}${temp.substring(0, 2)}` - } - - const formatter = Intl.NumberFormat('en-US', { - notation: num >= 1000 ? 'compact' : 'standard', - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 2, - minimumSignificantDigits: 1, - maximumSignificantDigits: 2, - }) - - return formatter.format(num) -} - type Props = { period: TimePeriod setHoverValue?: React.Dispatch> @@ -123,7 +82,9 @@ const EarningAreaChart: React.FC = ({ data, setHoverValue = EMPTY_FUNCTIO axisLine={false} tickLine={false} stroke={theme.subText} - tickFormatter={(value: any, _index: number) => formatter(String(value))} + tickFormatter={(value: any, _index: number) => + formatDisplayNumber(value, { style: 'currency', fractionDigits: 2 }) + } width={54} /> diff --git a/src/components/EarningAreaChart/utils.ts b/src/components/EarningAreaChart/utils.ts deleted file mode 100644 index 2c7cc4c85d..0000000000 --- a/src/components/EarningAreaChart/utils.ts +++ /dev/null @@ -1,19 +0,0 @@ -export const formatUSDValue = (v: number, compact = true): string => { - if (v === 0) { - return '$0' - } - - if (v < 0.01) { - return '< $0.01' - } - - const formatter = Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - notation: compact ? 'compact' : 'standard', - minimumFractionDigits: 0, - maximumFractionDigits: 2, - }) - - return formatter.format(v) -} diff --git a/src/components/EarningPieChart/index.tsx b/src/components/EarningPieChart/index.tsx index 604f3ab20b..26dca83f20 100644 --- a/src/components/EarningPieChart/index.tsx +++ b/src/components/EarningPieChart/index.tsx @@ -11,41 +11,7 @@ import Logo, { NetworkLogo } from 'components/Logo' import { EMPTY_ARRAY } from 'constants/index' import useTheme from 'hooks/useTheme' import { Loading } from 'pages/ProAmmPool/ContentLoader' - -const formatUSDValue = (v: string) => { - const num = Number(v) - - if (num === 0) { - return '$0' - } - - if (num < 0.01) { - return '< $0.01' - } - - const formatter = Intl.NumberFormat('en-US', { - notation: 'compact', - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: num < 0.1 ? 2 : 1, - }) - - return formatter.format(num) -} - -const formatPercent = (num: number) => { - if (num < 0.01) { - return '< 0.01%' - } - - const formatter = Intl.NumberFormat('en-US', { - minimumFractionDigits: 0, - maximumFractionDigits: 2, - }) - - return formatter.format(num) + '%' -} +import { formatDisplayNumber } from 'utils/numbers' const LegendsWrapper = styled.div` display: flex; @@ -179,7 +145,8 @@ const Legend: React.FC = ({ whiteSpace: 'nowrap', }} > - {formatUSDValue(value)} ({formatPercent(percent)}) + {formatDisplayNumber(value, { style: 'currency', fractionDigits: 2 })} ( + {formatDisplayNumber(percent / 100, { style: 'percent', fractionDigits: 3 })}) diff --git a/src/components/Header/web3/SelectNetwork.tsx b/src/components/Header/web3/SelectNetwork.tsx index cee6ad5043..5cb6b18179 100644 --- a/src/components/Header/web3/SelectNetwork.tsx +++ b/src/components/Header/web3/SelectNetwork.tsx @@ -16,6 +16,7 @@ import { ApplicationModal } from 'state/application/actions' import { useModalOpen, useNetworkModalToggle } from 'state/application/hooks' import { useIsDarkMode } from 'state/user/hooks' import { useNativeBalance } from 'state/wallet/hooks' +import { formatDisplayNumber } from 'utils/numbers' const NetworkSwitchContainer = styled.div` display: flex; @@ -74,13 +75,8 @@ function SelectNetwork(): JSX.Element | null { const userEthBalance = useNativeBalance() const labelContent = useMemo(() => { if (!userEthBalance) return networkInfo.name - const balanceFixedStr = userEthBalance.lessThan(1000 * 10 ** NativeCurrencies[chainId].decimals) // less than 1000 - ? userEthBalance.lessThan(10 ** NativeCurrencies[chainId].decimals) // less than 1 - ? parseFloat(userEthBalance.toSignificant(6)).toFixed(6) - : parseFloat(userEthBalance.toExact()).toFixed(4) - : parseFloat(userEthBalance.toExact()).toFixed(2) - const balanceFixed = Number(balanceFixedStr) - return `${balanceFixed} ${NativeCurrencies[chainId].symbol}` + const balanceFixedStr = formatDisplayNumber(userEthBalance, { significantDigits: 6 }) + return `${balanceFixedStr} ${NativeCurrencies[chainId].symbol}` }, [userEthBalance, chainId, networkInfo]) const walletSupportsChain = useWalletSupportedChains() const disableSelectNetwork = walletSupportsChain.length <= 1 diff --git a/src/components/ProAmm/ProAmmPriceRangeConfirm.tsx b/src/components/ProAmm/ProAmmPriceRangeConfirm.tsx index 6c73ef8e2b..c1a48aadcb 100644 --- a/src/components/ProAmm/ProAmmPriceRangeConfirm.tsx +++ b/src/components/ProAmm/ProAmmPriceRangeConfirm.tsx @@ -15,8 +15,8 @@ import useTheme from 'hooks/useTheme' import { Bound } from 'state/mint/proamm/type' import { useUserSlippageTolerance } from 'state/user/hooks' import { ExternalLink, TYPE } from 'theme' -import { toSignificantOrMaxIntegerPart } from 'utils/formatCurrencyAmount' import { formatTickPrice } from 'utils/formatTickPrice' +import { formatDisplayNumber } from 'utils/numbers' import { checkWarningSlippage, formatSlippage } from 'utils/slippage' import { unwrappedToken } from 'utils/wrappedCurrency' @@ -80,7 +80,7 @@ export default function ProAmmPriceRangeConfirm({ - 1 {baseCurrency.symbol} = {toSignificantOrMaxIntegerPart(price, 6)} {quoteCurrency.symbol} + 1 {baseCurrency.symbol} = {formatDisplayNumber(price, { significantDigits: 6 })} {quoteCurrency.symbol} diff --git a/src/components/SwapForm/TradeSummary.tsx b/src/components/SwapForm/TradeSummary.tsx index 6018b935dd..6bbc3825e8 100644 --- a/src/components/SwapForm/TradeSummary.tsx +++ b/src/components/SwapForm/TradeSummary.tsx @@ -20,6 +20,7 @@ import { ExternalLink, TYPE } from 'theme' import { DetailedRouteSummary } from 'types/route' import { formattedNum } from 'utils' import { minimumAmountAfterSlippage } from 'utils/currencyAmount' +import { formatDisplayNumber } from 'utils/numbers' import { checkPriceImpact, formatPriceImpact } from 'utils/prices' const IconWrapper = styled.div<{ $flip: boolean }>` @@ -64,22 +65,15 @@ const Wrapper = styled.div.attrs(props => ({ } ` -const formatPercent = (v: number) => { - const formatter = Intl.NumberFormat('en-US', { - minimumFractionDigits: 0, - maximumFractionDigits: 2, - style: 'percent', - }) - - return formatter.format(v) -} - type TooltipTextOfSwapFeeProps = { feeBips: string | undefined feeAmountText: string } export const TooltipTextOfSwapFee: React.FC = ({ feeBips, feeAmountText }) => { - const feePercent = formatPercent(Number(feeBips) / Number(BIPS_BASE.toString())) + const feePercent = formatDisplayNumber(Number(feeBips) / Number(BIPS_BASE.toString()), { + style: 'percent', + fractionDigits: 2, + }) const hereLink = ( diff --git a/src/components/YieldPools/FarmingPoolAPRCell.tsx b/src/components/YieldPools/FarmingPoolAPRCell.tsx index bebfd9565f..83c1d376a6 100644 --- a/src/components/YieldPools/FarmingPoolAPRCell.tsx +++ b/src/components/YieldPools/FarmingPoolAPRCell.tsx @@ -15,6 +15,7 @@ import { useElasticFarms } from 'state/farms/elastic/hooks' import { useTokenPrices } from 'state/tokenPrices/hooks' import { MEDIA_WIDTHS } from 'theme' import { useFarmApr } from 'utils/dmm' +import { formatDisplayNumber } from 'utils/numbers' export const APRTooltipContent = ({ poolAPR, @@ -43,7 +44,7 @@ export const APRTooltipContent = ({ Total APR:{' '} - {(poolAPR + maxFarmAPR).toFixed(2)}% + {formatDisplayNumber((poolAPR + maxFarmAPR) / 100, { style: 'percent', fractionDigits: 2 })} Pool APR:{' '} - {poolAPR.toFixed(2)}% + {formatDisplayNumber(poolAPR / 100, { style: 'percent', fractionDigits: 2 })} Farm APR:{' '} - {farmAPR.toFixed(2)}% + {formatDisplayNumber(farmAPR / 100, { style: 'percent', fractionDigits: 2 })} Farm APR:{' '} - {farmV2APR.toFixed(2)}% + {formatDisplayNumber(farmV2APR / 100, { style: 'percent', fractionDigits: 2 })} = ({ text={} > - {(poolAPR + maxFarmAPR).toFixed(2)}% + {formatDisplayNumber((poolAPR + maxFarmAPR) / 100, { style: 'percent', fractionDigits: 2 })} @@ -217,7 +218,7 @@ export const ClassicFarmingPoolAPRCell = ({ poolAPR, farm }: { poolAPR: number; gap: '4px', }} > - {(poolAPR + farmAPR).toFixed(2)}% + {formatDisplayNumber((poolAPR + farmAPR) / 100, { style: 'percent', fractionDigits: 2 })} }> diff --git a/src/components/swapv2/TradePrice.tsx b/src/components/swapv2/TradePrice.tsx index 3bb77e043f..be8b493881 100644 --- a/src/components/swapv2/TradePrice.tsx +++ b/src/components/swapv2/TradePrice.tsx @@ -7,6 +7,7 @@ import { CSSProperties } from 'styled-components' import useTheme from 'hooks/useTheme' import { useCurrencyConvertedToNative } from 'utils/dmm' +import { formatDisplayNumber } from 'utils/numbers' import { Dots, StyledBalanceMaxMini } from './styleds' @@ -23,7 +24,7 @@ export default function TradePrice({ price, label, icon, style = {}, color }: Tr const [showInverted, setShowInverted] = useState(false) let formattedPrice try { - formattedPrice = showInverted ? price?.invert()?.toSignificant(6) : price?.toSignificant(6) + formattedPrice = formatDisplayNumber(showInverted ? price?.invert() : price, { significantDigits: 7 }) } catch (error) {} const show = Boolean(price?.baseCurrency && price?.quoteCurrency && formattedPrice) diff --git a/src/constants/index.ts b/src/constants/index.ts index d0a2696b93..c71fa4e63a 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -8,7 +8,6 @@ import { TransactionFlowState } from 'types/TransactionFlowState' import { CAMPAIGN_BASE_URL as CAMPAIGN_BASE_DOMAIN } from './env' import * as ENV from './env' import { EVM_NETWORK, NETWORKS_INFO, SUPPORTED_NETWORKS, isEVM } from './networks' -import { ENV_TYPE } from './type' export const EMPTY_OBJECT: any = {} export const EMPTY_ARRAY: any[] = [] @@ -126,6 +125,8 @@ export const DEFAULT_DEADLINE_FROM_NOW = 60 * 20 // denominated in seconds export const TIME_TO_REFRESH_SWAP_RATE = 10 +export const BIG_INT_ONE = JSBI.BigInt(1) +export const BIG_INT_MINUS_ONE = JSBI.BigInt(-1) export const BIG_INT_ZERO = JSBI.BigInt(0) // one basis point @@ -261,12 +262,6 @@ export const EIP712Domain = [ { name: 'verifyingContract', type: 'address' }, ] -if (ENV.ENV_LEVEL < ENV_TYPE.PROD) { - console.groupCollapsed('ENV') - console.log(JSON.stringify(ENV, null, 4)) - console.groupEnd() -} - export const INPUT_DEBOUNCE_TIME = 300 export const ENABLE_CLICK_TO_REFRESH_GET_ROUTE = false diff --git a/src/pages/AddLiquidityV2/components/NewPoolNote.tsx b/src/pages/AddLiquidityV2/components/NewPoolNote.tsx index c67ee68be3..bf1bc4bc85 100644 --- a/src/pages/AddLiquidityV2/components/NewPoolNote.tsx +++ b/src/pages/AddLiquidityV2/components/NewPoolNote.tsx @@ -8,7 +8,7 @@ import SwitchIcon from 'components/Icons/SwitchIcon' import { RowBetween } from 'components/Row' import useTheme from 'hooks/useTheme' import { TYPE } from 'theme' -import { formattedNum } from 'utils' +import { formatDisplayNumber } from 'utils/numbers' import { Spin } from '../styled' @@ -43,10 +43,12 @@ function NewPoolNote({ maxCharacters={24} text={ !invertMarketPrice - ? `1 ${baseCurrency?.symbol} = ${formattedNum(marketPrice.toString())} ${quoteCurrency?.symbol}` - : `1 ${quoteCurrency?.symbol} = ${formattedNum((1 / marketPrice).toString())} ${ - baseCurrency?.symbol - }` + ? `1 ${baseCurrency?.symbol} = ${formatDisplayNumber(marketPrice, { + significantDigits: 6, + })} ${quoteCurrency?.symbol}` + : `1 ${quoteCurrency?.symbol} = ${formatDisplayNumber(1 / marketPrice, { + significantDigits: 6, + })} ${baseCurrency?.symbol}` } /> diff --git a/src/pages/AddLiquidityV2/index.tsx b/src/pages/AddLiquidityV2/index.tsx index a2baac7ae7..6b6de01c6f 100644 --- a/src/pages/AddLiquidityV2/index.tsx +++ b/src/pages/AddLiquidityV2/index.tsx @@ -87,9 +87,8 @@ import { ExternalLink, MEDIA_WIDTHS, StyledInternalLink, TYPE } from 'theme' import { basisPointsToPercent, calculateGasMargin, formattedNum } from 'utils' import { currencyId } from 'utils/currencyId' import { friendlyError } from 'utils/errorMessage' -import { toSignificantOrMaxIntegerPart } from 'utils/formatCurrencyAmount' import { maxAmountSpend } from 'utils/maxAmountSpend' -import { formatNotDollarAmount } from 'utils/numbers' +import { formatDisplayNumber } from 'utils/numbers' import { SLIPPAGE_STATUS, checkRangeSlippage } from 'utils/slippage' import { unwrappedToken } from 'utils/wrappedCurrency' @@ -806,10 +805,13 @@ export default function AddLiquidity() { - Note: A very small amount of your liquidity about {formattedNum(amountUnlockUSD.toString(), true)}{' '} + Note: A very small amount of your liquidity about{' '} + {formatDisplayNumber(amountUnlockUSD, { style: 'currency', significantDigits: 6 })}{' '} - ({amountUnlocks[Field.CURRENCY_A].toSignificant(6)} {amountUnlocks[Field.CURRENCY_A].currency.symbol},{' '} - {amountUnlocks[Field.CURRENCY_B].toSignificant(6)} {amountUnlocks[Field.CURRENCY_B].currency.symbol}) + ({formatDisplayNumber(amountUnlocks[Field.CURRENCY_A], { significantDigits: 6 })}{' '} + {amountUnlocks[Field.CURRENCY_A].currency.symbol},{' '} + {formatDisplayNumber(amountUnlocks[Field.CURRENCY_B], { significantDigits: 6 })}{' '} + {amountUnlocks[Field.CURRENCY_B].currency.symbol}) {' '} will be used to first initialize the pool. Read more{' '} @@ -828,17 +830,21 @@ export default function AddLiquidity() { {noLiquidity ? ( The pool’s current price of 1 {baseCurrency.symbol} ={' '} - {(invertPrice ? price.invert() : price).toSignificant(4)} {quoteCurrency.symbol} deviates from the - market price (1 {baseCurrency.symbol} ={' '} - {formatNotDollarAmount(usdPrices[tokenA.wrapped.address] / usdPrices[tokenB.wrapped.address], 4)}{' '} + {formatDisplayNumber(invertPrice ? price.invert() : price, { significantDigits: 4 })}{' '} + {quoteCurrency.symbol} deviates from the market price (1 {baseCurrency.symbol} ={' '} + {formatDisplayNumber(usdPrices[tokenA.wrapped.address] / usdPrices[tokenB.wrapped.address], { + significantDigits: 4, + })}{' '} {quoteCurrency.symbol}). You might have high impermanent loss after the pool is created ) : ( The pool’s current price of 1 {baseCurrency.symbol} ={' '} - {(invertPrice ? price.invert() : price).toSignificant(4)} {quoteCurrency.symbol} deviates from the - market price (1 {baseCurrency.symbol} ={' '} - {formatNotDollarAmount(usdPrices[tokenA.wrapped.address] / usdPrices[tokenB.wrapped.address], 4)}{' '} + {formatDisplayNumber(invertPrice ? price.invert() : price, { significantDigits: 4 })}{' '} + {quoteCurrency.symbol} deviates from the market price (1 {baseCurrency.symbol} ={' '} + {formatDisplayNumber(usdPrices[tokenA.wrapped.address] / usdPrices[tokenB.wrapped.address], { + significantDigits: 4, + })}{' '} {quoteCurrency.symbol}). You might have high impermanent loss after you add liquidity to this pool )} @@ -1094,7 +1100,9 @@ export default function AddLiquidity() { @@ -1535,11 +1543,12 @@ export default function AddLiquidity() { diff --git a/src/pages/Bridge/helpers.ts b/src/pages/Bridge/helpers.ts index 701aa5652d..d25b756b84 100644 --- a/src/pages/Bridge/helpers.ts +++ b/src/pages/Bridge/helpers.ts @@ -166,6 +166,7 @@ export const formatPoolValue = (amount: PoolBridgeValue) => { 123456789012.123456 => 123.457B 1234567890123.123456 => 1.23457T */ +// todo: deprecated, use formatDisplayNumber instead export const formatAmountBridge = (rawAmount: string) => { const amount = parseFloat(String(rawAmount) ?? '0') if (amount > 100_000_000) { diff --git a/src/pages/GrantProgram/SingleProgram/LeaderBoardSection/index.tsx b/src/pages/GrantProgram/SingleProgram/LeaderBoardSection/index.tsx index 9e0d5124b1..a12f8ea50b 100644 --- a/src/pages/GrantProgram/SingleProgram/LeaderBoardSection/index.tsx +++ b/src/pages/GrantProgram/SingleProgram/LeaderBoardSection/index.tsx @@ -7,6 +7,7 @@ import Loader from 'components/Loader' import useGetLeaderboardGrantProgram, { RankByParam } from 'hooks/campaigns/useGetLeaderboardGrantProgram' import useTheme from 'hooks/useTheme' import { ProjectRanking } from 'types/grantProgram' +import { formatDisplayNumber } from 'utils/numbers' import { HeaderText } from '../../styleds' import LeaderBoard from './LeaderBoard' @@ -25,18 +26,6 @@ const EmptyRankings: any[] = [] export const ITEMS_PER_PAGE = 5 -const formatTradingVolume = (num: number) => { - const notation = num > 100_000_000 ? 'compact' : 'standard' - const formatter = new Intl.NumberFormat('en-US', { - notation, - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }) - return formatter.format(num) -} - export type RankByConfig = { extracter: (p: ProjectRanking) => string // used to extract the value param: RankByParam // used as param in GET request @@ -53,7 +42,7 @@ const rankByConfigs: RankByConfig[] = [ }, { extracter: (p: ProjectRanking) => { - return formatTradingVolume(Number(p.totalVolume)) + return formatDisplayNumber(p.totalVolume, { style: 'currency', significantDigits: 10, fractionDigits: 0 }) }, param: 'total_volume', title: t`Trading Volume`, diff --git a/src/pages/GrantProgram/SingleProgram/Stats.tsx b/src/pages/GrantProgram/SingleProgram/Stats.tsx index 49b2772ca4..5a1d28b5d6 100644 --- a/src/pages/GrantProgram/SingleProgram/Stats.tsx +++ b/src/pages/GrantProgram/SingleProgram/Stats.tsx @@ -6,6 +6,7 @@ import { ReactComponent as CampaignParticipants } from 'assets/svg/campaign_part import { ReactComponent as CampaignTrades } from 'assets/svg/campaign_trades.svg' import { ReactComponent as CampaignVolume } from 'assets/svg/campaign_volume.svg' import Loader from 'components/Loader' +import { formatDisplayNumber } from 'utils/numbers' const StatsCardWrapper = styled.div` display: flex; @@ -77,18 +78,6 @@ type Props = { trades?: number } -const formatTradingVolume = (v: string) => { - const formatter = Intl.NumberFormat('en-US', { - notation: 'compact', - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 1, - }) - - return formatter.format(Number(v)) -} - const formatNumber = (v: number) => { const formatter = Intl.NumberFormat('en-US', { notation: 'compact', @@ -134,7 +123,9 @@ const Stats: React.FC = ({ participants, trades, volume }) => { } - value={volume ? formatTradingVolume(volume) : volume} + value={ + volume ? formatDisplayNumber(volume, { style: 'currency', fractionDigits: 2, significantDigits: 6 }) : volume + } title="Total Trading Volume" /> = ({ poolEarning, chainId }) => { const myLiquidityBalance = poolEarning.liquidityTokenBalanceIncludingStake !== '0' && poolEarning.pool.totalSupply !== '0' - ? formatDollarAmount( + ? formatDisplayNumber( (+poolEarning.liquidityTokenBalanceIncludingStake * +poolEarning.pool.reserveUSD) / +poolEarning.pool.totalSupply, + { + style: 'currency', + significantDigits: 6, + }, ) : '--' @@ -96,10 +99,13 @@ const Position: React.FC = ({ poolEarning, chainId }) => { ) const liquidityStaked = +poolEarning.liquidityTokenBalanceIncludingStake - +poolEarning.liquidityTokenBalance - const myStakedBalance = - liquidityStaked !== 0 - ? formatDollarAmount((liquidityStaked * +poolEarning.pool.reserveUSD) / +poolEarning.pool.totalSupply) - : '--' + const myStakedBalance = formatDisplayNumber( + (liquidityStaked * +poolEarning.pool.reserveUSD) / +poolEarning.pool.totalSupply, + { + style: 'currency', + significantDigits: 6, + }, + ) const stakedShare = liquidityStaked / +poolEarning.pool.totalSupply @@ -155,13 +161,13 @@ const Position: React.FC = ({ poolEarning, chainId }) => { - {formattedNum(pooledToken0)} {unwrappedToken(token0).symbol} + {formatDisplayNumber(pooledToken0, { significantDigits: 6 })} {unwrappedToken(token0).symbol} - {formattedNum(pooledToken1)} {unwrappedToken(token1).symbol} + {formatDisplayNumber(pooledToken1, { significantDigits: 6 })} {unwrappedToken(token1).symbol} @@ -183,13 +189,13 @@ const Position: React.FC = ({ poolEarning, chainId }) => { - {formattedNum(stakedToken0)} {unwrappedToken(token0).symbol} + {formatDisplayNumber(stakedToken0, { significantDigits: 6 })} {unwrappedToken(token0).symbol} - {formattedNum(stakedToken1)} {unwrappedToken(token1).symbol} + {formatDisplayNumber(stakedToken1, { significantDigits: 6 })} {unwrappedToken(token1).symbol} @@ -201,22 +207,15 @@ const Position: React.FC = ({ poolEarning, chainId }) => { - + ) diff --git a/src/pages/MyEarnings/ClassicPools/SinglePool/index.tsx b/src/pages/MyEarnings/ClassicPools/SinglePool/index.tsx index 6de5550890..3047e1709f 100644 --- a/src/pages/MyEarnings/ClassicPools/SinglePool/index.tsx +++ b/src/pages/MyEarnings/ClassicPools/SinglePool/index.tsx @@ -31,7 +31,7 @@ import { TokenAddressMap } from 'state/lists/reducer' import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' import { isAddress, shortenAddress } from 'utils' import { currencyId } from 'utils/currencyId' -import { formatDollarAmount } from 'utils/numbers' +import { formatDisplayNumber } from 'utils/numbers' import { getTokenSymbolWithHardcode } from 'utils/tokenInfo' import { unwrappedToken } from 'utils/wrappedCurrency' @@ -126,9 +126,13 @@ const SinglePool: React.FC = ({ poolEarning, chainId }) => { ) const myLiquidityBalance = poolEarning.liquidityTokenBalanceIncludingStake !== '0' && poolEarning.pool.totalSupply !== '0' - ? formatDollarAmount( + ? formatDisplayNumber( (+poolEarning.liquidityTokenBalanceIncludingStake * +poolEarning.pool.reserveUSD) / +poolEarning.pool.totalSupply, + { + style: 'currency', + significantDigits: 4, + }, ) : '--' @@ -262,7 +266,13 @@ const SinglePool: React.FC = ({ poolEarning, chainId }) => { - + = ({ poolEarning, chainId }) => { value={ - {(+poolEarning.pool.apr).toFixed(2)}% + {formatDisplayNumber((+poolEarning.pool.apr + +poolEarning.pool.farmApr) / 100, { + style: 'percent', + fractionDigits: 2, + })} = ({ poolEarning, chainId }) => { /> - + @@ -451,15 +474,23 @@ const SinglePool: React.FC = ({ poolEarning, chainId }) => {
- {formatDollarAmount(ampLiquidity)} + + {formatDisplayNumber(ampLiquidity, { + style: 'currency', + significantDigits: 7, + })} + - {formatDollarAmount(+poolEarning.pool.reserveUSD)} + {formatDisplayNumber(poolEarning.pool.reserveUSD, { style: 'currency', significantDigits: 7 })}
- {(+poolEarning.pool.apr + +poolEarning.pool.farmApr).toFixed(2)}% + {formatDisplayNumber((+poolEarning.pool.apr + +poolEarning.pool.farmApr) / 100, { + style: 'percent', + fractionDigits: 2, + })} = ({ poolEarning, chainId }) => { - {formatDollarAmount(Number(poolEarning.pool.volumeUsd) - Number(poolEarning.pool.volumeUsdOneDayAgo))} + {formatDisplayNumber(Number(poolEarning.pool.volumeUsd) - Number(poolEarning.pool.volumeUsdOneDayAgo), { + style: 'currency', + significantDigits: 4, + })} + + + {formatDisplayNumber(Number(poolEarning.pool.feeUSD) - Number(poolEarning.pool.feesUsdOneDayAgo), { + style: 'currency', + significantDigits: 4, + })} - {formatDollarAmount(Number(poolEarning.pool.feeUSD) - Number(poolEarning.pool.feesUsdOneDayAgo))} {myLiquidityBalance} - {formatDollarAmount(poolEarningToday)} + {formatDisplayNumber(poolEarningToday, { style: 'currency', significantDigits: 4 })} (({ $columns }) => ({ @@ -141,7 +141,7 @@ const EarningsBreakdownPanel: React.FC = ({ isLoading, data, className, h ? tokens[item.chainId]?.[item.address]?.symbol || '' : item.symbol, }))} - totalValue={formatUSDValue(data.totalValue, true)} + totalValue={formatDisplayNumber(data.totalValue, { style: 'currency', significantDigits: 3 })} /> )} diff --git a/src/pages/MyEarnings/ElasticPools/SinglePool/index.tsx b/src/pages/MyEarnings/ElasticPools/SinglePool/index.tsx index 4870eea577..c05561cdc3 100644 --- a/src/pages/MyEarnings/ElasticPools/SinglePool/index.tsx +++ b/src/pages/MyEarnings/ElasticPools/SinglePool/index.tsx @@ -29,7 +29,7 @@ import { Badge, DownIcon, MobileStat, MobileStatWrapper, Row, Wrapper } from 'pa import { ButtonIcon } from 'pages/Pools/styleds' import { useAppSelector } from 'state/hooks' import { isAddress, shortenAddress } from 'utils' -import { formatDollarAmount } from 'utils/numbers' +import { formatDisplayNumber } from 'utils/numbers' import { getTokenSymbolWithHardcode } from 'utils/tokenInfo' import { unwrappedToken } from 'utils/wrappedCurrency' @@ -271,7 +271,14 @@ const SinglePool: React.FC = ({ poolEarning, chainId, positionEarnings, p - + = ({ poolEarning, chainId, positionEarnings, p } > - {(poolAPR + farmAPR).toFixed(2)}% + {formatDisplayNumber((poolAPR + farmAPR) / 100, { style: 'percent', fractionDigits: 2 })} @@ -304,14 +311,29 @@ const SinglePool: React.FC = ({ poolEarning, chainId, positionEarnings, p /> + + - - @@ -409,7 +431,13 @@ const SinglePool: React.FC = ({ poolEarning, chainId, positionEarnings, p {share} - {formatDollarAmount(+poolEarning.totalValueLockedUsd)} + + {formatDisplayNumber(poolEarning.totalValueLockedUsd, { + style: 'currency', + significantDigits: 7, + fractionDigits: 4, + })} + = ({ poolEarning, chainId, positionEarnings, p } > - {(poolAPR + farmAPR).toFixed(2)}% + {formatDisplayNumber((poolAPR + farmAPR) / 100, { style: 'percent', fractionDigits: 2 })} - {formatDollarAmount(Number(poolEarning.volumeUsd) - Number(poolEarning.volumeUsdOneDayAgo))} - {formatDollarAmount(Number(poolEarning.feesUsd) - Number(poolEarning.feesUsdOneDayAgo))} - {formatDollarAmount(myLiquidityUsd)} - {formatDollarAmount(poolEarningToday)} + + {formatDisplayNumber(Number(poolEarning.volumeUsd) - Number(poolEarning.volumeUsdOneDayAgo), { + style: 'currency', + significantDigits: 4, + })} + + + {formatDisplayNumber(Number(poolEarning.feesUsd) - Number(poolEarning.feesUsdOneDayAgo), { + style: 'currency', + significantDigits: 4, + })} + + {formatDisplayNumber(myLiquidityUsd, { style: 'currency', significantDigits: 4 })} + {formatDisplayNumber(poolEarningToday, { style: 'currency', significantDigits: 4 })} = props => { {earningToday ? formatUSDValue(earningToday.totalValue, false) : '--'}} + anchor={ + {formatDisplayNumber(earningToday?.totalValue, { style: 'currency', significantDigits: 6 })} + } text={ <> {earningToday?.tokens.map((token, index) => ( @@ -74,8 +75,8 @@ const EarningView: React.FC = props => { }} > - - {formattedNum(token.amount, false)} {token.symbol} + + {formatDisplayNumber(token.amount, { significantDigits: 6 })} {token.symbol} ))} @@ -95,8 +96,8 @@ const EarningView: React.FC = props => { - {myPoolAPR ? myPoolAPR.toFixed(2) + '%' : '--'} - {myFarmAPR ? myFarmAPR.toFixed(2) + '%' : '--'} + {formatDisplayNumber(myPoolAPR / 100, { style: 'percent', fractionDigits: 2 })} + {formatDisplayNumber(myFarmAPR / 100, { style: 'percent', fractionDigits: 2 })} diff --git a/src/pages/MyEarnings/ElasticPools/SinglePosition/PositionView.tsx b/src/pages/MyEarnings/ElasticPools/SinglePosition/PositionView.tsx index 87d0b21586..b51b52c3e7 100644 --- a/src/pages/MyEarnings/ElasticPools/SinglePosition/PositionView.tsx +++ b/src/pages/MyEarnings/ElasticPools/SinglePosition/PositionView.tsx @@ -34,7 +34,7 @@ import { useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE } from 'state/transactions/type' import { updateChainId } from 'state/user/actions' import { calculateGasMargin } from 'utils' -import { formatDollarAmount } from 'utils/numbers' +import { formatDisplayNumber } from 'utils/numbers' import ActionButtons from './ActionButtons' @@ -199,7 +199,7 @@ const PositionView: React.FC = props => { {formatDollarAmount(liquidityInUsd)}} + anchor={{formatDisplayNumber(liquidityInUsd, { style: 'currency', significantDigits: 6 })}} disabled={!liquidityInUsd || Number.isNaN(liquidityInUsd)} text={
@@ -221,7 +221,9 @@ const PositionView: React.FC = props => { {myStakedBalance ? ( {formatDollarAmount(myStakedBalance)}} + anchor={ + {formatDisplayNumber(myStakedBalance, { style: 'currency', significantDigits: 6 })} + } text={
@@ -273,7 +275,9 @@ const PositionView: React.FC = props => { - {+positionEarning.pendingRewardUSD ? formatDollarAmount(+positionEarning.pendingRewardUSD) : '--'} + {+positionEarning.pendingRewardUSD + ? formatDisplayNumber(positionEarning.pendingRewardUSD, { style: 'currency', significantDigits: 6 }) + : '--'} } disabled={!+positionEarning.pendingRewardUSD} diff --git a/src/pages/MyEarnings/HoverDropdown.tsx b/src/pages/MyEarnings/HoverDropdown.tsx index 86d6353014..ff5b003ae5 100644 --- a/src/pages/MyEarnings/HoverDropdown.tsx +++ b/src/pages/MyEarnings/HoverDropdown.tsx @@ -26,7 +26,7 @@ type Props = { } const HoverDropdown: React.FC = ({ anchor, text, disabled = false }) => { return ( - + {anchor} {!disabled && } diff --git a/src/pages/MyEarnings/PoolEarningsSection.tsx b/src/pages/MyEarnings/PoolEarningsSection.tsx index c508398d40..c2f1d3d60e 100644 --- a/src/pages/MyEarnings/PoolEarningsSection.tsx +++ b/src/pages/MyEarnings/PoolEarningsSection.tsx @@ -16,6 +16,7 @@ import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' import { MEDIA_WIDTHS } from 'theme' import { EarningStatsTick, EarningsBreakdown } from 'types/myEarnings' import { isAddressString } from 'utils' +import { toFixed } from 'utils/numbers' import OriginalEarningsBreakdownPanel from './EarningsBreakdownPanel' import OriginalMyEarningsOverTimePanel from './MyEarningsOverTimePanel' @@ -150,19 +151,19 @@ const PoolEarningsSection: React.FC = ({ historicalEarning, chainId }) => ? latestData.map(data => ({ logoUrl: data.logoUrl, symbol: data.symbol, - value: String(data.amountUSD), + value: toFixed(data.amountUSD), percent: isAllZero ? (1 / visibleItems) * 100 : (data.amountUSD / totalValue) * 100, })) : [ ...latestData.slice(0, 9).map(data => ({ logoUrl: data.logoUrl, symbol: data.symbol, - value: String(data.amountUSD), + value: toFixed(data.amountUSD), percent: isAllZero ? 10 : (data.amountUSD / totalValue) * 100, })), { symbol: t`Others`, - value: String(totalValueOfOthers), + value: toFixed(totalValueOfOthers), percent: isAllZero ? 10 : (totalValueOfOthers / totalValue) * 100, }, ] diff --git a/src/pages/MyEarnings/ShareModal.tsx b/src/pages/MyEarnings/ShareModal.tsx index bbd2b02b1c..426565de64 100644 --- a/src/pages/MyEarnings/ShareModal.tsx +++ b/src/pages/MyEarnings/ShareModal.tsx @@ -27,18 +27,7 @@ import useShareImage from 'hooks/useShareImage' import useTheme from 'hooks/useTheme' import { ButtonText, MEDIA_WIDTHS } from 'theme' import { downloadImage } from 'utils' - -const formatValue = (num: number, isSharePc: boolean) => { - const notation = (num > 1_000_000 && !isSharePc) || (num > 100_000_000 && isSharePc) ? 'compact' : 'standard' - const formatter = new Intl.NumberFormat('en-US', { - notation, - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 2, - }) - return formatter.format(num) -} +import { formatDisplayNumber } from 'utils/numbers' const ButtonWrapper = styled.div` text-align: center; @@ -292,7 +281,7 @@ export default function ShareModal({ isOpen, setIsOpen, title, value, poolInfo } {renderPool()} - {formatValue(value, isSharePc)} + {formatDisplayNumber(value, { style: 'currency', fractionDigits: 2 })} diff --git a/src/pages/MyEarnings/TotalEarningsAndChainSelect.tsx b/src/pages/MyEarnings/TotalEarningsAndChainSelect.tsx index 5aeb85ed0b..764c1cee8d 100644 --- a/src/pages/MyEarnings/TotalEarningsAndChainSelect.tsx +++ b/src/pages/MyEarnings/TotalEarningsAndChainSelect.tsx @@ -11,7 +11,6 @@ import earningApi, { import styled, { keyframes } from 'styled-components' import { ReactComponent as RefreshIcon } from 'assets/svg/refresh.svg' -import { formatUSDValue } from 'components/EarningAreaChart/utils' import { MouseoverTooltip } from 'components/Tooltip' import { EMPTY_FUNCTION } from 'constants/index' import { @@ -23,18 +22,7 @@ import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' import useTheme from 'hooks/useTheme' import ShareTotalEarningsButton from 'pages/MyEarnings/ShareTotalEarningsButton' import { useAppSelector } from 'state/hooks' - -// TODO: move to common -const formatPercent = (value: number) => { - const formatter = Intl.NumberFormat('en-US', { - notation: 'standard', - style: 'percent', - minimumFractionDigits: 0, - maximumFractionDigits: 2, - }) - - return formatter.format(value) -} +import { formatDisplayNumber } from 'utils/numbers' const Value = styled.span` max-width: 100%; @@ -148,11 +136,15 @@ const TotalEarningsAndChainSelect: React.FC = ({ totalEarningToday, total return -- } - const totalValue = formatUSDValue(totalEarningToday) - + const totalValue = formatDisplayNumber(totalEarningToday, { style: 'currency', significantDigits: 6 }) const diffPercent = totalEarningYesterday && !Number.isNaN(totalEarningYesterday) - ? formatPercent(totalEarningToday / totalEarningYesterday - 1) + ? formatDisplayNumber(totalEarningToday / totalEarningYesterday - 1, { + style: 'percent', + fractionDigits: 2, + significantDigits: 6, + allowNegative: true, + }) : '' return ( diff --git a/src/utils/fee.ts b/src/utils/fee.ts index 8a2d798a00..daba1d412a 100644 --- a/src/utils/fee.ts +++ b/src/utils/fee.ts @@ -5,7 +5,8 @@ import { BuildRouteData } from 'services/route/types/buildRoute' import { BIPS_BASE, RESERVE_USD_DECIMALS } from 'constants/index' import { ChargeFeeBy, DetailedRouteSummary } from 'types/route' -import { formattedNum } from 'utils/index' + +import { formatDisplayNumber } from './numbers' export const calculateFeeFromBuildData = ( routeSummary: DetailedRouteSummary | undefined, @@ -39,8 +40,9 @@ export const calculateFeeFromBuildData = ( const feeUsd = buildData.feeUsd return { - feeAmount: formattedNum(fee, false), - feeAmountUsd: feeUsd && feeUsd !== '0' ? formattedNum(feeUsd, true, 4) : '', + feeAmount: formatDisplayNumber(fee, { significantDigits: 10 }), + feeAmountUsd: + feeUsd && feeUsd !== '0' ? formatDisplayNumber(feeUsd, { style: 'currency', significantDigits: 10 }) : '', currency: currencyAmountToTakeFee.currency, } } diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index c2ccc42827..d9757bc92e 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -88,7 +88,6 @@ function subscribeListLimitOrder( result.orders.push({ ...e, id: Number(e.id) } as LimitOrder) } }) - console.log(result) callback(result) }, ) diff --git a/src/utils/formatCurrencyAmount.tsx b/src/utils/formatCurrencyAmount.tsx index 505dc7a5ef..352a304226 100644 --- a/src/utils/formatCurrencyAmount.tsx +++ b/src/utils/formatCurrencyAmount.tsx @@ -3,6 +3,7 @@ import JSBI from 'jsbi' import { MouseoverTooltip } from 'components/Tooltip' +// todo: deprecated, use formatDisplayNumber instead export function formatCurrencyAmount(amount: CurrencyAmount | undefined, sigFigs: number) { if (!amount) { return '-' @@ -19,6 +20,7 @@ export function formatCurrencyAmount(amount: CurrencyAmount | undefine return amount.toSignificant(sigFigs) } +// todo: deprecated, use formatDisplayNumber instead export function toSignificantOrMaxIntegerPart(price: Price | undefined, sigFigs: number): string { if (!price) return '' @@ -28,6 +30,7 @@ export function toSignificantOrMaxIntegerPart(price: Price | return price.toSignificant(sigFigs) } +// todo: deprecated, use formatDisplayNumber instead export function formatPrice(price: Price | undefined, sigFigs: number) { if (!price) { return '-' diff --git a/src/utils/formatTickPrice.ts b/src/utils/formatTickPrice.ts index 1f2ebe62d2..fcd6fa47c9 100644 --- a/src/utils/formatTickPrice.ts +++ b/src/utils/formatTickPrice.ts @@ -2,7 +2,7 @@ import { Currency, Price } from '@kyberswap/ks-sdk-core' import { Bound } from 'state/mint/proamm/type' -import { formatPrice } from './formatCurrencyAmount' +import { formatDisplayNumber } from './numbers' export function formatTickPrice( price: Price | undefined, @@ -17,5 +17,5 @@ export function formatTickPrice( if (!price && placeholder !== undefined) { return placeholder } - return formatPrice(price, 5) + return formatDisplayNumber(price, { significantDigits: 6 }) } diff --git a/src/utils/index.ts b/src/utils/index.ts index dc0a7a8e42..81a45127d0 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -153,6 +153,7 @@ const formatDollarSignificantAmount = (num: number, minDigits: number, maxDigits return formatter.format(num) } +// todo: deprecated, use formatDisplayNumber instead export function formatNumberWithPrecisionRange(number: number, minPrecision = 2, maxPrecision = 2) { const options = { minimumFractionDigits: minPrecision, @@ -175,6 +176,7 @@ const truncateFloatNumber = (num: number, maximumFractionDigits = 6) => { return `${wholePart}.${fractionalPart.slice(0, maximumFractionDigits)}` } +// todo: deprecated, use formatDisplayNumber instead export function formattedNum(number: string | number, usd = false, fractionDigits = 5): string { if (number === 0 || number === '' || number === undefined) { return usd ? '$0' : '0' @@ -216,6 +218,7 @@ export function formattedNum(number: string | number, usd = false, fractionDigit return truncateFloatNumber(num, fractionDigits) } +// todo: deprecated, use formatDisplayNumber instead export function formattedNumLong(num: number, usd = false) { if (num === 0) { if (usd) { diff --git a/src/utils/numbers.ts b/src/utils/numbers.ts index 4ee69ea07a..69323955e8 100644 --- a/src/utils/numbers.ts +++ b/src/utils/numbers.ts @@ -1,9 +1,9 @@ -import { Fraction } from '@kyberswap/ks-sdk-core' +import { CurrencyAmount, Fraction, Percent, Price } from '@kyberswap/ks-sdk-core' import JSBI from 'jsbi' -import { RESERVE_USD_DECIMALS } from 'constants/index' +import { BIG_INT_ONE, BIG_INT_ZERO, RESERVE_USD_DECIMALS } from 'constants/index' -// using a currency library here in case we want to add more in future +// todo: deprecated, use formatDisplayNumber instead export const formatDollarAmount = (num: number | undefined, digits = 2) => { if (num === 0) return '$0.00' if (!num) return '-' @@ -22,7 +22,7 @@ export const formatDollarAmount = (num: number | undefined, digits = 2) => { .toLowerCase() } -// do the same with above, without the $ sign +// todo: deprecated, use formatDisplayNumber instead export const formatNotDollarAmount = (num: number | undefined, digits = 2) => { if (num === 0) return '0.00' if (!num) return '-' @@ -39,13 +39,16 @@ export const formatNotDollarAmount = (num: number | undefined, digits = 2) => { .toLowerCase() } +// stringify number without scientific format +// e.g: (123456789123456789123456789).toString() => 1.2345678912345679e+26 +// toFixed(123456789123456789123456789) => 123456789123456800000000000 // https://stackoverflow.com/a/1685917/8153505 export function toFixed(x: number): string { if (Math.abs(x) < 1.0) { const e = parseInt(x.toString().split('e-')[1]) if (e) { x *= Math.pow(10, e - 1) - return '0.' + '0'.repeat(e - 1) + x.toString().substring(2) + return x.toString().split('.')[0] + '.' + '0'.repeat(e - 1) + x.toString().split('.')[1] } } else { let e = parseInt(x.toString().split('+')[1]) @@ -60,3 +63,161 @@ export function toFixed(x: number): string { export const uint256ToFraction = (value: string, decimals = RESERVE_USD_DECIMALS) => new Fraction(value, JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(decimals))) + +const subscriptMap: { [key: string]: string } = { + '0': '₀', + '1': '₁', + '2': '₂', + '3': '₃', + '4': '₄', + '5': '₅', + '6': '₆', + '7': '₇', + '8': '₈', + '9': '₉', +} + +const log10 = (n: Fraction): number => { + const parsedN = Number(n.toSignificant(30)) + return Math.log10(parsedN) +} + +const parseNum = (value: FormatValue): Fraction => { + try { + if ( + typeof value === 'string' || + typeof value === 'number' || + value instanceof CurrencyAmount || + value instanceof Percent || + value instanceof Price + ) { + const valueStr = (() => { + if (typeof value === 'string') return value + if (typeof value === 'number') return toFixed(value) + if (value instanceof CurrencyAmount) return value.toFixed(value.currency.decimals) + if (value instanceof Price) return value.toFixed(18) + if (value instanceof Percent) return value.divide(100).toFixed(18) + return '0' + })() + return new Fraction(valueStr.replace('.', ''), '1' + '0'.repeat(valueStr.split('.')[1]?.length || 0)) + } + if (value instanceof Fraction) return value + if (value instanceof JSBI) return new Fraction(value) + if (typeof value === 'bigint') return new Fraction(value.toString(10)) + return new Fraction(0, 1) + } catch (error) { + console.error('parseNum error', { value, 'typeof value': typeof value, error }) + return new Fraction(0, 1) + } +} + +type FormatValue = string | number | bigint | JSBI | Fraction | undefined | null +type FormatOptions = { + style?: 'decimal' | 'currency' | 'percent' + fractionDigits?: number // usually for percent & currency styles + significantDigits?: number // usually for decimal style + fallback?: string + allowNegative?: boolean +} +interface RequiredFraction extends FormatOptions { + fractionDigits: number // usually for percent & currency styles +} +interface RequiredSignificant extends FormatOptions { + significantDigits: number // usually for percent & currency styles +} + +// todo: deprecated others format functions and all .toSignificant() to only use this function +/** + * Format number to displaying to the UI + * @example + * // returns 0.2 + * formatDisplayNumber(0.2, { style: 'decimal', significantDigits: 6 }) + * @example + * // returns $0.2 + * formatDisplayNumber(0.2, { style: 'currency', significantDigits: 6 }) + * @example + * // returns 20% + * formatDisplayNumber(0.2, { style: 'percent', significantDigits: 6 }) + * @example + * @returns {string} Returns the formatted number in string + */ +export const formatDisplayNumber = ( + value: FormatValue, + { + style = 'decimal', + significantDigits, + fractionDigits, + fallback = '--', + allowNegative = false, + }: RequiredFraction | RequiredSignificant, +): string => { + const currency = style === 'currency' ? '$' : '' + const percent = style === 'percent' ? '%' : '' + const fallbackResult = `${currency}${fallback}${percent}` + + if (value === undefined || value === null || Number.isNaN(value)) return fallbackResult + const parsedFraction = parseNum(value) + if (!allowNegative && parsedFraction.lessThan(BIG_INT_ZERO)) return fallbackResult + + const shownFraction = style === 'percent' ? parsedFraction.multiply(100) : parsedFraction + const absShownFraction = shownFraction.lessThan(0) ? shownFraction.multiply(-1) : shownFraction + + if (absShownFraction.lessThan(BIG_INT_ONE) && !shownFraction.equalTo(BIG_INT_ZERO)) { + const decimal = shownFraction.toSignificant(Math.max(30, significantDigits || 0, fractionDigits || 0)).split('.')[1] + const negative = shownFraction.lessThan(BIG_INT_ZERO) ? '-' : '' + const numberOfLeadingZeros = -Math.floor(log10(absShownFraction) + 1) + const slicedDecimal = decimal + .replace(/^0+/, '') + .slice(0, fractionDigits) + .slice(0, significantDigits || 6) + .replace(/0+$/, '') + + if (numberOfLeadingZeros > 2) { + const subscripts = numberOfLeadingZeros + .toString() + .split('') + .map(item => subscriptMap[item]) + .join('') + return `${negative}${currency}0.0${subscripts}${slicedDecimal}${percent}` + } + + return `${negative}${currency}0${ + slicedDecimal.length ? '.' + '0'.repeat(numberOfLeadingZeros) + slicedDecimal : '' + }${percent}` + } + + const formatter = Intl.NumberFormat('en-US', { + notation: absShownFraction.greaterThan(10 ** (significantDigits || fractionDigits || 4)) ? 'compact' : 'standard', + style, + currency: 'USD', + minimumFractionDigits: fractionDigits ? 0 : undefined, + maximumFractionDigits: fractionDigits, + minimumSignificantDigits: significantDigits ? 1 : undefined, + maximumSignificantDigits: significantDigits, + }) + + const result = formatter.format( + Number(parsedFraction.toSignificant(Math.max(30, significantDigits || 0, fractionDigits || 0))), + ) + + // Intl.NumberFormat does not handle maximumFractionDigits well when used along with maximumSignificantDigits + // It might return number with longer fraction digits than maximumFractionDigits + // Hence, we have to do an additional step that manually slice those oversize fraction digits + if (fractionDigits !== undefined) { + const [negative, currency, integer, decimal, unit] = parseNumPart(result) + const trimedSlicedDecimal = decimal?.slice(0, fractionDigits).replace(/0+$/, '') + if (trimedSlicedDecimal) return negative + currency + integer + '.' + trimedSlicedDecimal + unit + return negative + currency + integer + unit + } + return result +} + +const regex = /^(-\s*)?(\$\s*)?([\d,]+)(\.\d+)?\s*?(\w?.*?)$/ +const parseNumPart = (str: string): string[] => { + const parsedResult = regex.exec(str) + if (parsedResult) { + const [, negative, currency, integer, decimal, unit] = parsedResult + return [negative?.trim() || '', currency?.trim() || '', integer, decimal?.slice(1) || '', unit?.trim() || ''] + } + return ['', '', '', '', ''] +} diff --git a/yarn.lock b/yarn.lock index 1248657aaf..4ed7afb166 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1965,16 +1965,6 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/types@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" - integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - "@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" @@ -4661,14 +4651,6 @@ dependencies: "@types/istanbul-lib-coverage" "*" -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - "@types/istanbul-reports@^3.0.0": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" @@ -4676,14 +4658,6 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^25.2.1": - version "25.2.3" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.2.3.tgz#33d27e4c4716caae4eced355097a47ad363fdcaf" - integrity sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw== - dependencies: - jest-diff "^25.2.1" - pretty-format "^25.2.1" - "@types/js-cookie@2.2.6": version "2.2.6" resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.6.tgz#f1a1cb35aff47bc5cfb05cb0c441ca91e914c26f" @@ -7184,14 +7158,6 @@ chalk@5.2.0, chalk@^5.0.0, chalk@^5.0.1, chalk@^5.2.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chance@^1.1.4: version "1.1.11" resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.11.tgz#78e10e1f9220a5bbc60a83e3f28a5d8558d84d1b" @@ -8759,11 +8725,6 @@ detect-node@2.1.0, detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== -diff-sequences@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" - integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== - diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -11928,21 +11889,6 @@ jayson@^4.1.0: uuid "^8.3.2" ws "^7.4.5" -jest-diff@^25.2.1: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" - integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== - dependencies: - chalk "^3.0.0" - diff-sequences "^25.2.6" - jest-get-type "^25.2.6" - pretty-format "^25.5.0" - -jest-get-type@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" - integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== - jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" @@ -14224,16 +14170,6 @@ pretty-error@^4.0.0: lodash "^4.17.20" renderkid "^3.0.0" -pretty-format@^25.2.1, pretty-format@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" - integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== - dependencies: - "@jest/types" "^25.5.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" - pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" @@ -14785,7 +14721,7 @@ react-is@16.10.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.2.tgz#984120fd4d16800e9a738208ab1fba422d23b5ab" integrity sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA== -react-is@^16.10.2, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0: +react-is@^16.10.2, react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -16882,9 +16818,9 @@ ts-node@^10.8.1, ts-node@^10.9.1: yn "3.1.1" tsconfck@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-2.1.1.tgz#9b51603d2712d1f4740fa14748ca886a2e1893e5" - integrity sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww== + version "2.1.2" + resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-2.1.2.tgz#f667035874fa41d908c1fe4d765345fcb1df6e35" + integrity sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg== tslib@1.14.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" @@ -17414,9 +17350,9 @@ vite-plugin-svgr@^2.4.0: "@svgr/core" "^6.5.1" vite-tsconfig-paths@^4.0.8: - version "4.2.0" - resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.0.tgz#bd2647d3eadafb65a10fc98a2ca565211f2eaf63" - integrity sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw== + version "4.2.1" + resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.1.tgz#e53b89096b91d31a6d1e26f75999ea8c336a89ed" + integrity sha512-GNUI6ZgPqT3oervkvzU+qtys83+75N/OuDaQl7HmOqFTb0pjZsuARrRipsyJhJ3enqV8beI1xhGbToR4o78nSQ== dependencies: debug "^4.1.1" globrex "^0.1.2" From a4e4dce9eaeb2ba6957c254f8da06340092edfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Ho=C3=A0i=20Danh?= <33005392+nguyenhoaidanh@users.noreply.github.com> Date: Thu, 14 Sep 2023 09:38:37 +0700 Subject: [PATCH 02/13] feat: use chains from config (#2231) --- .../Header/web3/NetworkModal/Networks.tsx | 45 ++++++++++++++++--- src/constants/networks/type.ts | 2 + src/hooks/useChainsConfig.ts | 42 +++++++++++++++++ src/hooks/useKyberSwapConfig.ts | 3 ++ src/pages/About/AboutKyberSwap/index.tsx | 18 ++++---- .../MultipleChainSelect/PopoverBody.tsx | 6 ++- src/services/ksSetting.ts | 17 +++++++ src/state/lists/updater.ts | 3 +- 8 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 src/hooks/useChainsConfig.ts diff --git a/src/components/Header/web3/NetworkModal/Networks.tsx b/src/components/Header/web3/NetworkModal/Networks.tsx index 1d549d3239..e7125ff432 100644 --- a/src/components/Header/web3/NetworkModal/Networks.tsx +++ b/src/components/Header/web3/NetworkModal/Networks.tsx @@ -1,4 +1,5 @@ import { ChainId, getChainType } from '@kyberswap/ks-sdk-core' +import { Trans, t } from '@lingui/macro' import { darken, rgba } from 'polished' import { stringify } from 'querystring' import React from 'react' @@ -8,15 +9,30 @@ import styled, { css } from 'styled-components' import { ButtonEmpty } from 'components/Button' import { MouseoverTooltip } from 'components/Tooltip' -import { MAINNET_NETWORKS, NETWORKS_INFO } from 'constants/networks' +import { NetworkInfo } from 'constants/networks/type' import { Z_INDEXS } from 'constants/styles' import { SUPPORTED_WALLETS } from 'constants/wallets' import { useActiveWeb3React } from 'hooks' +import useChainsConfig, { ChainState } from 'hooks/useChainsConfig' import useParsedQueryString from 'hooks/useParsedQueryString' import useTheme from 'hooks/useTheme' import { useChangeNetwork } from 'hooks/web3/useChangeNetwork' import { useIsDarkMode } from 'state/user/hooks' +const NewLabel = styled.span` + font-size: 12px; + color: ${({ theme }) => theme.red}; + margin-left: 2px; + margin-top: -10px; +` + +const MaintainLabel = styled.span` + font-size: 8px; + color: ${({ theme }) => theme.red}; + margin-left: 2px; + margin-top: -10px; +` + const ListItem = styled.div<{ selected?: boolean }>` width: 100%; display: flex; @@ -157,11 +173,14 @@ const Networks = ({ } } + const { supportedChains } = useChainsConfig() + return ( - {MAINNET_NETWORKS.map((itemChainId: ChainId, i: number) => { - const { iconDark, icon, name } = NETWORKS_INFO[itemChainId] - const disabled = !isAcceptedTerm || (activeChainIds ? !activeChainIds?.includes(itemChainId) : false) + {supportedChains.map(({ chainId: itemChainId, iconDark, icon, name, state }: NetworkInfo, i: number) => { + const isMaintenance = state === ChainState.MAINTENANCE + const disabled = + !isAcceptedTerm || (activeChainIds ? !activeChainIds?.includes(itemChainId) : false) || isMaintenance const selected = selectedId === itemChainId && !isWrongNetwork const imgSrc = (isDarkMode ? iconDark : icon) || icon @@ -175,7 +194,13 @@ const Networks = ({ + {state === ChainState.NEW && ( + + New + + )} + {isMaintenance && ( + + Maintainance + + )} {selected && !walletKey && } {walletKey && ( diff --git a/src/constants/networks/type.ts b/src/constants/networks/type.ts index 31dcc6a44a..7862039b90 100644 --- a/src/constants/networks/type.ts +++ b/src/constants/networks/type.ts @@ -2,6 +2,7 @@ import { ChainId } from '@kyberswap/ks-sdk-core' import { PublicKey } from '@solana/web3.js' import { EnvKeys } from 'constants/env' +import { ChainState } from 'hooks/useChainsConfig' export interface NetworkInfo { readonly chainId: ChainId @@ -37,6 +38,7 @@ export interface NetworkInfo { // USDT: Token // } readonly geckoTermialId: string | null + readonly state?: ChainState } export interface EVMNetworkInfo extends NetworkInfo { diff --git a/src/hooks/useChainsConfig.ts b/src/hooks/useChainsConfig.ts new file mode 100644 index 0000000000..2cffb5e7bd --- /dev/null +++ b/src/hooks/useChainsConfig.ts @@ -0,0 +1,42 @@ +import { ChainId } from '@kyberswap/ks-sdk-core' +import { useMemo } from 'react' +import { useGetChainsConfigurationQuery } from 'services/ksSetting' + +import { MAINNET_NETWORKS, NETWORKS_INFO } from 'constants/networks' +import { NetworkInfo } from 'constants/networks/type' +import { useKyberswapGlobalConfig } from 'hooks/useKyberSwapConfig' + +export enum ChainState { + NEW = 'new', + ACTIVE = 'active', + INACTIVE = 'inactive', + MAINTENANCE = 'maintainain', +} + +export type ChainStateMap = { [chain in ChainId]: ChainState } + +const defaultData = MAINNET_NETWORKS.map(chainId => NETWORKS_INFO[chainId]) +export default function useChainsConfig() { + const { data } = useGetChainsConfigurationQuery() + const globalConfig = useKyberswapGlobalConfig() + + return useMemo(() => { + const hasConfig = !!data + const chains: NetworkInfo[] = (data || defaultData).map(chain => { + const chainId = +chain.chainId as ChainId + const chainState = hasConfig ? globalConfig?.chainStates?.[chainId] : ChainState.ACTIVE + return { + ...NETWORKS_INFO[chainId], + ...chain, // BE config + chainId, + state: chainState, + } + }) + return { + activeChains: chains.filter(e => [ChainState.ACTIVE, ChainState.NEW].includes(e.state)), + supportedChains: chains.filter(e => + [ChainState.ACTIVE, ChainState.NEW, ChainState.MAINTENANCE].includes(e.state), + ), + } + }, [data, globalConfig]) +} diff --git a/src/hooks/useKyberSwapConfig.ts b/src/hooks/useKyberSwapConfig.ts index e49c31df91..24501dfb8a 100644 --- a/src/hooks/useKyberSwapConfig.ts +++ b/src/hooks/useKyberSwapConfig.ts @@ -16,6 +16,7 @@ import { NETWORKS_INFO, SUPPORTED_NETWORKS, isEVM, isSolana } from 'constants/ne import ethereumInfo from 'constants/networks/ethereum' import solanaInfo from 'constants/networks/solana' import { AppJsonRpcProvider } from 'constants/providers' +import { ChainStateMap } from 'hooks/useChainsConfig' import { AppState } from 'state' import { createClient } from 'utils/client' @@ -58,6 +59,7 @@ type KyberswapGlobalConfig = { aggregatorDomain: string aggregatorAPI: string isEnableAuthenAggregator: boolean + chainStates: ChainStateMap } const parseGlobalResponse = ( @@ -68,6 +70,7 @@ const parseGlobalResponse = ( const aggregatorDomain = data?.aggregator ?? AGGREGATOR_API const isEnableAuthenAggregator = !!data?.isEnableAuthenAggregator return { + chainStates: data?.chainStates || ({} as ChainStateMap), aggregatorDomain, aggregatorAPI: `${aggregatorDomain}/${NETWORKS_INFO[chainId].aggregatorRoute}/route/encode`, isEnableAuthenAggregator, diff --git a/src/pages/About/AboutKyberSwap/index.tsx b/src/pages/About/AboutKyberSwap/index.tsx index 520339d1a4..bdaeac143c 100644 --- a/src/pages/About/AboutKyberSwap/index.tsx +++ b/src/pages/About/AboutKyberSwap/index.tsx @@ -49,9 +49,10 @@ import AntiSnippingAttack from 'components/Icons/AntiSnippingAttack' import ZkSyncFull from 'components/Icons/ZkSyncFull' import Loader from 'components/Loader' import { APP_PATHS } from 'constants/index' -import { MAINNET_NETWORKS, NETWORKS_INFO } from 'constants/networks' +import { NETWORKS_INFO } from 'constants/networks' import { VERSION } from 'constants/v2' import { useActiveWeb3React } from 'hooks' +import useChainsConfig from 'hooks/useChainsConfig' import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' import useTheme from 'hooks/useTheme' import { useGlobalData } from 'state/about/hooks' @@ -121,6 +122,7 @@ const ForTraderInfoCell = styled.div` export const KSStatistic = () => { const theme = useTheme() const upToLarge = useMedia(`(max-width: ${MEDIA_WIDTHS.upToLarge}px)`) + const { supportedChains } = useChainsConfig() return ( @@ -153,7 +155,7 @@ export const KSStatistic = () => { - {MAINNET_NETWORKS.length}+ + {supportedChains.length}+ Chains @@ -475,6 +477,8 @@ function AboutKyberSwap() { ) } + const { supportedChains } = useChainsConfig() + return (
@@ -495,14 +499,10 @@ function AboutKyberSwap() { - {MAINNET_NETWORKS.map(chain => ( + {supportedChains.map(({ chainId: chain, iconDark, icon, name }) => ( {NETWORKS_INFO[chain].name} = ({ onClose }) => { const isLegacy = useAppSelector(state => state.myEarnings.activeTab === VERSION.ELASTIC_LEGACY) const isClassic = useAppSelector(state => state.myEarnings.activeTab === VERSION.CLASSIC) + const { activeChains } = useChainsConfig() const comingSoonList = isLegacy ? COMING_SOON_NETWORKS_FOR_MY_EARNINGS_LEGACY @@ -121,7 +123,9 @@ const PopoverBody: React.FC = ({ onClose }) => { const [localSelectedChains, setLocalSelectedChains] = useState(() => selectedChains) - const networkList = SUPPORTED_NETWORKS_FOR_MY_EARNINGS.filter(item => !comingSoonList.includes(item)) + const networkList = SUPPORTED_NETWORKS_FOR_MY_EARNINGS.filter( + item => !comingSoonList.includes(item) && activeChains.some(e => e.chainId === item), + ) const isAllSelected = localSelectedChains.length === networkList.length const handleChangeChains = (chains: ChainId[]) => { diff --git a/src/services/ksSetting.ts b/src/services/ksSetting.ts index 2b99fd8720..9a20c38b0d 100644 --- a/src/services/ksSetting.ts +++ b/src/services/ksSetting.ts @@ -5,6 +5,7 @@ import { Connection } from '@solana/web3.js' import { KS_SETTING_API } from 'constants/env' import { AppJsonRpcProvider } from 'constants/providers' +import { ChainStateMap } from 'hooks/useChainsConfig' import { TokenInfo } from 'state/lists/wrappedTokenInfo' import { TopToken } from 'state/topTokens/type' @@ -41,6 +42,7 @@ export type KyberswapGlobalConfigurationResponse = { config: { aggregator: string isEnableAuthenAggregator: boolean + chainStates: ChainStateMap } } } @@ -77,6 +79,20 @@ const ksSettingApi = createApi({ }, }), }), + getChainsConfiguration: builder.query<{ chainId: string; name: string; icon: string }[], void>({ + query: () => ({ + url: '/configurations/fetch', + params: { + serviceCode: `chains`, + }, + }), + transformResponse: (data: any) => + data?.data?.config?.map((e: any) => ({ + ...e, + name: e.displayName, + icon: e.logoUrl, + })), + }), getTokenList: builder.query< TokenListResponse, @@ -111,6 +127,7 @@ export const { useGetTokenListQuery, useImportTokenMutation, useLazyGetTopTokensQuery, + useGetChainsConfigurationQuery, } = ksSettingApi export default ksSettingApi diff --git a/src/state/lists/updater.ts b/src/state/lists/updater.ts index ec913e12c9..cae41c91d5 100644 --- a/src/state/lists/updater.ts +++ b/src/state/lists/updater.ts @@ -1,7 +1,7 @@ import { ChainId } from '@kyberswap/ks-sdk-core' import { useEffect } from 'react' import { useDispatch } from 'react-redux' -import { useLazyGetTokenListQuery } from 'services/ksSetting' +import { useGetChainsConfigurationQuery, useLazyGetTokenListQuery } from 'services/ksSetting' import { MAINNET_NETWORKS } from 'constants/networks' import { TokenMap, formatAndCacheToken } from 'hooks/Tokens' @@ -29,6 +29,7 @@ export default function Updater(): null { const dispatch = useDispatch() const [fetchTokenList] = useLazyGetTokenListQuery() + useGetChainsConfigurationQuery() useEffect(() => { const getTokens = async () => { From 72e35a9eec7711c8c167a79034fcb0ee9377df2a Mon Sep 17 00:00:00 2001 From: Nguyen Van Viet Date: Thu, 14 Sep 2023 10:09:02 +0700 Subject: [PATCH 03/13] feat: add cookie3 (#2208) * feat: add cookie3 * download lib file to local --- index.html | 396 +++-- public/libs/cookie3.js | 3403 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3599 insertions(+), 200 deletions(-) create mode 100644 public/libs/cookie3.js diff --git a/index.html b/index.html index 8a0ee5abac..ed49b2f07f 100644 --- a/index.html +++ b/index.html @@ -1,211 +1,206 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - KyberSwap - Trading Smart - - - - - - - -
- - - -
-
- -