From 3a8de2d7c3f914d4c2b524eea258f1026355922f Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 15 Mar 2023 11:27:13 +0000 Subject: [PATCH 01/20] feat: added util to calculate apr with unit test --- src/utilities/__tests__/calculateAprPercentage.spec.ts | 7 +++++++ src/utilities/calculateAprPercentage.ts | 4 ++++ 2 files changed, 11 insertions(+) create mode 100644 src/utilities/__tests__/calculateAprPercentage.spec.ts create mode 100644 src/utilities/calculateAprPercentage.ts diff --git a/src/utilities/__tests__/calculateAprPercentage.spec.ts b/src/utilities/__tests__/calculateAprPercentage.spec.ts new file mode 100644 index 00000000..418cc90c --- /dev/null +++ b/src/utilities/__tests__/calculateAprPercentage.spec.ts @@ -0,0 +1,7 @@ +import calculateAprPercentage from '../calculateAprPercentage' + +describe('calculateAprPercentage', () => { + it('should return correct percentage', () => { + expect(calculateAprPercentage(34, 32)).toBe(6.25) + }) +}) diff --git a/src/utilities/calculateAprPercentage.ts b/src/utilities/calculateAprPercentage.ts new file mode 100644 index 00000000..fcd7068f --- /dev/null +++ b/src/utilities/calculateAprPercentage.ts @@ -0,0 +1,4 @@ +const calculateAprPercentage = (currentTotal: number, startingTotal: number) => + (Math.pow(currentTotal / startingTotal, 1) - 1) * 100 + +export default calculateAprPercentage From e9ac25524207d85bdd74d06e70f86f45251d58d1 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 15 Mar 2023 11:28:02 +0000 Subject: [PATCH 02/20] feat: add apr util to hook --- src/hooks/useValidatorEarnings.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/useValidatorEarnings.ts b/src/hooks/useValidatorEarnings.ts index da849ef2..a8c3085b 100644 --- a/src/hooks/useValidatorEarnings.ts +++ b/src/hooks/useValidatorEarnings.ts @@ -10,6 +10,7 @@ import { import calculateEpochEstimate from '../utilities/calculateEpochEstimate' import { validatorCacheBalanceResult } from '../recoil/atoms' import { selectValidatorInfos } from '../recoil/selectors/selectValidatorInfos' +import calculateAprPercentage from '../utilities/calculateAprPercentage' const useValidatorEarnings = (indices?: string[]) => { const validators = useRecoilValue(selectValidatorInfos) @@ -82,7 +83,7 @@ const useValidatorEarnings = (indices?: string[]) => { ) const initialEth = filteredValidators.length * initialEthDeposit - const annualizedEarningsPercent = (Math.pow(total / initialEth, 1) - 1) * 100 + const annualizedEarningsPercent = calculateAprPercentage(total, initialEth) return { total, From 1a2a835986cf51b7018208867eadee2a3b190b70 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 15 Mar 2023 11:29:06 +0000 Subject: [PATCH 03/20] feat: added apr calcualtion to table --- .../ValidatorDetailTable/ValidatorDetailTable.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/ValidatorDetailTable/ValidatorDetailTable.tsx b/src/components/ValidatorDetailTable/ValidatorDetailTable.tsx index 1b849299..5c64ad3a 100644 --- a/src/components/ValidatorDetailTable/ValidatorDetailTable.tsx +++ b/src/components/ValidatorDetailTable/ValidatorDetailTable.tsx @@ -3,6 +3,8 @@ import { FC } from 'react' import { ValidatorInfo } from '../../types/validator' import formatBalanceColor from '../../utilities/formatBalanceColor' import { useTranslation } from 'react-i18next' +import calculateAprPercentage from '../../utilities/calculateAprPercentage' +import { initialEthDeposit } from '../../constants/constants' export interface ValidatorDetailTableProps { validator: ValidatorInfo @@ -13,6 +15,8 @@ export const ValidatorDetailTable: FC = ({ validator const { balance } = validator const income = balance ? balance - 32 : 0 const incomeColor = formatBalanceColor(income) + const aprPercentage = calculateAprPercentage(balance, initialEthDeposit) + const annualizedTextColor = formatBalanceColor(aprPercentage) return ( <>
@@ -172,9 +176,13 @@ export const ValidatorDetailTable: FC = ({ validator -
-
- - - +
+ + {`${aprPercentage.toFixed(2)} %`}
From ace83fcaf26d03af362cf555779a66f838a4cf59 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 15 Mar 2023 11:32:09 +0000 Subject: [PATCH 04/20] fix: typogrphy fix --- src/components/AccountEarnings/AccountEarning.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AccountEarnings/AccountEarning.tsx b/src/components/AccountEarnings/AccountEarning.tsx index 21682177..e330b759 100644 --- a/src/components/AccountEarnings/AccountEarning.tsx +++ b/src/components/AccountEarnings/AccountEarning.tsx @@ -185,7 +185,7 @@ const AccountEarning = () => {
- + {t('annualized')} From a0ffdd2d9dd833580cc7221eb9a77ba20d73422a Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 15 Mar 2023 11:39:01 +0000 Subject: [PATCH 05/20] feat: added tooltip text for annual apr --- src/components/AccountEarnings/AccountEarning.tsx | 14 ++++++++------ src/locales/translations/en-US.json | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/AccountEarnings/AccountEarning.tsx b/src/components/AccountEarnings/AccountEarning.tsx index e330b759..d864ae34 100644 --- a/src/components/AccountEarnings/AccountEarning.tsx +++ b/src/components/AccountEarnings/AccountEarning.tsx @@ -184,12 +184,14 @@ const AccountEarning = () => {
-
- - {t('annualized')} - - -
+ +
+ + {t('annualized')} + + +
+
Date: Mon, 27 Mar 2023 20:21:30 +0200 Subject: [PATCH 06/20] feat: created hook to return filtered cache data by index --- src/hooks/useFilteredValidatorCacheData.ts | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/hooks/useFilteredValidatorCacheData.ts diff --git a/src/hooks/useFilteredValidatorCacheData.ts b/src/hooks/useFilteredValidatorCacheData.ts new file mode 100644 index 00000000..942097ba --- /dev/null +++ b/src/hooks/useFilteredValidatorCacheData.ts @@ -0,0 +1,24 @@ +import { useRecoilValue } from 'recoil' +import { validatorCacheBalanceResult } from '../recoil/atoms' +import { useMemo } from 'react' +import { ValidatorCacheResults } from '../types/validator' + +const useFilteredValidatorCacheData = (indices?: string[]): ValidatorCacheResults | undefined => { + const validatorCacheData = useRecoilValue(validatorCacheBalanceResult) + + return useMemo(() => { + if (!validatorCacheData) return undefined + + if (!indices) return validatorCacheData + + return Object.keys(validatorCacheData) + .filter((key) => indices.includes(key)) + .reduce((obj, key: string) => { + return Object.assign(obj, { + [key]: validatorCacheData[Number(key)], + }) + }, {}) + }, [validatorCacheData, indices]) +} + +export default useFilteredValidatorCacheData From 27b324f311560a9856d9cb19da4c7c011f782b33 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Mon, 27 Mar 2023 21:23:43 +0200 Subject: [PATCH 07/20] fix: format validator cache atom to remove info key --- src/hooks/useFilteredValidatorCacheData.ts | 4 +- src/hooks/useValidatorCachePolling.ts | 7 +- src/hooks/useValidatorEpochBalance.ts | 4 +- src/mocks/validatorResults.ts | 150 ++++++++++----------- src/recoil/atoms.ts | 4 +- src/types/validator.ts | 8 +- 6 files changed, 87 insertions(+), 90 deletions(-) diff --git a/src/hooks/useFilteredValidatorCacheData.ts b/src/hooks/useFilteredValidatorCacheData.ts index 942097ba..13c4acc5 100644 --- a/src/hooks/useFilteredValidatorCacheData.ts +++ b/src/hooks/useFilteredValidatorCacheData.ts @@ -1,9 +1,9 @@ import { useRecoilValue } from 'recoil' import { validatorCacheBalanceResult } from '../recoil/atoms' import { useMemo } from 'react' -import { ValidatorCacheResults } from '../types/validator' +import { ValidatorCache } from '../types/validator' -const useFilteredValidatorCacheData = (indices?: string[]): ValidatorCacheResults | undefined => { +const useFilteredValidatorCacheData = (indices?: string[]): ValidatorCache | undefined => { const validatorCacheData = useRecoilValue(validatorCacheBalanceResult) return useMemo(() => { diff --git a/src/hooks/useValidatorCachePolling.ts b/src/hooks/useValidatorCachePolling.ts index 9be0e3ee..c241424c 100644 --- a/src/hooks/useValidatorCachePolling.ts +++ b/src/hooks/useValidatorCachePolling.ts @@ -4,6 +4,7 @@ import { beaconEpochInterval, validatorCacheBalanceResult } from '../recoil/atom import { selectActiveValidators } from '../recoil/selectors/selectActiveValidators' import usePollApi from './usePollApi' import { selectBeaconUrl } from '../recoil/selectors/selectBeaconUrl' +import { ValidatorCacheResults } from '../types/validator' const useValidatorCachePolling = () => { const beaconUrl = useRecoilValue(selectBeaconUrl) @@ -25,9 +26,11 @@ const useValidatorCachePolling = () => { }) useEffect(() => { - const data = response?.data.data.validators + const data = response?.data.data.validators as ValidatorCacheResults if (data) { - setValidatorCache(data) + setValidatorCache( + Object.fromEntries(Object.entries(data).map(([key, { info }]) => [Number(key), info])), + ) } }, [response]) diff --git a/src/hooks/useValidatorEpochBalance.ts b/src/hooks/useValidatorEpochBalance.ts index 61c33c75..2b4db6f3 100644 --- a/src/hooks/useValidatorEpochBalance.ts +++ b/src/hooks/useValidatorEpochBalance.ts @@ -17,7 +17,7 @@ const useValidatorEpochBalance = () => { return validatorCacheData && activeValidators.length && Object.values(validatorCacheData).length ? activeValidators .map(({ index, name }) => { - const data = validatorCacheData[index as any]?.info + const data = validatorCacheData[index as any] return { index, name, @@ -35,7 +35,7 @@ const useValidatorEpochBalance = () => { const formattedTimestamps = useMemo(() => { const data = validatorCacheData && Object.values(validatorCacheData)[0] return data - ? data.info.map(({ epoch }) => { + ? data.map(({ epoch }) => { const slot = epoch * slotsInEpoc return moment((genesisBlock + slot * secondsInSlot) * 1000).format('HH:mm') diff --git a/src/mocks/validatorResults.ts b/src/mocks/validatorResults.ts index a39b16aa..7a827b2d 100644 --- a/src/mocks/validatorResults.ts +++ b/src/mocks/validatorResults.ts @@ -34,86 +34,76 @@ export const mockActiveValidators = [ ] export const mockValidatorCacheResults = { - 0: { - info: [ - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - ], - }, - 1: { - info: [ - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - ], - }, - 2: { - info: [ - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - ], - }, - 3: { - info: [ - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - ], - }, - 4: { - info: [ - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - { - epoch: 12345678, - total_balance: 3200000000, - }, - ], - }, + 0: [ + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + ], + 1: [ + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + ], + 2: [ + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + ], + 3: [ + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + ], + 4: [ + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + { + epoch: 12345678, + total_balance: 3200000000, + }, + ], } export const mockValidatorInfo = { diff --git a/src/recoil/atoms.ts b/src/recoil/atoms.ts index 1564df91..1615582b 100644 --- a/src/recoil/atoms.ts +++ b/src/recoil/atoms.ts @@ -2,7 +2,7 @@ import { atom } from 'recoil' import { AppView, ContentView, OnboardView, SetupSteps, UiMode } from '../constants/enums' import { Endpoint } from '../types' import { BeaconSyncResult, HealthDiagnosticResult, ValidatorSyncResult } from '../types/diagnostic' -import { BeaconValidatorResult, ValidatorCacheResults } from '../types/validator' +import { BeaconValidatorResult, ValidatorCache } from '../types/validator' export const uiMode = atom({ key: 'UiMode', @@ -134,7 +134,7 @@ export const activeCurrency = atom({ default: undefined, }) -export const validatorCacheBalanceResult = atom({ +export const validatorCacheBalanceResult = atom({ key: 'validatorCacheBalanceResult', default: undefined, }) diff --git a/src/types/validator.ts b/src/types/validator.ts index 491c1e12..f50b42b0 100644 --- a/src/types/validator.ts +++ b/src/types/validator.ts @@ -76,13 +76,17 @@ export type FormattedValidatorCache = { } export type ValidatorCacheResults = { - [key: number]: ValidatorCacheData + [key: number]: ValidatorCacheDataInfo } -export type ValidatorCacheData = { +export type ValidatorCacheDataInfo = { info: ValidatorEpochResult[] } +export type ValidatorCache = { + [key: number]: ValidatorEpochResult[] +} + export type ValidatorEpochResult = { epoch: number total_balance: number From 2cb68e3039cea989ef0bc57c2b3c383d24b1294b Mon Sep 17 00:00:00 2001 From: Mavrik Date: Mon, 27 Mar 2023 21:28:17 +0200 Subject: [PATCH 08/20] feat: created a hook to calculate the estimated apr based on the rewards for the previous 10 epoch cache data --- src/hooks/useEpochAprEstimate.ts | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/hooks/useEpochAprEstimate.ts diff --git a/src/hooks/useEpochAprEstimate.ts b/src/hooks/useEpochAprEstimate.ts new file mode 100644 index 00000000..a6b0c707 --- /dev/null +++ b/src/hooks/useEpochAprEstimate.ts @@ -0,0 +1,60 @@ +import useFilteredValidatorCacheData from './useFilteredValidatorCacheData' +import { useMemo } from 'react' +import reduceAddNum from '../utilities/reduceAddNum' +import { formatUnits } from 'ethers/lib/utils' +import { secondsInDay, secondsInEpoch } from '../constants/constants' +import calculateAprPercentage from '../utilities/calculateAprPercentage' +import formatBalanceColor from '../utilities/formatBalanceColor' +import { TypographyColor } from '../components/Typography/Typography' + +const useEpochAprEstimate = (indices?: string[]) => { + const filteredValidatorCache = useFilteredValidatorCacheData(indices) + + const formattedCache = useMemo(() => { + if (!filteredValidatorCache) return + return Object.values(filteredValidatorCache).map((cache) => + cache.map(({ total_balance }) => total_balance), + ) + }, [filteredValidatorCache]) + + const isValidEpochCount = formattedCache?.every((subArr) => subArr.length > 0) + + if (!isValidEpochCount || !formattedCache) + return { + estimatedApr: undefined, + textColor: 'text-dark500' as TypographyColor, + } + + const totalInitialBalance = Number( + formatUnits( + formattedCache?.map((validator) => validator[0]).reduce(reduceAddNum, 0) as number, + 'gwei', + ), + ) + const totalCurrentBalance = Number( + formatUnits( + formattedCache + ?.map((validator) => validator[validator?.length - 1]) + .reduce(reduceAddNum, 0) as number, + 'gwei', + ), + ) + + const rewards = totalCurrentBalance - totalInitialBalance + const multiplier = (secondsInDay * 365) / secondsInEpoch / formattedCache[0].length + + const rewardsMultiplied = rewards * multiplier + + const projectedTotalBalance = rewardsMultiplied + totalCurrentBalance + + const estimatedApr = calculateAprPercentage(projectedTotalBalance, totalInitialBalance) + + const textColor = formatBalanceColor(estimatedApr) + + return { + estimatedApr, + textColor, + } +} + +export default useEpochAprEstimate From 3564ec3dd722b035c22bb8712b5cbec7ddc6f0a2 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Mon, 27 Mar 2023 21:29:18 +0200 Subject: [PATCH 09/20] fix: refactor components to use the estimateApr hook --- .../AccountEarnings/AccountEarning.tsx | 15 +++++++-------- .../ValidatorDetailTable.tsx | 16 +++++----------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/components/AccountEarnings/AccountEarning.tsx b/src/components/AccountEarnings/AccountEarning.tsx index d864ae34..9477ac19 100644 --- a/src/components/AccountEarnings/AccountEarning.tsx +++ b/src/components/AccountEarnings/AccountEarning.tsx @@ -10,12 +10,12 @@ import Spinner from '../Spinner/Spinner' import { useRecoilValue } from 'recoil' import { selectEthExchangeRates } from '../../recoil/selectors/selectEthExchangeRates' import EarningsLayout from './EarningsLayout' -import formatBalanceColor from '../../utilities/formatBalanceColor' import { selectCurrencyPrefix } from '../../recoil/selectors/selectCurrencyPrefix' import { activeCurrency } from '../../recoil/atoms' import CurrencySelect from '../CurrencySelect/CurrencySelect' import useEarningsEstimate from '../../hooks/useEarningsEstimate' import Tooltip from '../ToolTip/Tooltip' +import useEpochAprEstimate from '../../hooks/useEpochAprEstimate' export const AccountEarningFallback = () => { return ( @@ -28,11 +28,12 @@ export const AccountEarningFallback = () => { const AccountEarning = () => { const { t } = useTranslation() const currency = useRecoilValue(activeCurrency) - const { estimate, totalEarnings, annualizedEarningsPercent, estimateSelection, selectEstimate } = - useEarningsEstimate() + const { estimate, totalEarnings, estimateSelection, selectEstimate } = useEarningsEstimate() const { formattedPrefix } = useRecoilValue(selectCurrencyPrefix) const { rates } = useRecoilValue(selectEthExchangeRates) + const { estimatedApr, textColor } = useEpochAprEstimate() + const activeRate = rates[currency] const formattedRate = activeRate ? Number(activeRate) : 0 const totalBalance = formattedRate * totalEarnings @@ -40,8 +41,6 @@ const AccountEarning = () => { const isEstimate = estimateSelection !== undefined const timeFrame = isEstimate ? EARNINGS_OPTIONS[estimateSelection]?.title : undefined - const annualizedTextColor = formatBalanceColor(annualizedEarningsPercent) - const viewEarnings = async (value: number) => selectEstimate(value) return ( @@ -194,11 +193,11 @@ const AccountEarning = () => { - {annualizedEarningsPercent.toFixed(2)}% + {estimatedApr ? estimatedApr.toFixed(2) : '---'}%
diff --git a/src/components/ValidatorDetailTable/ValidatorDetailTable.tsx b/src/components/ValidatorDetailTable/ValidatorDetailTable.tsx index 5c64ad3a..ad848637 100644 --- a/src/components/ValidatorDetailTable/ValidatorDetailTable.tsx +++ b/src/components/ValidatorDetailTable/ValidatorDetailTable.tsx @@ -3,8 +3,7 @@ import { FC } from 'react' import { ValidatorInfo } from '../../types/validator' import formatBalanceColor from '../../utilities/formatBalanceColor' import { useTranslation } from 'react-i18next' -import calculateAprPercentage from '../../utilities/calculateAprPercentage' -import { initialEthDeposit } from '../../constants/constants' +import useEpochAprEstimate from '../../hooks/useEpochAprEstimate' export interface ValidatorDetailTableProps { validator: ValidatorInfo @@ -12,11 +11,10 @@ export interface ValidatorDetailTableProps { export const ValidatorDetailTable: FC = ({ validator }) => { const { t } = useTranslation() - const { balance } = validator + const { balance, index } = validator const income = balance ? balance - 32 : 0 const incomeColor = formatBalanceColor(income) - const aprPercentage = calculateAprPercentage(balance, initialEthDeposit) - const annualizedTextColor = formatBalanceColor(aprPercentage) + const { estimatedApr, textColor } = useEpochAprEstimate([String(index)]) return ( <>
@@ -177,12 +175,8 @@ export const ValidatorDetailTable: FC = ({ validator
- - {`${aprPercentage.toFixed(2)} %`} + + {`${estimatedApr ? estimatedApr.toFixed(2) : '---'} %`}
From c912c42724bfeda97862017172ac46ea1295ec2c Mon Sep 17 00:00:00 2001 From: Mavrik Date: Mon, 27 Mar 2023 21:35:05 +0200 Subject: [PATCH 10/20] fix: refactored to use filtered cache data hook --- src/hooks/useValidatorEarnings.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/hooks/useValidatorEarnings.ts b/src/hooks/useValidatorEarnings.ts index a8c3085b..8b2fedbc 100644 --- a/src/hooks/useValidatorEarnings.ts +++ b/src/hooks/useValidatorEarnings.ts @@ -8,27 +8,14 @@ import { secondsInWeek, } from '../constants/constants' import calculateEpochEstimate from '../utilities/calculateEpochEstimate' -import { validatorCacheBalanceResult } from '../recoil/atoms' import { selectValidatorInfos } from '../recoil/selectors/selectValidatorInfos' import calculateAprPercentage from '../utilities/calculateAprPercentage' +import useFilteredValidatorCacheData from './useFilteredValidatorCacheData' const useValidatorEarnings = (indices?: string[]) => { const validators = useRecoilValue(selectValidatorInfos) - const validatorCacheData = useRecoilValue(validatorCacheBalanceResult) - const filteredCacheData = useMemo(() => { - if (!validatorCacheData) return undefined - - if (!indices) return validatorCacheData - - return Object.keys(validatorCacheData) - .filter((key) => indices.includes(key)) - .reduce((obj, key: string) => { - return Object.assign(obj, { - [key]: validatorCacheData[Number(key)], - }) - }, {}) - }, [validatorCacheData, indices]) + const filteredCacheData = useFilteredValidatorCacheData(indices) const filteredValidators = useMemo(() => { return indices ? validators.filter(({ index }) => indices.includes(String(index))) : validators }, [validators, indices]) @@ -37,7 +24,6 @@ const useValidatorEarnings = (indices?: string[]) => { if (!filteredCacheData) return undefined return Object.values(filteredCacheData) - .map((cache) => cache.info) .flat() .reduce(function (r, a) { r[a.epoch] = r[a.epoch] || [] From fb6171423379667df924456ccf8accf4fb92fa9b Mon Sep 17 00:00:00 2001 From: Mavrik Date: Mon, 27 Mar 2023 21:35:26 +0200 Subject: [PATCH 11/20] fix: allow empty prop --- src/utilities/formatBalanceColor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utilities/formatBalanceColor.ts b/src/utilities/formatBalanceColor.ts index 6ac71edd..97c62b28 100644 --- a/src/utilities/formatBalanceColor.ts +++ b/src/utilities/formatBalanceColor.ts @@ -1,7 +1,7 @@ import { TypographyColor } from '../components/Typography/Typography' -const formatBalanceColor = (amount: number): TypographyColor => { - return amount === 0 ? 'text-dark500' : amount > 0 ? 'text-success' : 'text-error' +const formatBalanceColor = (amount?: number): TypographyColor => { + return amount === 0 || !amount ? 'text-dark500' : amount > 0 ? 'text-success' : 'text-error' } export default formatBalanceColor From 56a111ef0d25bb214230229d78f4f94ad0dc528c Mon Sep 17 00:00:00 2001 From: Mavrik Date: Mon, 27 Mar 2023 21:36:38 +0200 Subject: [PATCH 12/20] fix: removed uneeded math pow --- src/utilities/calculateAprPercentage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utilities/calculateAprPercentage.ts b/src/utilities/calculateAprPercentage.ts index fcd7068f..7ce02ea4 100644 --- a/src/utilities/calculateAprPercentage.ts +++ b/src/utilities/calculateAprPercentage.ts @@ -1,4 +1,4 @@ const calculateAprPercentage = (currentTotal: number, startingTotal: number) => - (Math.pow(currentTotal / startingTotal, 1) - 1) * 100 + (currentTotal / startingTotal - 1) * 100 export default calculateAprPercentage From bbbaba11cb864b39c32118e04adde89085d1e22c Mon Sep 17 00:00:00 2001 From: Mavrik Date: Mon, 27 Mar 2023 22:04:29 +0200 Subject: [PATCH 13/20] chore: removed uneeded map --- src/hooks/useEpochAprEstimate.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hooks/useEpochAprEstimate.ts b/src/hooks/useEpochAprEstimate.ts index a6b0c707..52c6762b 100644 --- a/src/hooks/useEpochAprEstimate.ts +++ b/src/hooks/useEpochAprEstimate.ts @@ -1,6 +1,5 @@ import useFilteredValidatorCacheData from './useFilteredValidatorCacheData' import { useMemo } from 'react' -import reduceAddNum from '../utilities/reduceAddNum' import { formatUnits } from 'ethers/lib/utils' import { secondsInDay, secondsInEpoch } from '../constants/constants' import calculateAprPercentage from '../utilities/calculateAprPercentage' @@ -27,15 +26,16 @@ const useEpochAprEstimate = (indices?: string[]) => { const totalInitialBalance = Number( formatUnits( - formattedCache?.map((validator) => validator[0]).reduce(reduceAddNum, 0) as number, + formattedCache.reduce((acc, validator) => acc + Number(validator[0]), 0) as number, 'gwei', ), ) const totalCurrentBalance = Number( formatUnits( - formattedCache - ?.map((validator) => validator[validator?.length - 1]) - .reduce(reduceAddNum, 0) as number, + formattedCache.reduce( + (acc, validator) => acc + Number(validator[validator?.length - 1]), + 0, + ) as number, 'gwei', ), ) From f48d0e9f993cb62da3a71d90b176e9fac6221002 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Mon, 27 Mar 2023 22:10:58 +0200 Subject: [PATCH 14/20] fix: add tooltip to entire apr estimate text and updated text --- .../AccountEarnings/AccountEarning.tsx | 16 ++++++++-------- src/locales/translations/en-US.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/AccountEarnings/AccountEarning.tsx b/src/components/AccountEarnings/AccountEarning.tsx index 9477ac19..378cdd1b 100644 --- a/src/components/AccountEarnings/AccountEarning.tsx +++ b/src/components/AccountEarnings/AccountEarning.tsx @@ -190,15 +190,15 @@ const AccountEarning = () => { + + {estimatedApr ? estimatedApr.toFixed(2) : '---'}% + - - {estimatedApr ? estimatedApr.toFixed(2) : '---'}% - diff --git a/src/locales/translations/en-US.json b/src/locales/translations/en-US.json index 26f0f5af..596d7fbd 100644 --- a/src/locales/translations/en-US.json +++ b/src/locales/translations/en-US.json @@ -308,7 +308,7 @@ "ethTotal": "Total ETH earnings of all validators", "fiatEstimate": "Estimated {{time}} earnings converted to selected fiat currency exchange rate.", "fiatTotal": "Total earnings converted to selected fiat currency exchange rate.", - "annualApr": "Combined total Annual Percentage Rate." + "annualApr": "Combined total Annual Percentage Rate estimate." }, "networkErrorModal": { "title": "Network Error", From 82a5934c7909069b0a59b9635ff4252ce0bcf09f Mon Sep 17 00:00:00 2001 From: Mavrik Date: Tue, 28 Mar 2023 11:53:10 +0200 Subject: [PATCH 15/20] fix: use intial balance instead of current for projected --- src/hooks/useEpochAprEstimate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useEpochAprEstimate.ts b/src/hooks/useEpochAprEstimate.ts index 52c6762b..ae142c7d 100644 --- a/src/hooks/useEpochAprEstimate.ts +++ b/src/hooks/useEpochAprEstimate.ts @@ -45,7 +45,7 @@ const useEpochAprEstimate = (indices?: string[]) => { const rewardsMultiplied = rewards * multiplier - const projectedTotalBalance = rewardsMultiplied + totalCurrentBalance + const projectedTotalBalance = rewardsMultiplied + totalInitialBalance const estimatedApr = calculateAprPercentage(projectedTotalBalance, totalInitialBalance) From db48b9d237adba15de865879c5960200c3152981 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Tue, 28 Mar 2023 16:26:56 +0200 Subject: [PATCH 16/20] fix: updated hook to account for partial eth deposits --- src/hooks/useEpochAprEstimate.ts | 60 +++++++++++++++----------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/src/hooks/useEpochAprEstimate.ts b/src/hooks/useEpochAprEstimate.ts index ae142c7d..159a73dc 100644 --- a/src/hooks/useEpochAprEstimate.ts +++ b/src/hooks/useEpochAprEstimate.ts @@ -4,7 +4,7 @@ import { formatUnits } from 'ethers/lib/utils' import { secondsInDay, secondsInEpoch } from '../constants/constants' import calculateAprPercentage from '../utilities/calculateAprPercentage' import formatBalanceColor from '../utilities/formatBalanceColor' -import { TypographyColor } from '../components/Typography/Typography' +import reduceAddNum from '../utilities/reduceAddNum' const useEpochAprEstimate = (indices?: string[]) => { const filteredValidatorCache = useFilteredValidatorCacheData(indices) @@ -18,43 +18,39 @@ const useEpochAprEstimate = (indices?: string[]) => { const isValidEpochCount = formattedCache?.every((subArr) => subArr.length > 0) - if (!isValidEpochCount || !formattedCache) - return { - estimatedApr: undefined, - textColor: 'text-dark500' as TypographyColor, - } - - const totalInitialBalance = Number( - formatUnits( - formattedCache.reduce((acc, validator) => acc + Number(validator[0]), 0) as number, - 'gwei', - ), - ) - const totalCurrentBalance = Number( - formatUnits( - formattedCache.reduce( - (acc, validator) => acc + Number(validator[validator?.length - 1]), - 0, - ) as number, - 'gwei', - ), - ) + const formatForWithdrawal = (arr: number[]) => { + const foundIndex = arr.findIndex((value) => value > 32 && value < 32.001) + return foundIndex === -1 ? arr : [arr[foundIndex], ...arr.slice(foundIndex + 1)] + } - const rewards = totalCurrentBalance - totalInitialBalance - const multiplier = (secondsInDay * 365) / secondsInEpoch / formattedCache[0].length + const mappedTotalApr = useMemo(() => { + return formattedCache?.map((cache) => { + const formattedValues = cache.map((value) => Number(formatUnits(value, 'gwei'))) + const formattedCache = formatForWithdrawal(formattedValues) - const rewardsMultiplied = rewards * multiplier + const initialBalance = formattedCache[0] + const currentBalance = formattedCache[formattedCache.length - 1] + const rewards = currentBalance - initialBalance + const multiplier = (secondsInDay * 365) / secondsInEpoch / formattedCache.length - const projectedTotalBalance = rewardsMultiplied + totalInitialBalance + const rewardsMultiplied = rewards * multiplier + const projectedBalance = rewardsMultiplied + initialBalance - const estimatedApr = calculateAprPercentage(projectedTotalBalance, totalInitialBalance) + return calculateAprPercentage(projectedBalance, initialBalance) + }) + }, [formattedCache]) - const textColor = formatBalanceColor(estimatedApr) + return useMemo(() => { + const estimatedApr = mappedTotalApr + ? mappedTotalApr.reduce(reduceAddNum, 0) / mappedTotalApr.length + : undefined + const textColor = formatBalanceColor(estimatedApr) - return { - estimatedApr, - textColor, - } + return { + estimatedApr, + textColor, + } + }, [mappedTotalApr, isValidEpochCount]) } export default useEpochAprEstimate From ebc85c4d11978566aecc87d652bc7dc9233e2302 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 29 Mar 2023 06:26:06 +0200 Subject: [PATCH 17/20] fix: variable name change and unit test created --- .../__tests__/useEpochAprEstimate.spec.ts | 54 +++++++++++++ src/hooks/useEpochAprEstimate.ts | 18 ++--- src/mocks/validatorResults.ts | 81 +++++++++++++++++++ 3 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 src/hooks/__tests__/useEpochAprEstimate.spec.ts diff --git a/src/hooks/__tests__/useEpochAprEstimate.spec.ts b/src/hooks/__tests__/useEpochAprEstimate.spec.ts new file mode 100644 index 00000000..bc4ac6fc --- /dev/null +++ b/src/hooks/__tests__/useEpochAprEstimate.spec.ts @@ -0,0 +1,54 @@ +import useEpochAprEstimate from '../useEpochAprEstimate' +import { renderHook } from '@testing-library/react-hooks' +import { mockedRecoilValue } from '../../../test.helpers' +import { formatUnits } from 'ethers/lib/utils' +import { + mockValidatorCache, + mockedWithdrawalCash, + mockedWithdrawalCashLoss, +} from '../../mocks/validatorResults' + +jest.mock('ethers/lib/utils', () => ({ + formatUnits: jest.fn(), +})) + +const mockedFormatUnits = formatUnits as jest.MockedFn + +describe('useEpochAprEstimate hook', () => { + it('should return default values', () => { + const { result } = renderHook(() => useEpochAprEstimate()) + expect(result.current).toStrictEqual({ + estimatedApr: undefined, + textColor: 'text-dark500', + }) + }) + it('should return correct values', () => { + mockedRecoilValue.mockReturnValue(mockValidatorCache) + mockedFormatUnits.mockImplementation((value) => value.toString()) + const { result } = renderHook(() => useEpochAprEstimate()) + expect(result.current).toStrictEqual({ + estimatedApr: 1.3438636363304557, + textColor: 'text-success', + }) + }) + + it('should return correct when there is a withdrawal value', () => { + mockedRecoilValue.mockReturnValue(mockedWithdrawalCash) + mockedFormatUnits.mockImplementation((value) => value.toString()) + const { result } = renderHook(() => useEpochAprEstimate()) + expect(result.current).toStrictEqual({ + estimatedApr: 3.8495973450145105, + textColor: 'text-success', + }) + }) + + it('should return correct when there is a withdrawal values at a loss', () => { + mockedRecoilValue.mockReturnValue(mockedWithdrawalCashLoss) + mockedFormatUnits.mockImplementation((value) => value.toString()) + const { result } = renderHook(() => useEpochAprEstimate()) + expect(result.current).toStrictEqual({ + estimatedApr: -0.1710932155095768, + textColor: 'text-error', + }) + }) +}) diff --git a/src/hooks/useEpochAprEstimate.ts b/src/hooks/useEpochAprEstimate.ts index 159a73dc..9b0ff181 100644 --- a/src/hooks/useEpochAprEstimate.ts +++ b/src/hooks/useEpochAprEstimate.ts @@ -4,7 +4,6 @@ import { formatUnits } from 'ethers/lib/utils' import { secondsInDay, secondsInEpoch } from '../constants/constants' import calculateAprPercentage from '../utilities/calculateAprPercentage' import formatBalanceColor from '../utilities/formatBalanceColor' -import reduceAddNum from '../utilities/reduceAddNum' const useEpochAprEstimate = (indices?: string[]) => { const filteredValidatorCache = useFilteredValidatorCacheData(indices) @@ -16,7 +15,7 @@ const useEpochAprEstimate = (indices?: string[]) => { ) }, [filteredValidatorCache]) - const isValidEpochCount = formattedCache?.every((subArr) => subArr.length > 0) + const isValidEpochCount = formattedCache?.every((subArr) => subArr.length > 1) const formatForWithdrawal = (arr: number[]) => { const foundIndex = arr.findIndex((value) => value > 32 && value < 32.001) @@ -26,12 +25,12 @@ const useEpochAprEstimate = (indices?: string[]) => { const mappedTotalApr = useMemo(() => { return formattedCache?.map((cache) => { const formattedValues = cache.map((value) => Number(formatUnits(value, 'gwei'))) - const formattedCache = formatForWithdrawal(formattedValues) + const formattedWithdrawalCache = formatForWithdrawal(formattedValues) - const initialBalance = formattedCache[0] - const currentBalance = formattedCache[formattedCache.length - 1] + const initialBalance = formattedWithdrawalCache[0] + const currentBalance = formattedWithdrawalCache[formattedWithdrawalCache.length - 1] const rewards = currentBalance - initialBalance - const multiplier = (secondsInDay * 365) / secondsInEpoch / formattedCache.length + const multiplier = (secondsInDay * 365) / secondsInEpoch / formattedWithdrawalCache.length const rewardsMultiplied = rewards * multiplier const projectedBalance = rewardsMultiplied + initialBalance @@ -41,9 +40,10 @@ const useEpochAprEstimate = (indices?: string[]) => { }, [formattedCache]) return useMemo(() => { - const estimatedApr = mappedTotalApr - ? mappedTotalApr.reduce(reduceAddNum, 0) / mappedTotalApr.length - : undefined + const estimatedApr = + mappedTotalApr && isValidEpochCount + ? mappedTotalApr.reduce((acc, a) => acc + a, 0) / mappedTotalApr.length + : undefined const textColor = formatBalanceColor(estimatedApr) return { diff --git a/src/mocks/validatorResults.ts b/src/mocks/validatorResults.ts index 7a827b2d..f517c6d7 100644 --- a/src/mocks/validatorResults.ts +++ b/src/mocks/validatorResults.ts @@ -106,6 +106,87 @@ export const mockValidatorCacheResults = { ], } +export const mockValidatorCache = { + 1234567: [ + { epoch: '12345678', total_balance: 33 }, + { epoch: '12345679', total_balance: 33.00002 }, + { epoch: '12345679', total_balance: 33.000025 }, + { epoch: '12345679', total_balance: 33.00003 }, + { epoch: '12345679', total_balance: 33.00004 }, + { epoch: '12345679', total_balance: 33.000045 }, + { epoch: '12345679', total_balance: 33.000046 }, + { epoch: '12345679', total_balance: 33.000047 }, + { epoch: '12345679', total_balance: 33.00005 }, + { epoch: '12345679', total_balance: 33.000054 }, + ], + 1234568: [ + { epoch: '12345678', total_balance: 33 }, + { epoch: '12345679', total_balance: 33.00002 }, + { epoch: '12345679', total_balance: 33.000025 }, + { epoch: '12345679', total_balance: 33.00003 }, + { epoch: '12345679', total_balance: 33.00004 }, + { epoch: '12345679', total_balance: 33.000045 }, + { epoch: '12345679', total_balance: 33.000046 }, + { epoch: '12345679', total_balance: 33.000047 }, + { epoch: '12345679', total_balance: 33.00005 }, + { epoch: '12345679', total_balance: 33.000054 }, + ], +} + +export const mockedWithdrawalCash = { + 1234567: [ + { epoch: '12345678', total_balance: 33 }, + { epoch: '12345679', total_balance: 33.00002 }, + { epoch: '12345679', total_balance: 33.000025 }, + { epoch: '12345679', total_balance: 33.00003 }, + { epoch: '12345679', total_balance: 32.0001 }, + { epoch: '12345679', total_balance: 32.00015 }, + { epoch: '12345679', total_balance: 32.00016 }, + { epoch: '12345679', total_balance: 32.00017 }, + { epoch: '12345679', total_balance: 32.00018 }, + { epoch: '12345679', total_balance: 32.00019 }, + ], + 1234568: [ + { epoch: '12345678', total_balance: 33 }, + { epoch: '12345679', total_balance: 33.00002 }, + { epoch: '12345679', total_balance: 33.000025 }, + { epoch: '12345679', total_balance: 33.00003 }, + { epoch: '12345679', total_balance: 32.0001 }, + { epoch: '12345679', total_balance: 32.00015 }, + { epoch: '12345679', total_balance: 32.00016 }, + { epoch: '12345679', total_balance: 32.00017 }, + { epoch: '12345679', total_balance: 32.00018 }, + { epoch: '12345679', total_balance: 32.00019 }, + ], +} + +export const mockedWithdrawalCashLoss = { + 1234567: [ + { epoch: '12345678', total_balance: 33 }, + { epoch: '12345679', total_balance: 33.00002 }, + { epoch: '12345679', total_balance: 33.000025 }, + { epoch: '12345679', total_balance: 33.00003 }, + { epoch: '12345679', total_balance: 32.0001 }, + { epoch: '12345679', total_balance: 32.000092 }, + { epoch: '12345679', total_balance: 32.000093 }, + { epoch: '12345679', total_balance: 32.000094 }, + { epoch: '12345679', total_balance: 32.000095 }, + { epoch: '12345679', total_balance: 32.000096 }, + ], + 1234568: [ + { epoch: '12345678', total_balance: 33 }, + { epoch: '12345679', total_balance: 33.00002 }, + { epoch: '12345679', total_balance: 33.000025 }, + { epoch: '12345679', total_balance: 33.00003 }, + { epoch: '12345679', total_balance: 32.0001 }, + { epoch: '12345679', total_balance: 32.000092 }, + { epoch: '12345679', total_balance: 32.000093 }, + { epoch: '12345679', total_balance: 32.000094 }, + { epoch: '12345679', total_balance: 32.000095 }, + { epoch: '12345679', total_balance: 32.000096 }, + ], +} + export const mockValidatorInfo = { name: 'mock-validator', balance: 32000000, From a79a2355c652d83ec38917f86c396f3e7b664226 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 29 Mar 2023 06:57:58 +0200 Subject: [PATCH 18/20] chore: updated and added new unit tests for useEpochAprEstimate --- .../__tests__/useEpochAprEstimate.spec.ts | 25 +++++++++++++-- src/mocks/validatorResults.ts | 32 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/hooks/__tests__/useEpochAprEstimate.spec.ts b/src/hooks/__tests__/useEpochAprEstimate.spec.ts index bc4ac6fc..dcb0a2f4 100644 --- a/src/hooks/__tests__/useEpochAprEstimate.spec.ts +++ b/src/hooks/__tests__/useEpochAprEstimate.spec.ts @@ -6,6 +6,8 @@ import { mockValidatorCache, mockedWithdrawalCash, mockedWithdrawalCashLoss, + mockShortValidatorCache, + mockedRecentWithdrawalCash, } from '../../mocks/validatorResults' jest.mock('ethers/lib/utils', () => ({ @@ -15,6 +17,9 @@ jest.mock('ethers/lib/utils', () => ({ const mockedFormatUnits = formatUnits as jest.MockedFn describe('useEpochAprEstimate hook', () => { + beforeEach(() => { + mockedFormatUnits.mockImplementation((value) => value.toString()) + }) it('should return default values', () => { const { result } = renderHook(() => useEpochAprEstimate()) expect(result.current).toStrictEqual({ @@ -22,9 +27,16 @@ describe('useEpochAprEstimate hook', () => { textColor: 'text-dark500', }) }) + it('should return default values when not enough epoch data', () => { + mockedRecoilValue.mockReturnValue(mockShortValidatorCache) + const { result } = renderHook(() => useEpochAprEstimate()) + expect(result.current).toStrictEqual({ + estimatedApr: undefined, + textColor: 'text-dark500', + }) + }) it('should return correct values', () => { mockedRecoilValue.mockReturnValue(mockValidatorCache) - mockedFormatUnits.mockImplementation((value) => value.toString()) const { result } = renderHook(() => useEpochAprEstimate()) expect(result.current).toStrictEqual({ estimatedApr: 1.3438636363304557, @@ -34,7 +46,6 @@ describe('useEpochAprEstimate hook', () => { it('should return correct when there is a withdrawal value', () => { mockedRecoilValue.mockReturnValue(mockedWithdrawalCash) - mockedFormatUnits.mockImplementation((value) => value.toString()) const { result } = renderHook(() => useEpochAprEstimate()) expect(result.current).toStrictEqual({ estimatedApr: 3.8495973450145105, @@ -44,11 +55,19 @@ describe('useEpochAprEstimate hook', () => { it('should return correct when there is a withdrawal values at a loss', () => { mockedRecoilValue.mockReturnValue(mockedWithdrawalCashLoss) - mockedFormatUnits.mockImplementation((value) => value.toString()) const { result } = renderHook(() => useEpochAprEstimate()) expect(result.current).toStrictEqual({ estimatedApr: -0.1710932155095768, textColor: 'text-error', }) }) + + it('should return correct values when last epoch was a withdrawal', () => { + mockedRecoilValue.mockReturnValue(mockedRecentWithdrawalCash) + const { result } = renderHook(() => useEpochAprEstimate()) + expect(result.current).toStrictEqual({ + estimatedApr: 0, + textColor: 'text-dark500', + }) + }) }) diff --git a/src/mocks/validatorResults.ts b/src/mocks/validatorResults.ts index f517c6d7..1740f75b 100644 --- a/src/mocks/validatorResults.ts +++ b/src/mocks/validatorResults.ts @@ -133,6 +133,11 @@ export const mockValidatorCache = { ], } +export const mockShortValidatorCache = { + 1234567: [{ epoch: '12345678', total_balance: 32 }], + 1234568: [{ epoch: '12345678', total_balance: 32 }], +} + export const mockedWithdrawalCash = { 1234567: [ { epoch: '12345678', total_balance: 33 }, @@ -160,6 +165,33 @@ export const mockedWithdrawalCash = { ], } +export const mockedRecentWithdrawalCash = { + 1234567: [ + { epoch: '12345678', total_balance: 33 }, + { epoch: '12345679', total_balance: 33.00002 }, + { epoch: '12345679', total_balance: 33.000025 }, + { epoch: '12345679', total_balance: 33.00003 }, + { epoch: '12345679', total_balance: 33.00015 }, + { epoch: '12345679', total_balance: 33.00016 }, + { epoch: '12345679', total_balance: 33.00017 }, + { epoch: '12345679', total_balance: 33.00018 }, + { epoch: '12345679', total_balance: 33.00019 }, + { epoch: '12345679', total_balance: 32.0001 }, + ], + 1234568: [ + { epoch: '12345678', total_balance: 33 }, + { epoch: '12345679', total_balance: 33.00002 }, + { epoch: '12345679', total_balance: 33.000025 }, + { epoch: '12345679', total_balance: 33.00003 }, + { epoch: '12345679', total_balance: 33.00015 }, + { epoch: '12345679', total_balance: 33.00016 }, + { epoch: '12345679', total_balance: 33.00017 }, + { epoch: '12345679', total_balance: 33.00018 }, + { epoch: '12345679', total_balance: 33.00019 }, + { epoch: '12345679', total_balance: 32.0001 }, + ], +} + export const mockedWithdrawalCashLoss = { 1234567: [ { epoch: '12345678', total_balance: 33 }, From 707057cbaeae2a06d771bf553701d718cc0396aa Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 29 Mar 2023 11:22:39 +0200 Subject: [PATCH 19/20] chore: added test for index param --- src/hooks/__tests__/useEpochAprEstimate.spec.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/hooks/__tests__/useEpochAprEstimate.spec.ts b/src/hooks/__tests__/useEpochAprEstimate.spec.ts index dcb0a2f4..8c053147 100644 --- a/src/hooks/__tests__/useEpochAprEstimate.spec.ts +++ b/src/hooks/__tests__/useEpochAprEstimate.spec.ts @@ -44,6 +44,15 @@ describe('useEpochAprEstimate hook', () => { }) }) + it('should return correct values when provided an array of indexes', () => { + mockedRecoilValue.mockReturnValue(mockValidatorCache) + const { result } = renderHook(() => useEpochAprEstimate(['1234567'])) + expect(result.current).toStrictEqual({ + estimatedApr: 1.3438636363304557, + textColor: 'text-success', + }) + }) + it('should return correct when there is a withdrawal value', () => { mockedRecoilValue.mockReturnValue(mockedWithdrawalCash) const { result } = renderHook(() => useEpochAprEstimate()) From 411deca9f93e4c3f0215ad72f4d7230bd3812db7 Mon Sep 17 00:00:00 2001 From: Mavrik Date: Wed, 29 Mar 2023 12:19:44 +0200 Subject: [PATCH 20/20] chore: added unit test for validatorCacheData filter --- .../useFilteredValidatorCacheData.spec.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/hooks/__tests__/useFilteredValidatorCacheData.spec.ts diff --git a/src/hooks/__tests__/useFilteredValidatorCacheData.spec.ts b/src/hooks/__tests__/useFilteredValidatorCacheData.spec.ts new file mode 100644 index 00000000..bc4dd7b5 --- /dev/null +++ b/src/hooks/__tests__/useFilteredValidatorCacheData.spec.ts @@ -0,0 +1,32 @@ +import { renderHook } from '@testing-library/react-hooks' +import useFilteredValidatorCacheData from '../useFilteredValidatorCacheData' +import { mockedRecoilValue } from '../../../test.helpers' +import { mockValidatorCache } from '../../mocks/validatorResults' +import clearAllMocks = jest.clearAllMocks + +describe('useFilteredValidatorCacheData hook', () => { + beforeEach(() => { + clearAllMocks() + }) + + it('should return undefined if no validator cache data', () => { + mockedRecoilValue.mockReturnValue(undefined) + const { result } = renderHook(() => useFilteredValidatorCacheData()) + + expect(result.current).toBe(undefined) + }) + + it('should return unfiltered data when no provided indices', () => { + mockedRecoilValue.mockReturnValue(mockValidatorCache) + const { result } = renderHook(() => useFilteredValidatorCacheData()) + + expect(result.current).toStrictEqual(mockValidatorCache) + }) + + it('should return filtered data', () => { + mockedRecoilValue.mockReturnValue(mockValidatorCache) + const { result } = renderHook(() => useFilteredValidatorCacheData(['1234567'])) + + expect(result.current).toStrictEqual({ '1234567': mockValidatorCache['1234567'] }) + }) +})