From 80c04ce0a21dac5a4adf0a0b08adbae8b41ca4c3 Mon Sep 17 00:00:00 2001 From: Harsh Date: Fri, 6 Oct 2023 19:01:11 +0530 Subject: [PATCH] added logic for total portfolio value --- .../screens/Portfolio/PortfolioScreen.tsx | 6 +- .../Portfolio/components/DFIBalanceCard.tsx | 36 +++-- .../Portfolio/components/TotalPortfolio.tsx | 17 +- .../Portfolio/hooks/EvmTokenBalances.ts | 150 +++++++----------- .../screens/Portfolio/hooks/TokenBalance.ts | 16 +- 5 files changed, 101 insertions(+), 124 deletions(-) diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx index bf93203e9c..154edd5e48 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx @@ -91,6 +91,7 @@ import { } from "./components/TotalPortfolio"; import { useTokenPrice } from "./hooks/TokenPrice"; import { PortfolioParamList } from "./PortfolioNavigator"; +import { useEvmTokenBalances } from "./hooks/EvmTokenBalances"; type Props = StackScreenProps; @@ -200,8 +201,9 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { const tokens = useSelector((state: RootState) => tokensSelector(state.wallet), ); + const { evmTokens } = useEvmTokenBalances(); const { totalAvailableValue, dstTokens } = useMemo(() => { - return tokens.reduce( + return (domain === DomainType.EVM ? evmTokens : tokens).reduce( ( { totalAvailableValue, @@ -242,7 +244,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { dstTokens: [], }, ); - }, [prices, tokens]); + }, [prices, tokens, domain, evmTokens]); // add token that are 100% locked as collateral into dstTokens const combinedTokens = useMemo(() => { diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx index d022f50991..87286bf64c 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx @@ -19,6 +19,7 @@ import { translate } from "@translations"; import { useDomainContext, DomainType } from "@contexts/DomainContext"; import { TokenNameText } from "./TokenNameText"; import { TokenAmountText } from "./TokenAmountText"; +import { useEvmTokenBalances } from "../hooks/EvmTokenBalances"; interface DFIBalaceCardProps { denominationCurrency: string; @@ -28,28 +29,35 @@ export function DFIBalanceCard({ denominationCurrency, }: DFIBalaceCardProps): JSX.Element { const { domain } = useDomainContext(); + const { evmTokens } = useEvmTokenBalances(); + const evmDFIToken = evmTokens.find(({ id }) => id === "0-EVM"); const navigation = useNavigation>(); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const DFIUnified = useSelector((state: RootState) => - unifiedDFISelector(state.wallet) + unifiedDFISelector(state.wallet), ); const { hasFetchedToken } = useSelector((state: RootState) => state.wallet); const { getTokenPrice } = useTokenPrice(denominationCurrency); // input based on selected denomination from portfolio tab + const isEvmDomain = domain === DomainType.EVM; + const tokenAmount = isEvmDomain + ? new BigNumber(evmDFIToken?.amount ?? 0) + : new BigNumber(DFIUnified.amount ?? 0); const usdAmount = getTokenPrice( DFIUnified.symbol, - new BigNumber(DFIUnified.amount), - DFIUnified.isLPS + tokenAmount, + DFIUnified.isLPS, ); const DFIIcon = getNativeIcon("_UTXO"); const EvmDFIIcon = getNativeIcon("EvmDFI"); - const isEvmDomain = domain === DomainType.EVM; - + const isPositiveBalance = isEvmDomain + ? new BigNumber(evmDFIToken?.amount ?? 0).gt(0) + : new BigNumber(DFIUtxo.amount ?? 0).plus(DFIToken.amount ?? 0).gt(0); return ( @@ -65,9 +73,7 @@ export function DFIBalanceCard({ }) } activeOpacity={0.7} - disabled={ - !new BigNumber(DFIUtxo.amount ?? 0).plus(DFIToken.amount ?? 0).gt(0) - } + disabled={!isPositiveBalance} > {!isEvmDomain ? ( @@ -88,7 +94,7 @@ export function DFIBalanceCard({ > {hasFetchedToken ? ( - {hasFetchedToken && - !new BigNumber(DFIUtxo.amount ?? 0) - .plus(DFIToken.amount ?? 0) - .gt(0) && - !isEvmDomain && } + {hasFetchedToken && !isPositiveBalance && !isEvmDomain && } ); @@ -158,7 +160,7 @@ function GetDFIBtn(): JSX.Element { > {translate("screens/GetDFIScreen", "Get DFI now!")} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx index 35862a3312..d0cd3a7a1d 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx @@ -45,17 +45,20 @@ interface PortfolioButtonGroup { export function TotalPortfolio(props: TotalPortfolioProps): JSX.Element { const { hasFetchedToken } = useSelector((state: RootState) => state.wallet); const { domain } = useDomainContext(); + const isEvmDomain = domain === DomainType.EVM; const { hasFetchedVaultsData } = useSelector( (state: RootState) => state.loans, ); const [isExpanded, setIsExpanded] = useState(false); const denominationCurrency = props.denominationCurrency; // for 'BTC' or 'DFI' denomination - const totalPortfolioValue = BigNumber.max( - 0, - new BigNumber(props.totalAvailableValue) - .plus(props.totalLockedValue) - .minus(props.totalLoansValue), - ); + const totalPortfolioValue = isEvmDomain + ? new BigNumber(props.totalAvailableValue) + : BigNumber.max( + 0, + new BigNumber(props.totalAvailableValue) + .plus(props.totalLockedValue) + .minus(props.totalLoansValue), + ); const [activeButtonGroup, setActiveButtonGroup] = useState(); const onCurrencySwitch = (): void => { @@ -123,7 +126,7 @@ export function TotalPortfolio(props: TotalPortfolioProps): JSX.Element { } /> - {domain === DomainType.DVM && ( + {!isEvmDomain && ( setIsExpanded(!isExpanded)} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts index bce3611e6b..f7e1263204 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts @@ -1,7 +1,6 @@ -import BigNumber from "bignumber.js"; import { useEffect, useState } from "react"; import { formatEther, formatUnits } from "viem"; -import { useNetworkContext } from "@waveshq/walletkit-ui"; +import { WalletToken, useNetworkContext } from "@waveshq/walletkit-ui"; import { utils } from "ethers"; import { useGetEvmAddressDetailsMutation, @@ -11,16 +10,19 @@ import { DomainType, useDomainContext } from "@contexts/DomainContext"; import { useSelector } from "react-redux"; import { RootState } from "@store"; import { useIsFocused } from "@react-navigation/native"; +import { TokenData } from "@defichain/whale-api-client/dist/api/tokens"; import { useLogger } from "@shared-contexts/NativeLoggingProvider"; -import { DomainToken } from "./TokenBalance"; +import { useWalletContext } from "@shared-contexts/WalletContext"; -const GWEI_DECIMAL = 9; // Source: https://docs.ethers.org/v5/api/utils/display-logic/ +interface AssociatedToken { + [key: string]: TokenData; +} -export function useEvmTokenBalances(): { evmTokens: DomainToken[] } { - // const { evmAddress } = useWalletContext(); - const evmAddress = "0x6aA59C49B27D9a3cBd9f976f7e6179F84be53C05"; - const [evmTokens, setEvmTokens] = useState([]); - const [allTokensWithAddress, setAllTokensWithAddress] = useState({}); +export function useEvmTokenBalances(): { evmTokens: WalletToken[] } { + const { evmAddress } = useWalletContext(); + const [evmTokens, setEvmTokens] = useState([]); + const [allTokensWithAddress, setAllTokensWithAddress] = + useState({}); const [getEvmAddressDetails] = useGetEvmAddressDetailsMutation(); const [getTokenBalances] = useGetEvmTokenBalancesMutation(); const blockCount = useSelector((state: RootState) => state.block.count); @@ -40,32 +42,18 @@ export function useEvmTokenBalances(): { evmTokens: DomainToken[] } { }, {}), ); }, [allTokens]); - // eslint-disable-next-line no-console - console.log({ allTokensWithAddress }); const getEvmTokens = async () => { - // const dfiToken = { - // id: "0-EVM", - // symbol: "DFI", - // symbolKey: "DFI", - // isDAT: true, - // isLPS: false, - // isLoanToken: false, - // amount: "0", - // name: "DeFiChain", - // displaySymbol: "EvmDFI", - // avatarSymbol: "EvmDFI", - // } - const evmDfiToken: DomainToken = { - tokenId: "0-EVM", - available: new BigNumber(0), - token: { - name: "DFI for EVM", - displaySymbol: "EvmDFI", - displayTextSymbol: "DFI", - symbol: "DFI", - isLPS: false, - domainType: DomainType.EVM, - }, + const dfiToken: WalletToken = { + id: "0-EVM", + symbol: "DFI", + symbolKey: "DFI", + isDAT: true, + isLPS: false, + isLoanToken: false, + amount: "0", + name: "DeFiChain for EVM", + displaySymbol: "EvmDFI", + avatarSymbol: "EvmDFI", }; try { const details = await getEvmAddressDetails({ @@ -73,68 +61,44 @@ export function useEvmTokenBalances(): { evmTokens: DomainToken[] } { evmAddress, }).unwrap(); const evmDfiBalance = formatEther(BigInt(details.coin_balance ?? 0)); - evmDfiToken.available = new BigNumber(evmDfiBalance); const tokensBalances = await getTokenBalances({ network, evmAddress, }).unwrap(); - // console.log({tokensBalances}) - // const evmTokens = tokensBalances.reduce((current, each) => { - // const tokenAddress = each?.token?.address - // const tokenDetails = allTokensWithAddress[tokenAddress] ?? null; - // if (tokenDetails) { - // return [...current, { - // id: "0-EVM", - // symbol: "DFI", - // symbolKey: "DFI", - // isDAT: true, - // isLPS: false, - // isLoanToken: false, - // amount: "0", - // name: "DeFiChain", - // displaySymbol: "EvmDFI", - // avatarSymbol: "EvmDFI", - // }] - // } - // return current - // // { - // // id: "0-EVM", - // // symbol: "DFI", - // // symbolKey: "DFI", - // // isDAT: true, - // // isLPS: false, - // // isLoanToken: false, - // // amount: "0", - // // name: "DeFiChain", - // // displaySymbol: "EvmDFI", - // // avatarSymbol: "EvmDFI", - // // } - // }, []) - - const evmAddressTokens: DomainToken[] = tokensBalances - // .filter(({ token }) => token.type === "DST20") // TODO (lyka): Add filter to only get DST20 tokens - .map(({ token_id, value, token }) => ({ - tokenId: `${token_id}-EVM`, - available: new BigNumber( - formatUnits( - BigInt(value ?? "0"), - Number(token.decimals ?? GWEI_DECIMAL), - ), - ), - token: { - name: `${token.name} for EVM`, - displaySymbol: token.symbol, - displayTextSymbol: token.symbol, - symbol: token.symbol, - isLPS: false, - domainType: DomainType.EVM, + dfiToken.amount = evmDfiBalance; + setEvmTokens( + tokensBalances.reduce( + (current: WalletToken[], each) => { + const tokenAddress = each?.token?.address; + const tokenDetails = allTokensWithAddress[tokenAddress] ?? null; + if (tokenDetails) { + return [ + ...current, + { + id: `${tokenDetails.id}-EVM`, + symbol: tokenDetails.symbol, + symbolKey: tokenDetails.symbolKey, + isDAT: tokenDetails.isDAT, + isLPS: tokenDetails.isLPS, + isLoanToken: tokenDetails.isLoanToken, + name: `${tokenDetails.name} for EVM`, + displaySymbol: tokenDetails.displaySymbol, + avatarSymbol: tokenDetails.symbol, + amount: formatUnits( + BigInt(each.value), + +each?.token?.decimals, + ), + }, + ]; + } + return current; }, - })); - - setEvmTokens([evmDfiToken, ...evmAddressTokens]); + [dfiToken], + ), + ); } catch (e) { logger.error(e); - setEvmTokens([evmDfiToken]); + setEvmTokens([dfiToken]); } }; @@ -147,14 +111,6 @@ export function useEvmTokenBalances(): { evmTokens: DomainToken[] } { return { evmTokens }; } -// function getTokenIdFromAddress(ethAddress: string): string { -// if (!ethAddress.startsWith('0xff') || ethAddress.length !== 42) { -// throw new Error('Invalid Ethereum address format'); -// } -// const hexTokenId = ethAddress.slice(4); // Remove '0xff' prefix -// return BigInt(`0x${hexTokenId}`).toString(); -// } - function getAddressFromDST20TokenId(tokenId: string): string { const parsedTokenId = BigInt(tokenId); const numberStr = parsedTokenId.toString(16); // Convert parsedTokenId to hexadecimal diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/TokenBalance.ts b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/TokenBalance.ts index 74cbd3b84e..0bd8b022f2 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/TokenBalance.ts +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/TokenBalance.ts @@ -39,6 +39,20 @@ export function useTokenBalance(): { ); const { evmTokens } = useEvmTokenBalances(); + const evmTokenList = evmTokens.map((token) => { + return { + tokenId: token.id, + available: new BigNumber(token.amount), + token: { + name: token.name, + displaySymbol: token.symbol, + displayTextSymbol: token.symbol, + symbol: token.symbol, + isLPS: token.isLPS, + domainType: DomainType.EVM, + }, + }; + }); const { dvmTokens } = useMemo(() => { return tokens.reduce( ( @@ -83,7 +97,7 @@ export function useTokenBalance(): { return { dvmTokens, - evmTokens, + evmTokens: evmTokenList, }; }