From 576da77a2a61c150f5e37e36ba1198243a4c7e73 Mon Sep 17 00:00:00 2001 From: hoailp Date: Sun, 17 Dec 2023 01:27:25 +0700 Subject: [PATCH] [GSW-471] fix: assets wallet --- .../web/src/common/values/token-constant.ts | 2 +- .../LiquidityEnterAmounts.stories.tsx | 20 +- .../wallet/asset-info/AssetInfo.stories.tsx | 21 +- .../wallet/asset-info/AssetInfo.styles.ts | 2 +- .../wallet/asset-info/AssetInfo.tsx | 23 +- .../AssetListHeader.styles.ts | 2 +- .../asset-list-header/AssetListHeader.tsx | 4 +- .../wallet/deposit-modal/DepositModal.tsx | 14 +- .../wallet/withdraw-modal/WithDrawModal.tsx | 16 +- .../AssetListContainer.tsx | 228 +++++++++--------- .../WalletBalanceContainer.tsx | 33 ++- .../web/src/hooks/token/use-token-data.tsx | 158 +++++++----- packages/web/src/models/token/token-model.ts | 6 +- 13 files changed, 297 insertions(+), 232 deletions(-) diff --git a/packages/web/src/common/values/token-constant.ts b/packages/web/src/common/values/token-constant.ts index 679c0609c..4d9b56963 100644 --- a/packages/web/src/common/values/token-constant.ts +++ b/packages/web/src/common/values/token-constant.ts @@ -3,7 +3,7 @@ import { TokenModel } from "@models/token/token-model"; export const GNOT_TOKEN: TokenModel = { type: "native", chainId: "", - createdAt: "0001-01-01T00:00:00Z", + createdat: "0001-01-01T00:00:00Z", name: "Gnoland", path: "gnot", decimals: 6, diff --git a/packages/web/src/components/common/liquidity-enter-amounts/LiquidityEnterAmounts.stories.tsx b/packages/web/src/components/common/liquidity-enter-amounts/LiquidityEnterAmounts.stories.tsx index 344e7af43..4ce364636 100644 --- a/packages/web/src/components/common/liquidity-enter-amounts/LiquidityEnterAmounts.stories.tsx +++ b/packages/web/src/components/common/liquidity-enter-amounts/LiquidityEnterAmounts.stories.tsx @@ -1,8 +1,5 @@ import React from "react"; -import { - ComponentStory, - ComponentMeta -} from "@storybook/react"; +import { ComponentStory, ComponentMeta } from "@storybook/react"; import EnterAmounts from "./LiquidityEnterAmounts"; import { action } from "@storybook/addon-actions"; @@ -18,20 +15,21 @@ const Template: ComponentStory = args => ( ); const token: TokenModel = { - "isWrappedGasToken": false, - "isGasToken": false, - "description": "", - "websiteURL": "", + isWrappedGasToken: false, + isGasToken: false, + description: "", + websiteURL: "", type: "grc20", chainId: "dev.gnoswap", - createdAt: "2023-12-08T03:57:43Z", + createdat: "2023-12-08T03:57:43Z", name: "Foo", path: "gno.land/r/foo", decimals: 4, symbol: "FOO", - logoURI: "https://raw.githubusercontent.com/onbloc/gno-token-resource/main/grc20/images/gno_land_r_foo.svg", + logoURI: + "https://raw.githubusercontent.com/onbloc/gno-token-resource/main/grc20/images/gno_land_r_foo.svg", priceId: "gno.land/r/foo", - address: "" + address: "", }; export const Default = Template.bind({}); diff --git a/packages/web/src/components/wallet/asset-info/AssetInfo.stories.tsx b/packages/web/src/components/wallet/asset-info/AssetInfo.stories.tsx index 68c95355f..f9a1ca0aa 100644 --- a/packages/web/src/components/wallet/asset-info/AssetInfo.stories.tsx +++ b/packages/web/src/components/wallet/asset-info/AssetInfo.stories.tsx @@ -19,14 +19,19 @@ const Template: ComponentStory = args => ( export const Default = Template.bind({}); Default.args = { asset: { - id: "BTC", - logoUri: - "https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png", - type: "GRC20", - name: "Bitcoin", - symbol: "BTC", - chain: "Gnoland", - balance: "0.000000", + type: "grc20", + chainId: "dev", + createdat: "2023-12-12 23:45:12", + name: "Bar", + path: "gno.land/r/bar", + decimals: 6, + symbol: "BAR", + logoURI: + "https://raw.githubusercontent.com/onbloc/gno-token-resource/main/grc20/images/gno_land_r_bar.svg", + priceId: "gno.land/r/bar", + description: "this_is_desc_section", + websiteURL: "https://website~~~~", + balance: 0.0, }, deposit: action("deposit"), withdraw: action("withdraw"), diff --git a/packages/web/src/components/wallet/asset-info/AssetInfo.styles.ts b/packages/web/src/components/wallet/asset-info/AssetInfo.styles.ts index 5528f3a4e..710278334 100644 --- a/packages/web/src/components/wallet/asset-info/AssetInfo.styles.ts +++ b/packages/web/src/components/wallet/asset-info/AssetInfo.styles.ts @@ -39,7 +39,7 @@ export const TableColumn = styled.div<{ tdWidth: number }>` height: 100%; ${mixins.flexbox("row", "center", "flex-end")}; .logo { - margin-left: 16px; + margin-left: 15px; } .name, .chain, diff --git a/packages/web/src/components/wallet/asset-info/AssetInfo.tsx b/packages/web/src/components/wallet/asset-info/AssetInfo.tsx index deda3b9be..c7a0228a9 100644 --- a/packages/web/src/components/wallet/asset-info/AssetInfo.tsx +++ b/packages/web/src/components/wallet/asset-info/AssetInfo.tsx @@ -23,7 +23,7 @@ const AssetInfo: React.FC = ({ withdraw, breakpoint, }) => { - const { logoUri, name, symbol, chain, balance } = asset; + const { logoURI, name, symbol, balance } = asset; const onClickItem = useCallback((symbol: string) => { location.href = "/tokens/" + symbol; @@ -44,12 +44,15 @@ const AssetInfo: React.FC = ({ tdWidth={ASSET_TD_WIDTH[0]} onClick={() => onClickItem(symbol)} > - logo + logo {name} {symbol} - {chain} + + Gnoland + {/* {chain} */} + {balance} @@ -68,12 +71,15 @@ const AssetInfo: React.FC = ({ tdWidth={TABLET_ASSET_TD_WIDTH[0]} onClick={() => onClickItem(symbol)} > - logo + logo {name} {symbol} - {chain} + + Gnoland + {/* {chain} */} + {balance} @@ -92,12 +98,15 @@ const AssetInfo: React.FC = ({ tdWidth={MOBILE_ASSET_TD_WIDTH[0]} onClick={() => onClickItem(symbol)} > - logo + logo {name} {symbol} - {chain} + + Gnoland + {/* {chain} */} + {balance} diff --git a/packages/web/src/components/wallet/asset-list-header/AssetListHeader.styles.ts b/packages/web/src/components/wallet/asset-list-header/AssetListHeader.styles.ts index 205ca4bcb..c757eaa77 100644 --- a/packages/web/src/components/wallet/asset-list-header/AssetListHeader.styles.ts +++ b/packages/web/src/components/wallet/asset-list-header/AssetListHeader.styles.ts @@ -22,7 +22,7 @@ export const AssetListHeaderWrapper = styled.div` gap: 36px; ${media.tabletMiddle} { gap: 24px; - height: 24px; + // height: 24px; ${mixins.flexbox("column", "flex-start", "flex-start")}; } ${media.mobile} { diff --git a/packages/web/src/components/wallet/asset-list-header/AssetListHeader.tsx b/packages/web/src/components/wallet/asset-list-header/AssetListHeader.tsx index 48b5d0096..07a5026d0 100644 --- a/packages/web/src/components/wallet/asset-list-header/AssetListHeader.tsx +++ b/packages/web/src/components/wallet/asset-list-header/AssetListHeader.tsx @@ -53,7 +53,9 @@ const AssetListHeader: React.FC = ({ /> )} {searchIcon ? ( -
}> +
} + > = ({
- {!Number(amount) ? "-" : `$${amount}`} + + {!Number(amount) ? "-" : `$${amount}`} + Available: -
@@ -111,7 +113,7 @@ const DepositModal: React.FC = ({ /> {fromToken.symbol} -

{formatAddress(fromToken.address)}

+

{formatAddress(fromToken?.address ?? "")}

@@ -126,7 +128,7 @@ const DepositModal: React.FC = ({ /> {toToken.symbol} -

{formatAddress(toToken.address)}

+

{formatAddress(toToken.address ?? "")}

@@ -146,13 +148,15 @@ const DepositModal: React.FC = ({ ? undefined : ButtonHierarchy.Primary, bgColor: - connected && !Number(amount || 0) ? "background17" : undefined, + connected && !Number(amount || 0) + ? "background17" + : undefined, }} /> - + ); }; diff --git a/packages/web/src/components/wallet/withdraw-modal/WithDrawModal.tsx b/packages/web/src/components/wallet/withdraw-modal/WithDrawModal.tsx index e1c80c60f..b74090eb7 100644 --- a/packages/web/src/components/wallet/withdraw-modal/WithDrawModal.tsx +++ b/packages/web/src/components/wallet/withdraw-modal/WithDrawModal.tsx @@ -27,7 +27,7 @@ interface Props { toToken: TokenModel; connected: boolean; changeToken: (token: TokenModel) => void; - callback?: (value: boolean) => void; + callback?: (value: boolean) => void; } function isAmount(str: string) { @@ -96,7 +96,9 @@ const WithDrawModal: React.FC = ({
- {!Number(amount) ? "-" : `$${amount}`} + + {!Number(amount) ? "-" : `$${amount}`} + Available: -
@@ -112,7 +114,7 @@ const WithDrawModal: React.FC = ({ /> {fromToken.symbol} -

{formatAddress(fromToken.address)}

+

{formatAddress(fromToken.address ?? "")}

@@ -127,7 +129,7 @@ const WithDrawModal: React.FC = ({ /> {toToken.symbol} -

{formatAddress(toToken.address)}

+

{formatAddress(toToken.address ?? "")}

@@ -147,13 +149,15 @@ const WithDrawModal: React.FC = ({ ? undefined : ButtonHierarchy.Primary, bgColor: - connected && !Number(amount || 0) ? "background17" : undefined, + connected && !Number(amount || 0) + ? "background17" + : undefined, }} /> - + ); }; diff --git a/packages/web/src/containers/asset-list-container/AssetListContainer.tsx b/packages/web/src/containers/asset-list-container/AssetListContainer.tsx index b05c26424..1788eb9e9 100644 --- a/packages/web/src/containers/asset-list-container/AssetListContainer.tsx +++ b/packages/web/src/containers/asset-list-container/AssetListContainer.tsx @@ -1,23 +1,18 @@ // TODO : remove eslint-disable after work /* eslint-disable */ -import React, { useCallback, useEffect, useState, useMemo } from "react"; -import { ValuesType } from "utility-types"; -import { useQuery } from "@tanstack/react-query"; import AssetList from "@components/wallet/asset-list/AssetList"; -import BigNumber from "bignumber.js"; -import { useWindowSize } from "@hooks/common/use-window-size"; -import useClickOutside from "@hooks/common/use-click-outside"; import DepositModal from "@components/wallet/deposit-modal/DepositModal"; import WithDrawModal from "@components/wallet/withdraw-modal/WithDrawModal"; -import { TokenModel } from "@models/token/token-model"; -import { useWallet } from "@hooks/wallet/use-wallet"; +import useClickOutside from "@hooks/common/use-click-outside"; import { usePreventScroll } from "@hooks/common/use-prevent-scroll"; - -interface AssetListResponse { - hasNext: boolean; - currentPage: number; - assets: Asset[]; -} +import { useWindowSize } from "@hooks/common/use-window-size"; +import { useTokenData } from "@hooks/token/use-token-data"; +import { useWallet } from "@hooks/wallet/use-wallet"; +import { TokenModel } from "@models/token/token-model"; +import { useGetTokensList } from "@query/token"; +import BigNumber from "bignumber.js"; +import React, { useCallback, useEffect, useState } from "react"; +import { ValuesType } from "utility-types"; export interface AssetSortOption { key: ASSET_HEAD; @@ -41,19 +36,19 @@ const SORT_PARAMS: { [key in ASSET_HEAD]: string } = { Withdraw: "withdraw", }; -export interface Asset { - id: string; - logoUri: string; - type: ASSET_TYPE; - name: string; - symbol: string; - chain: string; - balance: string; +export interface Asset extends TokenModel { + // id: string; + // logoUri: string; + // type: ASSET_TYPE; + // name: string; + // symbol: string; + // chain: string; + balance?: number | string | null; } export const ASSET_TYPE = { - NATIVE: "NATIVE", - GRC20: "GRC20", + NATIVE: "native", + GRC20: "grc20", } as const; export type ASSET_TYPE = ValuesType; @@ -67,53 +62,37 @@ export type ASSET_FILTER_TYPE = ValuesType; export const dummyAssetList: Asset[] = [ { - id: "BTC", - logoUri: - "https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png", - type: ASSET_TYPE.NATIVE, - name: "Bitcoin", - symbol: "BTC", - chain: "Gnoland", - balance: "0.1", + type: "grc20", + chainId: "dev", + createdat: "2023-12-12 23:45:12", + name: "Bar", + path: "gno.land/r/bar", + decimals: 6, + symbol: "BAR", + logoURI: + "https://raw.githubusercontent.com/onbloc/gno-token-resource/main/grc20/images/gno_land_r_bar.svg", + priceId: "gno.land/r/bar", + description: "this_is_desc_section", + websiteURL: "https://website~~~~", }, { - id: "GNS", - logoUri: - "https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xB98d4C97425d9908E66E53A6fDf673ACcA0BE986/logo.png", - type: ASSET_TYPE.GRC20, - name: "Gnoswap", - symbol: "GNS", - chain: "Gnoland", - balance: "0.000000", + type: "grc20", + chainId: "dev", + createdat: "2023-12-12 23:45:12", + name: "Bar", + path: "gno.land/r/bar", + decimals: 6, + symbol: "BAR", + logoURI: + "https://raw.githubusercontent.com/onbloc/gno-token-resource/main/grc20/images/gno_land_r_bar.svg", + priceId: "gno.land/r/bar", + description: "this_is_desc_section", + websiteURL: "https://website~~~~", }, ]; -async function fetchAssets( - address: string, - sortKey?: string, // eslint-disable-line - direction?: string, // eslint-disable-line -): Promise { - return new Promise(resolve => setTimeout(resolve, 2000)).then(() => - Promise.resolve([ - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ...dummyAssetList, - ]), - ); -} - function filterZeroBalance(asset: Asset) { - const balance = BigNumber(asset.balance); + const balance = BigNumber(asset?.balance ?? 0); return balance.isGreaterThan(0); } @@ -127,7 +106,7 @@ function filterKeyword(asset: Asset, keyword: string) { if (searchKeyword === "") return true; return ( asset.name.toLowerCase().includes(searchKeyword) || - asset.chain.toLowerCase().includes(searchKeyword) || + // asset.chain.toLowerCase().includes(searchKeyword) || asset.symbol.toLowerCase().includes(searchKeyword) ); } @@ -140,8 +119,7 @@ const DEPOSIT_TO: TokenModel = { path: "gno.land/r/gns", decimals: 4, symbol: "Cosmos", - logoURI: - "/cosmos.svg", + logoURI: "/cosmos.svg", type: "grc20", priceId: "gno.land/r/gns", }; @@ -167,13 +145,11 @@ const DEPOSIT_INFO: TokenModel = { path: "gno.land/r/gns", decimals: 4, symbol: "ATOM", - logoURI: - "/atom.svg", + logoURI: "/atom.svg", type: "grc20", priceId: "gno.land/r/gns", }; - const AssetListContainer: React.FC = () => { const { connected } = useWallet(); @@ -219,41 +195,71 @@ const AssetListContainer: React.FC = () => { } }, [isClickOutside, keyword]); - const { - isFetched, - error, - data: assets, - } = useQuery({ - queryKey: ["assets", address, sortOption?.key, sortOption?.direction], - queryFn: () => - fetchAssets( - address, - sortOption && SORT_PARAMS[sortOption.key], - sortOption?.direction, - ), - }); + const { isFetched } = useGetTokensList(); + const { tokens, displayBalanceMap } = useTokenData(); useEffect(() => { - if (assets && assets.length > 0) { - const COLLAPSED_LENGTH = 15; - const filteredAssets = assets - .filter( - asset => invisibleZeroBalance === false || filterZeroBalance(asset), - ) - .filter(asset => filterType(asset, assetType)) - .filter(asset => filterKeyword(asset, keyword)); - const hasLoader = filteredAssets.length > COLLAPSED_LENGTH; - const resultFilteredAssets = extended - ? filteredAssets - : filteredAssets.slice( + if (!tokens || tokens?.length === 0) return; + + const COLLAPSED_LENGTH = 15; + let filteredAssets = tokens + .map(asset => ({ ...asset, balance: displayBalanceMap[asset.path] ?? 0 })) + .filter( + asset => invisibleZeroBalance === false || filterZeroBalance(asset), + ) + .filter(asset => filterType(asset, assetType)) + .filter(asset => filterKeyword(asset, keyword)); + + switch (sortOption?.key) { + case "Balance": + filteredAssets = filteredAssets.sort((x, y) => { + if ( + x.balance === undefined || + y.balance === undefined || + x.balance === null || + y.balance === null + ) + return 0; + + return sortOption?.direction === "asc" + ? x.balance - y.balance + : y.balance - x.balance; + }); + break; + // case "Chain": + // break; + case "Asset": + filteredAssets = filteredAssets.sort((x, y) => { + return sortOption?.direction === "asc" + ? x.name.localeCompare(y.name) + : y.name.localeCompare(x.name); + }); + break; + + default: + break; + } + + const hasLoader = filteredAssets.length > COLLAPSED_LENGTH; + const resultFilteredAssets = extended + ? filteredAssets + : filteredAssets.slice( 0, Math.min(filteredAssets.length, COLLAPSED_LENGTH), ); - setHasLoader(hasLoader); - setFilteredAsset(resultFilteredAssets); - } - }, [assets, assetType, invisibleZeroBalance, extended, keyword]); + setHasLoader(hasLoader); + setFilteredAsset(resultFilteredAssets); + }, [ + assetType, + invisibleZeroBalance, + extended, + keyword, + tokens, + connected, + displayBalanceMap, + sortOption, + ]); const changeAssetType = useCallback((newType: string) => { switch (newType) { @@ -292,7 +298,7 @@ const AssetListContainer: React.FC = () => { path: "gno.land/r/gns", decimals: 4, symbol: asset.symbol, - logoURI: asset.logoUri, + logoURI: asset.logoURI, type: "grc20", priceId: "gno.land/r/gns", }); @@ -314,7 +320,7 @@ const AssetListContainer: React.FC = () => { path: "gno.land/r/gns", decimals: 4, symbol: asset.symbol, - logoURI: asset.logoUri, + logoURI: asset.logoURI, type: "grc20", priceId: "gno.land/r/gns", }); @@ -331,8 +337,8 @@ const AssetListContainer: React.FC = () => { sortOption?.key !== item ? "desc" : sortOption.direction === "asc" - ? "desc" - : "asc"; + ? "desc" + : "asc"; setTokenSortOption({ key, @@ -347,26 +353,24 @@ const AssetListContainer: React.FC = () => { return !disableItems.includes(head); }, []); - const closeDeposit = () => { - setIsShowDepositModal(false) - } + setIsShowDepositModal(false); + }; const closeWithdraw = () => { - setIsShowWithDrawModal(false) - } + setIsShowWithDrawModal(false); + }; const callbackDeposit = (value: boolean) => { setIsShowDepositModal(value); - } + }; const callbackWithdraw = (value: boolean) => { setIsShowWithDrawModal(value); - } + }; usePreventScroll(isShowDepositModal || isShowWithdrawModal); - return ( <> { if (!address) return; }, [connected, address]); - const claimAll = useCallback(() => { }, []); + const claimAll = useCallback(() => {}, []); const { isLoading: isBalanceSummaryInfoLoading, @@ -155,20 +152,20 @@ const WalletBalanceContainer: React.FC = () => { }); const closeDeposit = () => { - setIsShowDepositModal(false) - } + setIsShowDepositModal(false); + }; const closeWithdraw = () => { - setIsShowWithDrawModal(false) - } + setIsShowWithDrawModal(false); + }; const callbackDeposit = (value: boolean) => { setIsShowDepositModal(value); - } + }; const callbackWithdraw = (value: boolean) => { setIsShowWithDrawModal(value); - } + }; usePreventScroll(isShowDepositModal || isShowWithdrawModal); diff --git a/packages/web/src/hooks/token/use-token-data.tsx b/packages/web/src/hooks/token/use-token-data.tsx index 343fc0d5d..06f507cac 100644 --- a/packages/web/src/hooks/token/use-token-data.tsx +++ b/packages/web/src/hooks/token/use-token-data.tsx @@ -2,7 +2,10 @@ import { GNOT_TOKEN } from "@common/values/token-constant"; import { MATH_NEGATIVE_TYPE } from "@constants/option.constant"; import { useGnoswapContext } from "@hooks/common/use-gnoswap-context"; import { useWallet } from "@hooks/wallet/use-wallet"; -import { CardListTokenInfo, UpDownType } from "@models/common/card-list-item-info"; +import { + CardListTokenInfo, + UpDownType, +} from "@models/common/card-list-item-info"; import { TokenModel } from "@models/token/token-model"; import { TokenPriceModel } from "@models/token/token-price-model"; import { TokenState } from "@states/index"; @@ -12,16 +15,16 @@ import { convertLargePrice } from "@utils/stake-position-utils"; import { makeDisplayTokenAmount } from "@utils/token-utils"; import BigNumber from "bignumber.js"; import { useAtom } from "jotai"; -import { useCallback, useMemo } from "react"; +import { useCallback, useEffect, useMemo } from "react"; export const useTokenData = () => { - const { account } = useWallet(); + const { account, connected } = useWallet(); const { rpcProvider, tokenRepository } = useGnoswapContext(); const [tokens, setTokens] = useAtom(TokenState.tokens); const [tokenPrices, setTokenPrices] = useAtom(TokenState.tokenPrices); const [balances, setBalances] = useAtom(TokenState.balances); const [loading, setLoading] = useAtom(TokenState.isLoading); - + const gnotToken = useMemo((): TokenModel => { const token = tokens.find(token => token.path === "gnot"); if (token) { @@ -36,34 +39,48 @@ export const useTokenData = () => { const balance = balances[key]; const token = tokens.find(token => token.priceId === key); const exist = token && balance !== null && balance !== undefined; - tokenBalanceMap[key] = exist ? makeDisplayTokenAmount(token, balance) : null; + tokenBalanceMap[key] = exist + ? makeDisplayTokenAmount(token, balance) + : null; }); return tokenBalanceMap; }, [balances, tokens]); const trendingTokens: CardListTokenInfo[] = useMemo(() => { - const sortedTokens = tokens.sort((t1, t2) => { - if (tokenPrices[t1.path] && tokenPrices[t2.path]) { - return BigNumber(tokenPrices[t2.path].volume).toNumber() - BigNumber(tokenPrices[t1.path].volume).toNumber(); - } - if (tokenPrices[t2.path]) { - return 1; - } - if (tokenPrices[t1.path]) { - return -1; - } - return 0; - }).filter((_, index) => index < 3); + const sortedTokens = tokens + .sort((t1, t2) => { + if (tokenPrices[t1.path] && tokenPrices[t2.path]) { + return ( + BigNumber(tokenPrices[t2.path].volume).toNumber() - + BigNumber(tokenPrices[t1.path].volume).toNumber() + ); + } + if (tokenPrices[t2.path]) { + return 1; + } + if (tokenPrices[t1.path]) { + return -1; + } + return 0; + }) + .filter((_, index) => index < 3); return sortedTokens.map(token => { const tokenPrice = tokenPrices[token.priceId]; - if (!tokenPrice || BigNumber(tokenPrice.pricesBefore.latestPrice).isNaN() || BigNumber(tokenPrice.pricesBefore.priceToday).isNaN()) { + if ( + !tokenPrice || + BigNumber(tokenPrice.pricesBefore.latestPrice).isNaN() || + BigNumber(tokenPrice.pricesBefore.priceToday).isNaN() + ) { return { token, upDown: "none", - content: "-" + content: "-", }; } - const data1D = checkPositivePrice(tokenPrice.pricesBefore.latestPrice, tokenPrice.pricesBefore.priceToday); + const data1D = checkPositivePrice( + tokenPrice.pricesBefore.latestPrice, + tokenPrice.pricesBefore.priceToday, + ); return { token, upDown: data1D.status === MATH_NEGATIVE_TYPE.POSITIVE ? "up" : "down", @@ -73,39 +90,54 @@ export const useTokenData = () => { }, [tokens, tokenPrices]); const recentlyAddedTokens: CardListTokenInfo[] = useMemo(() => { - const sortedTokens = tokens.sort((t1, t2) => { - const createTimeOfToken1 = new Date(t1.createdAt).getTime(); - const createTimeOfToken2 = new Date(t2.createdAt).getTime(); - return createTimeOfToken2 - createTimeOfToken1; - }).filter((_: TokenModel) => !!_.logoURI); - return sortedTokens.map(token => ( - tokenPrices[token.path] ? { - token, - upDown: "none" as UpDownType, - content: `$${convertLargePrice(tokenPrices[token.path].usd, 10)}` - } : { - token, - upDown: "none" as UpDownType, - content: "-" - })).slice(0,3); + const sortedTokens = tokens + .sort((t1, t2) => { + const createTimeOfToken1 = new Date(t1?.createdat ?? "").getTime(); + const createTimeOfToken2 = new Date(t2?.createdAt ?? "").getTime(); + return createTimeOfToken2 - createTimeOfToken1; + }) + .filter((_: TokenModel) => !!_.logoURI); + return sortedTokens + .map(token => + tokenPrices[token.path] + ? { + token, + upDown: "none" as UpDownType, + content: `$${convertLargePrice(tokenPrices[token.path].usd, 10)}`, + } + : { + token, + upDown: "none" as UpDownType, + content: "-", + }, + ) + .slice(0, 3); }, [tokenPrices, tokens]); - const getTokenUSDPrice = useCallback((tokenAId: string, amount: bigint | string | number) => { - const tokenUSDPrice = tokenPrices[tokenAId]?.usd || "0"; - if (!tokenUSDPrice || Number.isNaN(amount)) { - return null; - } - return BigNumber(amount.toString()).multipliedBy(tokenUSDPrice).toNumber(); - }, [tokenPrices]); + const getTokenUSDPrice = useCallback( + (tokenAId: string, amount: bigint | string | number) => { + const tokenUSDPrice = tokenPrices[tokenAId]?.usd || "0"; + if (!tokenUSDPrice || Number.isNaN(amount)) { + return null; + } + return BigNumber(amount.toString()) + .multipliedBy(tokenUSDPrice) + .toNumber(); + }, + [tokenPrices], + ); - const getTokenPriceRate = useCallback((tokenAId: string, tokenBId: string) => { - const tokenAUSDPrice = tokenPrices[tokenAId]?.usd; - const tokenBUSDPrice = tokenPrices[tokenBId]?.usd; - if (!tokenAUSDPrice || !tokenBUSDPrice) { - return null; - } - return BigNumber(tokenBUSDPrice).dividedBy(tokenAUSDPrice).toNumber(); - }, [tokenPrices]); + const getTokenPriceRate = useCallback( + (tokenAId: string, tokenBId: string) => { + const tokenAUSDPrice = tokenPrices[tokenAId]?.usd; + const tokenBUSDPrice = tokenPrices[tokenBId]?.usd; + if (!tokenAUSDPrice || !tokenBUSDPrice) { + return null; + } + return BigNumber(tokenBUSDPrice).dividedBy(tokenAUSDPrice).toNumber(); + }, + [tokenPrices], + ); async function updateTokens() { const response = await tokenRepository.getTokens(); @@ -115,10 +147,13 @@ export const useTokenData = () => { async function updateTokenPrices() { const response = await tokenRepository.getTokenPrices(); - const priceMap = response.prices.reduce>((prev, current) => { - prev[current.path] = current; - return prev; - }, {}); + const priceMap = response.prices.reduce>( + (prev, current) => { + prev[current.path] = current; + return prev; + }, + {}, + ); setTokenPrices(priceMap); } @@ -131,12 +166,13 @@ export const useTokenData = () => { return null; } if (token.type === "native") { - return rpcProvider.getBalance(account.address, token.denom || "ugnot") + return rpcProvider + .getBalance(account.address, token.denom || "ugnot") .catch(() => null); - } - else if (token.type === "grc20") { + } else if (token.type === "grc20") { const param = `BalanceOf("${account.address}")`; - return rpcProvider.evaluateExpression(token.path, param) + return rpcProvider + .evaluateExpression(token.path, param) .then(evaluateExpressionToNumber) .catch(() => null); } @@ -152,6 +188,10 @@ export const useTokenData = () => { setBalances(balances); } + useEffect(() => { + updateTokens(); + }, [connected]); + return { gnotToken, tokens, @@ -167,4 +207,4 @@ export const useTokenData = () => { updateBalances, loading, }; -}; \ No newline at end of file +}; diff --git a/packages/web/src/models/token/token-model.ts b/packages/web/src/models/token/token-model.ts index 562133ca0..7a7d75364 100644 --- a/packages/web/src/models/token/token-model.ts +++ b/packages/web/src/models/token/token-model.ts @@ -10,7 +10,7 @@ export interface TokenModel { type: "native" | "grc20"; - address: string; + address?: string; priceId: string; @@ -24,7 +24,9 @@ export interface TokenModel { logoURI: string; - createdAt: string; + createdAt?: string; + + createdat?: string; isWrappedGasToken?: boolean;