diff --git a/components/newDashboard/DashboardSummary/DashboardHeader/BorrowLimit/index.tsx b/components/newDashboard/DashboardSummary/DashboardHeader/BorrowLimit/index.tsx index 3ba6696e8..5f4a26944 100644 --- a/components/newDashboard/DashboardSummary/DashboardHeader/BorrowLimit/index.tsx +++ b/components/newDashboard/DashboardSummary/DashboardHeader/BorrowLimit/index.tsx @@ -11,7 +11,7 @@ import { WEI_PER_ETHER } from 'utils/const'; const BorrowLimit = () => { const { t } = useTranslation(); const healthFactor = useHealthFactor(); - const { accountData } = useAccountData(); + const { accountData, isFetching } = useAccountData(); const maximumBorrow = useMemo((): string => { if (!accountData || !healthFactor) return ''; @@ -58,12 +58,12 @@ const BorrowLimit = () => { palette.grey[900] }} /> {t('Borrow Limit')} - {maximumBorrow ? ( + {!isFetching && maximumBorrow ? ( ${maximumBorrow} ) : ( - + )} ); diff --git a/components/newDashboard/DashboardSummary/DashboardHeader/HealthFactor/index.tsx b/components/newDashboard/DashboardSummary/DashboardHeader/HealthFactor/index.tsx index d87b03b7d..3d840a189 100644 --- a/components/newDashboard/DashboardSummary/DashboardHeader/HealthFactor/index.tsx +++ b/components/newDashboard/DashboardSummary/DashboardHeader/HealthFactor/index.tsx @@ -4,10 +4,12 @@ import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import { useTranslation } from 'react-i18next'; import useHealthFactor from 'hooks/useHealthFactor'; import parseHealthFactor from 'utils/parseHealthFactor'; +import useAccountData from 'hooks/useAccountData'; const HealthFactor = () => { const { t } = useTranslation(); const { palette } = useTheme(); + const { isFetching } = useAccountData(); const hf = useHealthFactor(); const healthFactor = useMemo(() => (hf ? parseHealthFactor(hf.debt, hf.collateral) : undefined), [hf]); @@ -37,8 +39,8 @@ const HealthFactor = () => { {t('Health Factor')} - {!healthFactor ? ( - + {isFetching || !healthFactor ? ( + ) : ( {healthFactor} diff --git a/components/newDashboard/DashboardSummary/DashboardHeader/NetEarnings/index.tsx b/components/newDashboard/DashboardSummary/DashboardHeader/NetEarnings/index.tsx index 81750f76e..ec9129888 100644 --- a/components/newDashboard/DashboardSummary/DashboardHeader/NetEarnings/index.tsx +++ b/components/newDashboard/DashboardSummary/DashboardHeader/NetEarnings/index.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Divider, Typography } from '@mui/material'; +import { Box, Divider, Skeleton, Typography } from '@mui/material'; import PaidRoundedIcon from '@mui/icons-material/PaidRounded'; import { useTranslation } from 'react-i18next'; import useNetAPR from 'hooks/useNetAPR'; @@ -30,16 +30,24 @@ const NetEarnings = () => { {t('Net APR')} - - {toPercentage(Number(netAPR) / 1e18)} - + {netAPR !== undefined ? ( + + {toPercentage(Number(netAPR) / 1e18)} + + ) : ( + + )} {t('Net Position')} - ${formatNumber(Number(netPosition) / 1e18)} + {netPosition !== undefined ? ( + ${formatNumber(Number(netPosition) / 1e18)} + ) : ( + + )} diff --git a/components/newDashboard/DashboardSummary/DashboardHeader/UserRewards/index.tsx b/components/newDashboard/DashboardSummary/DashboardHeader/UserRewards/index.tsx index 2fd8f686a..a01e445bb 100644 --- a/components/newDashboard/DashboardSummary/DashboardHeader/UserRewards/index.tsx +++ b/components/newDashboard/DashboardSummary/DashboardHeader/UserRewards/index.tsx @@ -10,6 +10,7 @@ import { WEI_PER_ETHER } from 'utils/const'; import { LoadingButton } from '@mui/lab'; import { useWeb3 } from 'hooks/useWeb3'; import { useModal } from 'contexts/ModalContext'; +import useAccountData from 'hooks/useAccountData'; type RewardProps = { assetSymbol: string; @@ -43,6 +44,7 @@ const Reward: FC = ({ assetSymbol, amount, amountInUSD, xsDirection const UserRewards = () => { const { t } = useTranslation(); + const { isFetching } = useAccountData(); const { impersonateActive } = useWeb3(); const { breakpoints } = useTheme(); const isMobile = useMediaQuery(breakpoints.down('lg')); @@ -99,10 +101,9 @@ const UserRewards = () => { flexDirection={{ xs: 'column', lg: 'row' }} gap={{ xs: 1, lg: 2 }} alignItems={{ xs: 'none', lg: 'center' }} - mx={rewards && rewards.length > 1 ? 0 : 'auto'} mb={{ xs: 0.5, lg: 0 }} > - {rewards ? ( + {!isFetching && rewards ? ( rewards.map(({ assetSymbol, amount, amountInUSD }) => ( { )) ) : ( - + <> + + + )} diff --git a/components/newDashboard/DashboardSummary/DashboardOverview/OverviewCard/index.tsx b/components/newDashboard/DashboardSummary/DashboardOverview/OverviewCard/index.tsx index 5eaafc695..c4b04e241 100644 --- a/components/newDashboard/DashboardSummary/DashboardOverview/OverviewCard/index.tsx +++ b/components/newDashboard/DashboardSummary/DashboardOverview/OverviewCard/index.tsx @@ -31,7 +31,7 @@ const OverviewCard: FC = ({ mobileWrap, }) => { const { t } = useTranslation(); - const { accountData } = useAccountData(); + const { accountData, isFetching } = useAccountData(); const loading = useMemo(() => !accountData, [accountData]); const empty = useMemo(() => total === '$0.00', [total]); @@ -64,17 +64,21 @@ const OverviewCard: FC = ({ )} - {loading ? ( - + {isFetching || loading ? ( + ) : ( {total} )} {!empty && ( - - {fixedValue} - + {isFetching ? ( + + ) : ( + + {fixedValue} + + )} @@ -88,9 +92,13 @@ const OverviewCard: FC = ({ - - {floatingValue} - + {isFetching ? ( + + ) : ( + + {floatingValue} + + )} diff --git a/hooks/useAccountData.ts b/hooks/useAccountData.ts index c1494d7ba..9fe67d3b8 100644 --- a/hooks/useAccountData.ts +++ b/hooks/useAccountData.ts @@ -13,6 +13,7 @@ type AccountDataHook = { marketAccount?: MarketAccount; accountData?: readonly MarketAccount[]; lastSync?: number; + isFetching: boolean; getMarketAccount: (symbol: string) => MarketAccount | undefined; refreshAccountData: (delay?: number) => Promise; }; @@ -22,7 +23,7 @@ function useAccountData(): Omit; function useAccountData( symbol?: string, ): Omit | Omit { - const { isLoading, data, refetch } = usePreviewerExactly(); + const { isLoading, isFetching, data, refetch } = usePreviewerExactly(); const ctx = useContext(AccountDataContext); @@ -52,6 +53,7 @@ function useAccountData( return { accountData: isLoading ? undefined : data, lastSync: ctx?.lastSync, + isFetching, getMarketAccount, refreshAccountData, }; @@ -60,6 +62,7 @@ function useAccountData( return { marketAccount, accountData: isLoading ? undefined : data, + isFetching, lastSync: ctx?.lastSync, refreshAccountData, }; diff --git a/hooks/useNetAPR.ts b/hooks/useNetAPR.ts index ba42e7115..5921744b5 100644 --- a/hooks/useNetAPR.ts +++ b/hooks/useNetAPR.ts @@ -10,99 +10,80 @@ import useStETHNativeAPR from './useStETHNativeAPR'; import dayjs from 'dayjs'; export default () => { - const [accounts, setAccounts] = useState([]); + const [accounts, setAccounts] = useState(); const { walletAddress, subgraphURL } = useWeb3(); - const { accountData = [] } = useAccountData(); + const { accountData, isFetching } = useAccountData(); const { floatingRows: floatingDeposit } = useDashboard('deposit'); const { floatingRows: floatingBorrow } = useDashboard('borrow'); - const markets = useMemo(() => Object.values(accountData), [accountData]); - const { rates } = useRewards(); const stETHNativeAPR = useStETHNativeAPR(); - const now = dayjs().unix(); + const { rates } = useRewards(); useEffect(() => { if (!subgraphURL || !walletAddress) return; fetchAccounts(subgraphURL, walletAddress).then(setAccounts); }, [subgraphURL, walletAddress]); - const fixedDepositsAPRs = useMemo(() => { - if (!accounts.length) return; - const _fixedPositions = accounts - .flatMap(({ market: { asset }, fixedPositions }) => fixedPositions.map((fp) => ({ ...fp, asset }))) - .filter(({ borrow }) => !borrow); - return _fixedPositions.length - ? _fixedPositions.reduce( - (acc, { rate, asset, maturity }) => { - acc[asset.toLowerCase() + maturity] = maturity < now ? 0n : rate; - return acc; - }, - {} as Record, - ) - : undefined; - }, [accounts, now]); + return useMemo(() => { + if (!accountData || !accounts || isFetching || !floatingDeposit[0].apr || !floatingBorrow[0].apr) return {}; + + const markets = Object.values(accountData); + const now = dayjs().unix(); + + const _fixedPositions = accounts.flatMap(({ market: { asset }, fixedPositions }) => + fixedPositions.map((fp) => ({ ...fp, asset })), + ); + + const fixedDepositsAPRs = _fixedPositions + .filter(({ borrow }) => !borrow) + .reduce( + (acc, { rate, asset, maturity }) => { + acc[asset.toLowerCase() + maturity] = maturity < now ? 0n : rate; + return acc; + }, + {} as Record, + ); - const fixedBorrowsAPRs = useMemo(() => { - if (!accounts.length) return; - const _fixedPositions = accounts - .flatMap(({ market: { asset }, fixedPositions }) => fixedPositions.map((fp) => ({ ...fp, asset }))) - .filter(({ borrow }) => borrow); - return _fixedPositions.length - ? _fixedPositions.reduce( - (acc, { rate, asset, maturity }) => { - acc[asset.toLowerCase() + maturity] = maturity < now ? 0n : rate; - return acc; - }, - {} as Record, - ) - : undefined; - }, [accounts, now]); + const fixedBorrowsAPRs = _fixedPositions + .filter(({ borrow }) => borrow) + .reduce( + (acc, { rate, asset, maturity }) => { + acc[asset.toLowerCase() + maturity] = maturity < now ? 0n : rate; + return acc; + }, + {} as Record, + ); - const floatingDepositAPRs = useMemo(() => { - if (!floatingDeposit[0].apr) return; - return floatingDeposit.reduce( + const floatingDepositAPRs = floatingDeposit.reduce( (acc, { symbol, apr }) => { acc[symbol] = parseEther(String(apr)); return acc; }, {} as Record, ); - }, [floatingDeposit]); - const floatingBorrowAPRs = useMemo(() => { - if (!floatingBorrow[0].apr) return; - return floatingBorrow.reduce( + const floatingBorrowAPRs = floatingBorrow.reduce( (acc, { symbol, apr }) => { acc[symbol] = parseEther(String(apr)); return acc; }, {} as Record, ); - }, [floatingBorrow]); - const totalFloatingDeposits = useMemo( - () => - markets.reduce( - (total, { floatingDepositAssets, decimals, usdPrice }) => - total + (floatingDepositAssets * usdPrice) / BigInt(10 ** decimals), - 0n, - ), - [markets], - ); + const totalFloatingDeposits = markets.reduce( + (total, { floatingDepositAssets, decimals, usdPrice }) => + total + (floatingDepositAssets * usdPrice) / BigInt(10 ** decimals), + 0n, + ); - const projectedFloatingDeposits = useMemo(() => { - if (!floatingDepositAPRs) return 0n; - return markets.reduce( + const projectedFloatingDeposits = markets.reduce( (total, { assetSymbol, floatingDepositAssets, decimals, usdPrice }) => total + (((floatingDepositAssets * usdPrice) / BigInt(10 ** decimals)) * (floatingDepositAPRs[assetSymbol] || 0n)) / WEI_PER_ETHER, 0n, ); - }, [floatingDepositAPRs, markets]); - const projectedFloatingDepositRewards = useMemo(() => { - if (!floatingDepositAPRs) return 0n; - return markets.reduce( + const projectedFloatingDepositRewards = markets.reduce( (total, { assetSymbol, floatingDepositAssets, decimals, usdPrice }) => total + rates[assetSymbol].reduce( @@ -113,43 +94,30 @@ export default () => { WEI_PER_ETHER, 0n, ); - }, [floatingDepositAPRs, markets, rates]); - const projectedFloatingDepositNative = useMemo(() => { - if (!floatingDepositAPRs) return 0n; - return markets + const projectedFloatingDepositNative = markets .filter(({ assetSymbol }) => assetSymbol === 'wstETH') .reduce( (total, { floatingDepositAssets, decimals, usdPrice }) => total + (((floatingDepositAssets * usdPrice) / BigInt(10 ** decimals)) * stETHNativeAPR) / WEI_PER_ETHER, 0n, ); - }, [floatingDepositAPRs, markets, stETHNativeAPR]); - const totalFloatingBorrows = useMemo( - () => - markets.reduce( - (total, { floatingBorrowAssets, decimals, usdPrice }) => - total + (floatingBorrowAssets * usdPrice) / BigInt(10 ** decimals), - 0n, - ), - [markets], - ); + const totalFloatingBorrows = markets.reduce( + (total, { floatingBorrowAssets, decimals, usdPrice }) => + total + (floatingBorrowAssets * usdPrice) / BigInt(10 ** decimals), + 0n, + ); - const projectedFloatingBorrows = useMemo(() => { - if (!floatingBorrowAPRs) return 0n; - return markets.reduce( + const projectedFloatingBorrows = markets.reduce( (total, { assetSymbol, floatingBorrowAssets, decimals, usdPrice }) => total + (((floatingBorrowAssets * usdPrice) / BigInt(10 ** decimals)) * (floatingBorrowAPRs[assetSymbol] || 0n)) / WEI_PER_ETHER, 0n, ); - }, [floatingBorrowAPRs, markets]); - const projectedFloatingBorrowRewards = useMemo(() => { - if (!floatingBorrowAPRs) return 0n; - return markets.reduce( + const projectedFloatingBorrowRewards = markets.reduce( (total, { assetSymbol, floatingBorrowAssets, decimals, usdPrice }) => total + rates[assetSymbol].reduce( @@ -160,23 +128,16 @@ export default () => { WEI_PER_ETHER, 0n, ); - }, [floatingBorrowAPRs, markets, rates]); - const totalFixedDeposits = useMemo( - () => - markets.reduce((total, { fixedDepositPositions, decimals, usdPrice }) => { - const fixedPosition = fixedDepositPositions.reduce( - (fixedAcc, { position: { principal } }) => fixedAcc + principal, - 0n, - ); - return total + (fixedPosition * usdPrice) / BigInt(10 ** decimals); - }, 0n), - [markets], - ); + const totalFixedDeposits = markets.reduce((total, { fixedDepositPositions, decimals, usdPrice }) => { + const fixedPosition = fixedDepositPositions.reduce( + (fixedAcc, { position: { principal } }) => fixedAcc + principal, + 0n, + ); + return total + (fixedPosition * usdPrice) / BigInt(10 ** decimals); + }, 0n); - const projectedFixedDeposits = useMemo(() => { - if (!fixedDepositsAPRs) return 0n; - return markets.reduce((total, { asset, fixedDepositPositions, decimals, usdPrice }) => { + const projectedFixedDeposits = markets.reduce((total, { asset, fixedDepositPositions, decimals, usdPrice }) => { const fixedPosition = fixedDepositPositions.reduce( (fixedAcc, { position: { principal }, maturity }) => fixedAcc + @@ -187,11 +148,8 @@ export default () => { ); return total + fixedPosition; }, 0n); - }, [fixedDepositsAPRs, markets]); - const projectedFixedDepositNative = useMemo(() => { - if (!fixedDepositsAPRs) return 0n; - return markets + const projectedFixedDepositNative = markets .filter(({ assetSymbol }) => assetSymbol === 'wstETH') .reduce((total, { fixedDepositPositions, decimals, usdPrice }) => { const fixedPosition = fixedDepositPositions.reduce( @@ -201,93 +159,77 @@ export default () => { ); return total + fixedPosition; }, 0n); - }, [fixedDepositsAPRs, markets, stETHNativeAPR]); - - const totalFixedBorrows = useMemo( - () => - markets.reduce((total, { fixedBorrowPositions, decimals, usdPrice }) => { - const fixedPosition = fixedBorrowPositions.reduce( - (fixedAcc, { position: { principal } }) => fixedAcc + principal, - 0n, - ); - return total + (fixedPosition * usdPrice) / BigInt(10 ** decimals); - }, 0n), - [markets], - ); - const projectedFixedBorrows = useMemo(() => { - if (!fixedBorrowsAPRs) return 0n; - return markets.reduce((total, { asset, fixedBorrowPositions, decimals, usdPrice }) => { + const totalFixedBorrows = markets.reduce((total, { fixedBorrowPositions, decimals, usdPrice }) => { const fixedPosition = fixedBorrowPositions.reduce( - (fixedAcc, { position: { principal }, maturity }) => - fixedAcc + - (((principal * usdPrice) / BigInt(10 ** decimals)) * - (fixedBorrowsAPRs[asset.toLowerCase() + maturity] || 0n)) / - WEI_PER_ETHER, + (fixedAcc, { position: { principal } }) => fixedAcc + principal, 0n, ); - return total + fixedPosition; + return total + (fixedPosition * usdPrice) / BigInt(10 ** decimals); }, 0n); - }, [fixedBorrowsAPRs, markets]); - const projectedFixedBorrowRewards = useMemo(() => { - if (!fixedBorrowsAPRs) return 0n; - return markets.reduce((total, { assetSymbol, fixedBorrowPositions, decimals, usdPrice }) => { + const projectedFixedBorrows = markets.reduce((total, { asset, fixedBorrowPositions, decimals, usdPrice }) => { const fixedPosition = fixedBorrowPositions.reduce( - (fixedAcc, { position: { principal } }) => + (fixedAcc, { position: { principal }, maturity }) => fixedAcc + - rates[assetSymbol].reduce( - (acc, { borrow }) => acc + ((principal * usdPrice) / BigInt(10 ** decimals)) * borrow, - 0n, - ) / + (((principal * usdPrice) / BigInt(10 ** decimals)) * + (fixedBorrowsAPRs[asset.toLowerCase() + maturity] || 0n)) / WEI_PER_ETHER, 0n, ); return total + fixedPosition; }, 0n); - }, [fixedBorrowsAPRs, markets, rates]); - const netPosition = useMemo( - () => totalFloatingDeposits + totalFixedDeposits - totalFloatingBorrows - totalFixedBorrows, - [totalFixedBorrows, totalFixedDeposits, totalFloatingBorrows, totalFloatingDeposits], - ); + const projectedFixedBorrowRewards = markets.reduce( + (total, { assetSymbol, fixedBorrowPositions, decimals, usdPrice }) => { + const fixedPosition = fixedBorrowPositions.reduce( + (fixedAcc, { position: { principal } }) => + fixedAcc + + rates[assetSymbol].reduce( + (acc, { borrow }) => acc + ((principal * usdPrice) / BigInt(10 ** decimals)) * borrow, + 0n, + ) / + WEI_PER_ETHER, + 0n, + ); + return total + fixedPosition; + }, + 0n, + ); + + const netPosition = totalFloatingDeposits + totalFixedDeposits - totalFloatingBorrows - totalFixedBorrows; + if (netPosition === 0n) { + return { + marketAPR: 0n, + rewardsAPR: 0n, + nativeAPR: 0n, + netAPR: 0n, + netPosition: 0n, + }; + } - const projectedMarketEarnings = useMemo( - () => projectedFloatingDeposits + projectedFixedDeposits - projectedFloatingBorrows - projectedFixedBorrows, - [projectedFixedBorrows, projectedFixedDeposits, projectedFloatingBorrows, projectedFloatingDeposits], - ); + const projectedMarketEarnings = + projectedFloatingDeposits + projectedFixedDeposits - projectedFloatingBorrows - projectedFixedBorrows; - const projectedRewardsEarnings = useMemo( - () => projectedFixedBorrowRewards + projectedFloatingBorrowRewards + projectedFloatingDepositRewards, - [projectedFixedBorrowRewards, projectedFloatingBorrowRewards, projectedFloatingDepositRewards], - ); + const projectedRewardsEarnings = + projectedFixedBorrowRewards + projectedFloatingBorrowRewards + projectedFloatingDepositRewards; - const projectedNativeEarnings = useMemo( - () => projectedFixedDepositNative + projectedFloatingDepositNative, - [projectedFixedDepositNative, projectedFloatingDepositNative], - ); + const projectedNativeEarnings = projectedFixedDepositNative + projectedFloatingDepositNative; - const marketAPR = useMemo(() => { - if (!netPosition) return 0n; - return (projectedMarketEarnings * WEI_PER_ETHER) / netPosition; - }, [projectedMarketEarnings, netPosition]); + const marketAPR = (projectedMarketEarnings * WEI_PER_ETHER) / netPosition; - const rewardsAPR = useMemo(() => { - if (!netPosition) return 0n; - return (projectedRewardsEarnings * WEI_PER_ETHER) / netPosition; - }, [projectedRewardsEarnings, netPosition]); + const rewardsAPR = (projectedRewardsEarnings * WEI_PER_ETHER) / netPosition; - const nativeAPR = useMemo(() => { - if (!netPosition) return 0n; - return (projectedNativeEarnings * WEI_PER_ETHER) / netPosition; - }, [projectedNativeEarnings, netPosition]); + const nativeAPR = (projectedNativeEarnings * WEI_PER_ETHER) / netPosition; - const netAPR = useMemo(() => marketAPR + rewardsAPR + nativeAPR, [marketAPR, nativeAPR, rewardsAPR]); + const netAPR = marketAPR + rewardsAPR + nativeAPR; - return { - marketAPR, - rewardsAPR, - netAPR, - netPosition, - }; + return { + marketAPR, + rewardsAPR, + nativeAPR, + netAPR, + netPosition, + }; + }, [accountData, accounts, floatingBorrow, floatingDeposit, isFetching, rates, stETHNativeAPR]); };