From c6d975019be1c98d854f65b6ad46b5c0b5480e84 Mon Sep 17 00:00:00 2001 From: Nguyen Van Viet Date: Fri, 15 Dec 2023 18:50:00 +0700 Subject: [PATCH] feat: add liquidity snapshot (#2450) * feat: add liquidity snapshot * done * update tooltip * get route by clientId * update desc * update text * adjust ui * using github data * update text --- src/components/Header/groups/EarnNavGroup.tsx | 8 + src/components/SwapForm/hooks/useGetRoute.ts | 7 +- src/components/SwapForm/index.tsx | 4 +- src/constants/index.ts | 1 + src/pages/App.tsx | 4 + src/pages/ElasticSnapshot/index.tsx | 350 ++++++++++++++++++ src/utils/index.ts | 2 +- 7 files changed, 371 insertions(+), 5 deletions(-) create mode 100644 src/pages/ElasticSnapshot/index.tsx diff --git a/src/components/Header/groups/EarnNavGroup.tsx b/src/components/Header/groups/EarnNavGroup.tsx index 1eb95a3d59..d8f876efa4 100644 --- a/src/components/Header/groups/EarnNavGroup.tsx +++ b/src/components/Header/groups/EarnNavGroup.tsx @@ -1,4 +1,5 @@ import { Trans } from '@lingui/macro' +import { AlertOctagon } from 'react-feather' import { useLocation } from 'react-router-dom' import { useMedia } from 'react-use' import { Flex } from 'rebass' @@ -73,6 +74,13 @@ const EarnNavGroup = () => { My Pools + + + + + Snapshot + + } /> diff --git a/src/components/SwapForm/hooks/useGetRoute.ts b/src/components/SwapForm/hooks/useGetRoute.ts index f0d02e35ac..4f2df7eb36 100644 --- a/src/components/SwapForm/hooks/useGetRoute.ts +++ b/src/components/SwapForm/hooks/useGetRoute.ts @@ -24,6 +24,7 @@ export type ArgsGetRoute = { customChain?: ChainId isProcessingSwap?: boolean + clientId?: string } export const getRouteTokenAddressParam = (currency: Currency) => @@ -76,7 +77,7 @@ export const useRouteApiDomain = () => { const useGetRoute = (args: ArgsGetRoute) => { const { isEnableAuthenAggregator } = useKyberswapGlobalConfig() - const { isSaveGas, parsedAmount, currencyIn, currencyOut, customChain, isProcessingSwap } = args + const { isSaveGas, parsedAmount, currencyIn, currencyOut, customChain, isProcessingSwap, clientId } = args const { chainId: currentChain } = useActiveWeb3React() const chainId = customChain || currentChain @@ -119,7 +120,7 @@ const useGetRoute = (args: ArgsGetRoute) => { () => debounce( async (args: { url: string; params: GetRouteParams; authentication: boolean }) => { - await trigger(args) + await trigger({ ...args, clientId }) dismissSwapModalFlag.current = false }, INPUT_DEBOUNCE_TIME, @@ -127,7 +128,7 @@ const useGetRoute = (args: ArgsGetRoute) => { leading: true, }, ), - [trigger], + [trigger, clientId], ) const fetcher = useCallback(async () => { diff --git a/src/components/SwapForm/index.tsx b/src/components/SwapForm/index.tsx index ed850d81b5..664732879e 100644 --- a/src/components/SwapForm/index.tsx +++ b/src/components/SwapForm/index.tsx @@ -3,7 +3,7 @@ import { Trans } from '@lingui/macro' import { rgba } from 'polished' import { stringify } from 'querystring' import { useCallback, useEffect, useMemo, useState } from 'react' -import { useLocation, useNavigate } from 'react-router-dom' +import { useLocation, useNavigate, useSearchParams } from 'react-router-dom' import { useMedia } from 'react-use' import { Box, Flex, Text } from 'rebass' import { parseGetRouteResponse } from 'services/route/utils' @@ -90,6 +90,7 @@ export type SwapFormProps = { const SwapForm: React.FC = props => { const { pathname } = useLocation() const isPartnerSwap = pathname.startsWith(APP_PATHS.PARTNER_SWAP) + const [searchParams] = useSearchParams() const { hidden, currencyIn, @@ -146,6 +147,7 @@ const SwapForm: React.FC = props => { parsedAmount, isProcessingSwap, customChain: chainId, + clientId: searchParams.get('clientId') || undefined, }) const { data: getRouteRawResponse, isFetching: isGettingRoute, error: getRouteError } = result diff --git a/src/constants/index.ts b/src/constants/index.ts index 50f12c5fb9..b42d848c3b 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -172,6 +172,7 @@ export const APP_PATHS = { IAM_CONSENT: '/consent', DEPRECATED_NOTI_CENTER: '/notification-center/overview', + ELASTIC_SNAPSHOT: '/elastic-snapshot', } as const export const TERM_FILES_PATH = { diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 41376121bb..364a9eb5a0 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -38,6 +38,8 @@ const Login = lazy(() => import('./Oauth/Login')) const Logout = lazy(() => import('./Oauth/Logout')) const Consent = lazy(() => import('./Oauth/Consent')) +const ElasticSnapshot = lazy(() => import('./ElasticSnapshot')) + // test page for swap only through elastic const ElasticSwap = lazy(() => import('./ElasticSwap')) const SwapV3 = lazy(() => import('./SwapV3')) @@ -386,6 +388,8 @@ export default function App() { } /> } /> + } /> + } /> diff --git a/src/pages/ElasticSnapshot/index.tsx b/src/pages/ElasticSnapshot/index.tsx new file mode 100644 index 0000000000..3449134dde --- /dev/null +++ b/src/pages/ElasticSnapshot/index.tsx @@ -0,0 +1,350 @@ +import { ChainId } from '@kyberswap/ks-sdk-core' +import { Trans, t } from '@lingui/macro' +import { useEffect, useState } from 'react' +import { Info } from 'react-feather' +import { useMedia } from 'react-use' +import { Box, Flex, Text } from 'rebass' +import styled from 'styled-components' + +import { ButtonPrimary } from 'components/Button' +import DoubleCurrencyLogo from 'components/DoubleLogo' +import LocalLoader from 'components/LocalLoader' +import { MouseoverTooltip } from 'components/Tooltip' +import { useActiveWeb3React } from 'hooks' +import { useAllTokens } from 'hooks/Tokens' +import { NETWORKS_INFO } from 'hooks/useChainsConfig' +import useTheme from 'hooks/useTheme' +import { PoolsPageWrapper } from 'pages/Pools/styleds' +import { useWalletModalToggle } from 'state/application/hooks' +import { MEDIA_WIDTHS } from 'theme' +import { shortenAddress } from 'utils' +import { formatDisplayNumber } from 'utils/numbers' + +const Wrapper = styled.div` + border-radius: 1rem; + border: 1px solid ${({ theme }) => theme.border}; + background: ${({ theme }) => theme.background}; + color: ${({ theme }) => theme.subText}; + line-height: 1.5; + font-size: 14px; + overflow: hidden; + text-align: center; + + ${({ theme }) => theme.mediaWidth.upToSmall` + border: none; + border-radius: 0; + `} +` + +const TableHeader = styled.div` + display: grid; + font-size: 12px; + grid-template-columns: 1fr 0.75fr 1fr 1fr; + font-weight: 500; + padding: 1rem; + background: ${({ theme }) => theme.tableHeader}; + color: ${({ theme }) => theme.subText}; + align-items: center; +` +const TableRow = styled(TableHeader)` + background: ${({ theme }) => theme.background}; + color: ${({ theme }) => theme.text}; + border-bottom: 1px solid ${({ theme }) => theme.border}; + font-size: 14px; + + ${({ theme }) => theme.mediaWidth.upToSmall` + grid-template-columns: 1fr 1fr; + gap: 0.75rem; + background: ${({ theme }) => theme.buttonBlack}; + justify-content: space-between; + `} +` + +export default function ElasticSnapshot() { + const { account } = useActiveWeb3React() + const theme = useTheme() + const [data, setData] = useState< + { + user_address: string + total_usd: number + total_liquidity_usd: number + total_fee_usd: number + positions: { + position_id: number + position_usd: number + liquidity_usd: number + fee_usd: number + info: { + pool: string + chain: string + pair: string + token0: string + token1: string + } + }[] + }[] + >([]) + const [loading, setLoading] = useState(false) + useEffect(() => { + setLoading(true) + fetch('https://raw.githubusercontent.com/KyberNetwork/KIPs/master/elastic_incident_snapshot_data.json') + .then(res => res.json()) + .then(res => { + setData(res) + }) + .finally(() => setLoading(false)) + }, []) + + const userInfo = data.find(item => item.user_address.toLowerCase() === account?.toLowerCase()) + + const toggleWalletModal = useWalletModalToggle() + + const upToMedium = useMedia(`(max-width: ${MEDIA_WIDTHS.upToMedium}px)`) + const upToSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToSmall}px)`) + + const format = (value: number) => formatDisplayNumber(value, { style: 'currency', significantDigits: 7 }) + return ( + + + + + Snapshot + + + + You can find the list of your liquidity positions in KyberSwap Elastic pools that were affected by the + exploit below. Snapshots for each chain are taken based on the last block prior to the exploit. +
+
+ Prices are sourced based on the closest available pricing data from CoinGecko immediately following the + exploit. +
+
+ {/* + + + Official announcement is here ↗ + + + */} +
+ + + + + + Total Amount (USD) + + + {userInfo ? format(userInfo.total_usd) : '--'} + + + + {upToSmall &&
} + + + + + Total Liquidity Amount +
+ (USD) +
+
+ + {userInfo ? format(userInfo.total_liquidity_usd) : '--'} + +
+ + + + + Total Fees Amount +
+ (USD) +
+
+ + {userInfo ? format(userInfo.total_fee_usd) : '--'} + +
+ + + Total Amount (USD) = Total Liquidity Amount (USD) + Total Fees Amount (USD) + + + + + + {loading ? ( + + ) : account ? ( + userInfo ? ( + <> + + Wallet address:{' '} + + {upToSmall ? shortenAddress(1, account) : account} + + + + {!upToSmall && ( + + POOLS + NFT ID + + + + POSITION LIQUIDITY (USD) + + + + + POSITION FEE (USD) + + + + )} + + {userInfo.positions.map(item => ( + + + + {item.info.pair} + + #{item.position_id} + + {upToSmall && ( + <> + + + POSITION LIQUIDITY (USD) + + + + + + POSITION FEES (USD) + + + + )} + {format(item.position_usd)} + {format(item.fee_usd)} + + ))} + + ) : ( + + + + + None of the liquidity position(s) held by your wallet ({shortenAddress(1, account)}) was affected by + the exploit. + + + + ) + ) : ( + + + Connect your wallet to view this data + + + + Connect + + + )} + + + + ) +} + +const chainToChainId: { [key: string]: ChainId } = { + ethereum: 1, + optimism: 10, + arbitrum: 42161, + avalanche: 43114, + base: 8453, + cronos: 25, + polygon: 137, +} +const Logo = ({ chainId, address0, address1 }: { chainId: ChainId; address0: string; address1: string }) => { + const allTokens = useAllTokens(true, chainId) + + return ( + + + + + + ) +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 2124267fbd..5782216496 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -444,7 +444,7 @@ export const findTx = (txs: GroupedTxsByHash | undefined, hash: string): Transac export const isChristmasTime = () => { const currentTime = dayjs() - return currentTime.month() === 11 && currentTime.date() >= 15 + return false && currentTime.month() === 11 && currentTime.date() >= 15 } export const isSupportLimitOrder = (chainId: ChainId): boolean => {