From e4305d635ad93b65b56982ed3f66063bdab12ac6 Mon Sep 17 00:00:00 2001 From: David Totrashvili Date: Sun, 20 Oct 2024 13:08:23 +0500 Subject: [PATCH] feat: refactor system stats and personal balance sections (#226) * fix: refactor system stats section * feat: static UI for balance section --- .../components/Delegations/Delegations.tsx | 2 +- .../components/Modals/UnbondWithdrawModal.tsx | 2 +- .../PersonalBalance/BalanceItem.tsx | 53 +++ .../PersonalBalance/PersonalBalance.tsx | 45 +++ src/app/components/Stats/StatItem.tsx | 51 +++ src/app/components/Stats/Stats.tsx | 308 ++++++------------ .../components/Stats/icons/confirmed-tvl.svg | 3 - .../components/Stats/icons/delegations.svg | 3 - src/app/components/Stats/icons/index.tsx | 77 +++++ .../components/Stats/icons/pending-stake.svg | 3 - src/app/components/Stats/icons/stakers.svg | 5 - .../Stats/icons/staking-tvl-cap.svg | 3 - src/app/hooks/{ => api}/useApi.ts | 26 +- src/app/hooks/{ => api}/useBTCTipHeight.ts | 2 +- src/app/hooks/{ => api}/useDelegations.ts | 0 src/app/hooks/{ => api}/useNetworkFees.ts | 2 +- src/app/hooks/api/useSystemStats.ts | 23 ++ src/app/hooks/{ => api}/useUTXOs.ts | 2 +- src/app/hooks/api/useVersions.ts | 14 + src/app/hooks/useVersionByHeight.ts | 14 + src/app/hooks/useVersions.ts | 25 -- src/app/page.tsx | 4 +- src/app/state/DelegationState.tsx | 2 +- src/app/state/index.tsx | 8 +- 24 files changed, 405 insertions(+), 272 deletions(-) create mode 100644 src/app/components/PersonalBalance/BalanceItem.tsx create mode 100644 src/app/components/PersonalBalance/PersonalBalance.tsx create mode 100644 src/app/components/Stats/StatItem.tsx delete mode 100644 src/app/components/Stats/icons/confirmed-tvl.svg delete mode 100644 src/app/components/Stats/icons/delegations.svg create mode 100644 src/app/components/Stats/icons/index.tsx delete mode 100644 src/app/components/Stats/icons/pending-stake.svg delete mode 100644 src/app/components/Stats/icons/stakers.svg delete mode 100644 src/app/components/Stats/icons/staking-tvl-cap.svg rename src/app/hooks/{ => api}/useApi.ts (58%) rename src/app/hooks/{ => api}/useBTCTipHeight.ts (81%) rename src/app/hooks/{ => api}/useDelegations.ts (100%) rename src/app/hooks/{ => api}/useNetworkFees.ts (85%) create mode 100644 src/app/hooks/api/useSystemStats.ts rename src/app/hooks/{ => api}/useUTXOs.ts (94%) create mode 100644 src/app/hooks/api/useVersions.ts create mode 100644 src/app/hooks/useVersionByHeight.ts delete mode 100644 src/app/hooks/useVersions.ts diff --git a/src/app/components/Delegations/Delegations.tsx b/src/app/components/Delegations/Delegations.tsx index ec63ad41..b2499d61 100644 --- a/src/app/components/Delegations/Delegations.tsx +++ b/src/app/components/Delegations/Delegations.tsx @@ -11,7 +11,7 @@ import { LoadingTableList } from "@/app/components/Loading/Loading"; import { DelegationsPointsProvider } from "@/app/context/api/DelegationsPointsProvider"; import { useError } from "@/app/context/Error/ErrorContext"; import { useWallet } from "@/app/context/wallet/WalletProvider"; -import { useDelegations } from "@/app/hooks/useDelegations"; +import { useDelegations } from "@/app/hooks/api/useDelegations"; import { useHealthCheck } from "@/app/hooks/useHealthCheck"; import { useAppState } from "@/app/state"; import { useDelegationState } from "@/app/state/DelegationState"; diff --git a/src/app/components/Modals/UnbondWithdrawModal.tsx b/src/app/components/Modals/UnbondWithdrawModal.tsx index e4069f03..9f3e65b3 100644 --- a/src/app/components/Modals/UnbondWithdrawModal.tsx +++ b/src/app/components/Modals/UnbondWithdrawModal.tsx @@ -1,6 +1,6 @@ import { IoMdClose } from "react-icons/io"; -import { useVersionByHeight } from "@/app/hooks/useVersions"; +import { useVersionByHeight } from "@/app/hooks/useVersionByHeight"; import { Delegation as DelegationInterface } from "@/app/types/delegations"; import { getNetworkConfig } from "@/config/network.config"; import { blocksToDisplayTime } from "@/utils/blocksToDisplayTime"; diff --git a/src/app/components/PersonalBalance/BalanceItem.tsx b/src/app/components/PersonalBalance/BalanceItem.tsx new file mode 100644 index 00000000..67e872b7 --- /dev/null +++ b/src/app/components/PersonalBalance/BalanceItem.tsx @@ -0,0 +1,53 @@ +import { useId } from "react"; +import { AiOutlineInfoCircle } from "react-icons/ai"; +import { Tooltip } from "react-tooltip"; +import { twMerge } from "tailwind-merge"; + +interface BalanceItemProps { + className?: string; + label: string; + value: string | JSX.Element; + tooltip?: string; +} + +export function BalanceItem({ + className, + label, + value, + tooltip, +}: BalanceItemProps) { + const tooltipId = useId(); + + return ( +
+
+

{label}:

+ {tooltip && ( + <> + + + + + + )} +
+ {typeof value === "string" ? ( +
+ {value} +
+ ) : ( + value + )} +
+ ); +} diff --git a/src/app/components/PersonalBalance/PersonalBalance.tsx b/src/app/components/PersonalBalance/PersonalBalance.tsx new file mode 100644 index 00000000..0193abcf --- /dev/null +++ b/src/app/components/PersonalBalance/PersonalBalance.tsx @@ -0,0 +1,45 @@ +import { BalanceItem } from "./BalanceItem"; + +export function PersonalBalance() { + return ( +
+
+

Bitcoin Balance

+ +
+ + +
+ + +
+
+ +
+

+ Babylon Balance +

+ +
+ + +
+ + + 0.134 BBN + + } + /> +
+
+
+ ); +} diff --git a/src/app/components/Stats/StatItem.tsx b/src/app/components/Stats/StatItem.tsx new file mode 100644 index 00000000..62a7d001 --- /dev/null +++ b/src/app/components/Stats/StatItem.tsx @@ -0,0 +1,51 @@ +import { type JSX } from "react"; +import { AiOutlineInfoCircle } from "react-icons/ai"; +import { Tooltip } from "react-tooltip"; + +interface StatItemProps { + loading?: boolean; + icon: JSX.Element; + title: string; + value: string | number; + tooltip?: string; +} + +export const StatItem = ({ + loading, + icon, + title, + value, + tooltip, +}: StatItemProps) => ( +
+
+ {icon} +
+

{title}

+ {tooltip && ( + <> + + + + + + )} +
+
+ +
+

+ {loading ? ( + + ) : ( + {value} + )} +

+
+
+); diff --git a/src/app/components/Stats/Stats.tsx b/src/app/components/Stats/Stats.tsx index 39b28348..ac05bd09 100644 --- a/src/app/components/Stats/Stats.tsx +++ b/src/app/components/Stats/Stats.tsx @@ -1,224 +1,102 @@ -import Image from "next/image"; -import { Fragment, useEffect, useMemo, useState } from "react"; -import { AiOutlineInfoCircle } from "react-icons/ai"; -import { Tooltip } from "react-tooltip"; +import { memo } from "react"; -import { - StakingStats, - useStakingStats, -} from "@/app/context/api/StakingStatsProvider"; -import { useAppState } from "@/app/state"; -import { GlobalParamsVersion } from "@/app/types/globalParams"; +import { useSystemStats } from "@/app/hooks/api/useSystemStats"; import { getNetworkConfig } from "@/config/network.config"; import { satoshiToBtc } from "@/utils/btcConversions"; -import { ParamsWithContext } from "@/utils/globalParams"; import { maxDecimals } from "@/utils/maxDecimals"; -import confirmedTvl from "./icons/confirmed-tvl.svg"; -import delegations from "./icons/delegations.svg"; -import pendingStake from "./icons/pending-stake.svg"; -import stakers from "./icons/stakers.svg"; -import stakingTvlCap from "./icons/staking-tvl-cap.svg"; - -const buildNextCapText = ( - coinName: string, - btcHeight: number, - nextVersion: GlobalParamsVersion, -) => { - const { stakingCapHeight, stakingCapSat, activationHeight } = nextVersion; - if (stakingCapHeight) { - const remainingBlocks = activationHeight - btcHeight - 1; - return { - title: "Staking Window", - value: `opens in ${remainingBlocks} ${remainingBlocks == 1 ? "block" : "blocks"}`, - }; - } else if (stakingCapSat) { - return { - title: "Next Staking TVL Cap", - value: `${maxDecimals(satoshiToBtc(stakingCapSat), 8)} ${coinName}`, - }; - } -}; - -const buildStakingCapSection = ( - coinName: string, - btcHeight: number, - paramsCtx: ParamsWithContext, -) => { - const { currentVersion, nextVersion, isApprochingNextVersion } = paramsCtx; - if (!currentVersion) { - return; - } - if (isApprochingNextVersion && nextVersion) { - return buildNextCapText(coinName, btcHeight, nextVersion); - } - const { stakingCapHeight, stakingCapSat } = currentVersion; - if (stakingCapHeight) { - const numOfBlockLeft = stakingCapHeight - btcHeight; - return { - title: "Staking Window", - value: - numOfBlockLeft > 0 - ? `closes in ${numOfBlockLeft} ${numOfBlockLeft == 1 ? "block" : "blocks"}` - : "closed", - }; - } else if (stakingCapSat) { - return { - title: "Staking TVL Cap", - value: `${maxDecimals(satoshiToBtc(stakingCapSat), 8)} ${coinName}`, - }; - } -}; - -export const Stats: React.FC = () => { - const [stakingStats, setStakingStats] = useState({ - activeTVLSat: 0, - totalTVLSat: 0, - activeDelegations: 0, - totalDelegations: 0, - totalStakers: 0, - unconfirmedTVLSat: 0, - }); - const [isLoading, setIsLoading] = useState(true); - const stakingStatsProvider = useStakingStats(); - const appState = useAppState(); - - const { coinName } = getNetworkConfig(); - - // Load the data from staking stats provider - useEffect(() => { - if (stakingStatsProvider.data) { - setStakingStats(stakingStatsProvider.data); - } - setIsLoading( - stakingStatsProvider.isLoading || Boolean(appState?.isLoading), - ); - }, [stakingStatsProvider, appState?.isLoading]); - - const stakingCapText = useMemo(() => { - if (!appState?.currentHeight) { - return { - title: "Staking TVL Cap", - value: "-", - }; - } - - const cap = buildStakingCapSection( - coinName, - appState.currentHeight, - appState, - ); - - return ( - cap ?? { - title: "Staking TVL Cap", - value: "-", - } - ); - }, [coinName, appState]); - - const formatter = Intl.NumberFormat("en", { - notation: "compact", - maximumFractionDigits: 2, - }); - - const sections = [ - [ - { - title: stakingCapText.title, - value: stakingCapText.value, - icon: stakingTvlCap, - }, - { - title: "Confirmed TVL", - value: stakingStats?.activeTVLSat - ? `${maxDecimals(satoshiToBtc(stakingStats.activeTVLSat), 8)} ${coinName}` - : 0, - icon: confirmedTvl, - }, - { - title: "Pending Stake", - value: stakingStats?.unconfirmedTVLSat - ? `${maxDecimals(satoshiToBtc(stakingStats.unconfirmedTVLSat - stakingStats.activeTVLSat), 8)} ${coinName}` - : 0, - icon: pendingStake, - tooltip: - stakingStats && - stakingStats.unconfirmedTVLSat - stakingStats.activeTVLSat < 0 - ? "Pending TVL can be negative when there are unbonding requests" - : undefined, - }, - ], - [ - { - title: "Delegations", - value: stakingStats?.activeDelegations - ? formatter.format(stakingStats.activeDelegations as number) - : 0, - icon: delegations, - tooltip: "Total number of stake delegations", - }, - { - title: "Stakers", - value: stakingStats?.totalStakers - ? formatter.format(stakingStats.totalStakers as number) - : 0, - icon: stakers, - }, - ], - ]; +import { StatItem } from "./StatItem"; +import { + delegationIcon, + finalityProviderIcon, + rewardHistoryIcon, + rewardRateIcon, + stakerIcon, + tvlIcon, +} from "./icons"; + +const { coinName } = getNetworkConfig(); + +const formatter = Intl.NumberFormat("en", { + notation: "compact", + maximumFractionDigits: 2, +}); + +export const Stats = memo(() => { + const { + data: { + activeTvl, + activeStakers, + activeDelegations, + totalFinalityProviders, + activeFinalityProviders, + }, + isLoading, + } = useSystemStats(); return ( -
- {sections.map((section, index) => ( -
- {section.map((subSection, subIndex) => ( - -
-
- {subSection.title} -
-

- {subSection.title} -

- {subSection.tooltip && ( - <> - - - - - - )} -
-
-
-

- {isLoading ? ( - - ) : ( - {subSection.value} - )} -

-
-
- {subIndex !== section.length - 1 && ( -
- )} - - ))} -
- ))} +
+
+ + +
+ + + +
+ + +
+ +
+ + +
+ + + +
+ + +
); -}; +}); + +Stats.displayName = "Stats"; diff --git a/src/app/components/Stats/icons/confirmed-tvl.svg b/src/app/components/Stats/icons/confirmed-tvl.svg deleted file mode 100644 index f12b9346..00000000 --- a/src/app/components/Stats/icons/confirmed-tvl.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/app/components/Stats/icons/delegations.svg b/src/app/components/Stats/icons/delegations.svg deleted file mode 100644 index 8a851aa3..00000000 --- a/src/app/components/Stats/icons/delegations.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/app/components/Stats/icons/index.tsx b/src/app/components/Stats/icons/index.tsx new file mode 100644 index 00000000..1d8f8d75 --- /dev/null +++ b/src/app/components/Stats/icons/index.tsx @@ -0,0 +1,77 @@ +import { RiCopperCoinLine, RiHandCoinLine } from "react-icons/ri"; + +export const tvlIcon = ( + + + +); + +export const delegationIcon = ( + + + +); + +export const stakerIcon = ( + + + +); + +export const finalityProviderIcon = ( + + + +); + +export const rewardHistoryIcon = ; + +export const rewardRateIcon = ; diff --git a/src/app/components/Stats/icons/pending-stake.svg b/src/app/components/Stats/icons/pending-stake.svg deleted file mode 100644 index f268679d..00000000 --- a/src/app/components/Stats/icons/pending-stake.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/app/components/Stats/icons/stakers.svg b/src/app/components/Stats/icons/stakers.svg deleted file mode 100644 index 10eef4dd..00000000 --- a/src/app/components/Stats/icons/stakers.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/app/components/Stats/icons/staking-tvl-cap.svg b/src/app/components/Stats/icons/staking-tvl-cap.svg deleted file mode 100644 index 065afdc4..00000000 --- a/src/app/components/Stats/icons/staking-tvl-cap.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/app/hooks/useApi.ts b/src/app/hooks/api/useApi.ts similarity index 58% rename from src/app/hooks/useApi.ts rename to src/app/hooks/api/useApi.ts index defba57f..90071b1c 100644 --- a/src/app/hooks/useApi.ts +++ b/src/app/hooks/api/useApi.ts @@ -1,8 +1,12 @@ import { type DefaultError, + DefinedInitialDataOptions, + DefinedUseQueryResult, type QueryKey, type UndefinedInitialDataOptions, useQuery, + UseQueryOptions, + UseQueryResult, } from "@tanstack/react-query"; import { useEffect } from "react"; @@ -12,12 +16,28 @@ import { ErrorState } from "@/app/types/errors"; export function useAPIQuery< TQueryFnData = unknown, - TError extends Error = DefaultError, + TError = DefaultError, + TData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey, +>( + options: DefinedInitialDataOptions, +): DefinedUseQueryResult; +export function useAPIQuery< + TQueryFnData = unknown, + TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( options: UndefinedInitialDataOptions, -) { +): UseQueryResult; +export function useAPIQuery< + TQueryFnData = unknown, + TError = DefaultError, + TData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey, +>( + options: UseQueryOptions, +): UseQueryResult { const { isErrorOpen, handleError } = useError(); const data = useQuery({ @@ -30,7 +50,7 @@ export function useAPIQuery< useEffect(() => { handleError({ - error: data.error, + error: data.error as Error, hasError: data.isError, errorState: ErrorState.SERVER_ERROR, refetchFunction: data.refetch, diff --git a/src/app/hooks/useBTCTipHeight.ts b/src/app/hooks/api/useBTCTipHeight.ts similarity index 81% rename from src/app/hooks/useBTCTipHeight.ts rename to src/app/hooks/api/useBTCTipHeight.ts index ab952f39..7c5e30e1 100644 --- a/src/app/hooks/useBTCTipHeight.ts +++ b/src/app/hooks/api/useBTCTipHeight.ts @@ -1,4 +1,4 @@ -import { useAPIQuery } from "@/app/hooks/useApi"; +import { useAPIQuery } from "@/app/hooks/api/useApi"; import { getTipHeight } from "@/utils/mempool_api"; export const BTC_TIP_HEIGHT_KEY = "BTC_TIP_HEIGHT"; diff --git a/src/app/hooks/useDelegations.ts b/src/app/hooks/api/useDelegations.ts similarity index 100% rename from src/app/hooks/useDelegations.ts rename to src/app/hooks/api/useDelegations.ts diff --git a/src/app/hooks/useNetworkFees.ts b/src/app/hooks/api/useNetworkFees.ts similarity index 85% rename from src/app/hooks/useNetworkFees.ts rename to src/app/hooks/api/useNetworkFees.ts index 2a4840c5..8632af1a 100644 --- a/src/app/hooks/useNetworkFees.ts +++ b/src/app/hooks/api/useNetworkFees.ts @@ -1,4 +1,4 @@ -import { useAPIQuery } from "@/app/hooks/useApi"; +import { useAPIQuery } from "@/app/hooks/api/useApi"; import { getNetworkFees } from "@/utils/mempool_api"; export const NETWORK_FEES_KEY = "NETWORK_FEES"; diff --git a/src/app/hooks/api/useSystemStats.ts b/src/app/hooks/api/useSystemStats.ts new file mode 100644 index 00000000..3348350d --- /dev/null +++ b/src/app/hooks/api/useSystemStats.ts @@ -0,0 +1,23 @@ +import { useAPIQuery } from "@/app/hooks/api/useApi"; + +export const BTC_TIP_HEIGHT_KEY = "API_STATS"; + +const defaultValues = { + activeTvl: 0, + totalTvl: 0, + activeDelegations: 0, + totalDelegations: 0, + activeStakers: 0, + totalStakers: 0, + activeFinalityProviders: 0, + totalFinalityProviders: 0, +}; + +export function useSystemStats() { + return useAPIQuery({ + queryKey: ["API_STATS"], + queryFn: () => Promise.resolve(defaultValues), + initialData: defaultValues, + placeholderData: defaultValues, + }); +} diff --git a/src/app/hooks/useUTXOs.ts b/src/app/hooks/api/useUTXOs.ts similarity index 94% rename from src/app/hooks/useUTXOs.ts rename to src/app/hooks/api/useUTXOs.ts index 99b880a6..c987eee0 100644 --- a/src/app/hooks/useUTXOs.ts +++ b/src/app/hooks/api/useUTXOs.ts @@ -1,6 +1,6 @@ import { ONE_MINUTE } from "@/app/constants"; import { useWallet } from "@/app/context/wallet/WalletProvider"; -import { useAPIQuery } from "@/app/hooks/useApi"; +import { useAPIQuery } from "@/app/hooks/api/useApi"; import { filterOrdinals } from "@/utils/utxo"; export const UTXO_KEY = "UTXO"; diff --git a/src/app/hooks/api/useVersions.ts b/src/app/hooks/api/useVersions.ts new file mode 100644 index 00000000..3ea629a6 --- /dev/null +++ b/src/app/hooks/api/useVersions.ts @@ -0,0 +1,14 @@ +import { getGlobalParams } from "@/app/api/getGlobalParams"; +import { useAPIQuery } from "@/app/hooks/api/useApi"; + +export const VERSIONS_KEY = "VERSIONS"; + +export function useVersions({ enabled = true }: { enabled?: boolean } = {}) { + const data = useAPIQuery({ + queryKey: [VERSIONS_KEY], + queryFn: getGlobalParams, + enabled, + }); + + return data; +} diff --git a/src/app/hooks/useVersionByHeight.ts b/src/app/hooks/useVersionByHeight.ts new file mode 100644 index 00000000..05967a89 --- /dev/null +++ b/src/app/hooks/useVersionByHeight.ts @@ -0,0 +1,14 @@ +import { useMemo } from "react"; + +import { getCurrentGlobalParamsVersion } from "@/utils/globalParams"; + +import { useVersions } from "./api/useVersions"; + +export function useVersionByHeight(height: number) { + const { data: versions } = useVersions(); + + return useMemo( + () => getCurrentGlobalParamsVersion(height, versions ?? []), + [versions, height], + ); +} diff --git a/src/app/hooks/useVersions.ts b/src/app/hooks/useVersions.ts deleted file mode 100644 index f1f812b3..00000000 --- a/src/app/hooks/useVersions.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { useMemo } from "react"; - -import { getGlobalParams } from "@/app/api/getGlobalParams"; -import { useAPIQuery } from "@/app/hooks/useApi"; -import { getCurrentGlobalParamsVersion } from "@/utils/globalParams"; - -export const VERSIONS_KEY = "VERSIONS"; - -export function useVersions({ enabled = true }: { enabled?: boolean } = {}) { - const data = useAPIQuery({ - queryKey: [VERSIONS_KEY], - queryFn: getGlobalParams, - enabled, - }); - - return data; -} - -export function useVersionByHeight(height: number) { - const { data: versions } = useVersions(); - return useMemo( - () => getCurrentGlobalParamsVersion(height, versions ?? []), - [versions, height], - ); -} diff --git a/src/app/page.tsx b/src/app/page.tsx index 9877d947..c2d30fce 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -8,9 +8,9 @@ import { FAQ } from "./components/FAQ/FAQ"; import { Footer } from "./components/Footer/Footer"; import { Header } from "./components/Header/Header"; import { NetworkBadge } from "./components/NetworkBadge/NetworkBadge"; +import { PersonalBalance } from "./components/PersonalBalance/PersonalBalance"; import { Staking } from "./components/Staking/Staking"; import { Stats } from "./components/Stats/Stats"; -import { Summary } from "./components/Summary/Summary"; const Home = () => { useEffect(() => { @@ -24,7 +24,7 @@ const Home = () => {
- +
diff --git a/src/app/state/DelegationState.tsx b/src/app/state/DelegationState.tsx index 94dd9bf9..9b049837 100644 --- a/src/app/state/DelegationState.tsx +++ b/src/app/state/DelegationState.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, type PropsWithChildren } from "react"; import { useLocalStorage } from "usehooks-ts"; import { useWallet } from "@/app/context/wallet/WalletProvider"; -import { useDelegations } from "@/app/hooks/useDelegations"; +import { useDelegations } from "@/app/hooks/api/useDelegations"; import type { Delegation } from "@/app/types/delegations"; import { DelegationState as DelegationEnum } from "@/app/types/delegations"; import { createStateUtils } from "@/utils/createStateUtils"; diff --git a/src/app/state/index.tsx b/src/app/state/index.tsx index deb79286..a3623270 100644 --- a/src/app/state/index.tsx +++ b/src/app/state/index.tsx @@ -1,8 +1,8 @@ import { useMemo, type PropsWithChildren } from "react"; -import { useBTCTipHeight } from "@/app/hooks/useBTCTipHeight"; -import { useUTXOs } from "@/app/hooks/useUTXOs"; -import { useVersions } from "@/app/hooks/useVersions"; +import { useBTCTipHeight } from "@/app/hooks/api/useBTCTipHeight"; +import { useUTXOs } from "@/app/hooks/api/useUTXOs"; +import { useVersions } from "@/app/hooks/api/useVersions"; import { GlobalParamsVersion } from "@/app/types/globalParams"; import { createStateUtils } from "@/utils/createStateUtils"; import { getCurrentGlobalParamsVersion } from "@/utils/globalParams"; @@ -12,7 +12,7 @@ import { DelegationState } from "./DelegationState"; const STATE_LIST = [DelegationState]; -interface AppState { +export interface AppState { availableUTXOs?: UTXO[]; totalBalance: number; nextVersion?: GlobalParamsVersion;