Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show correct total balance #574

Merged
merged 3 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions src/app/components/PersonalBalance/PersonalBalance.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Heading } from "@babylonlabs-io/bbn-core-ui";
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { useMemo, useState } from "react";

import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider";
import { useCosmosWallet } from "@/app/context/wallet/CosmosWalletProvider";
import { useBbnQuery } from "@/app/hooks/client/rpc/queries/useBbnQuery";
import { useRewardsService } from "@/app/hooks/services/useRewardsService";
import { useAppState } from "@/app/state";
import { useDelegationV2State } from "@/app/state/DelegationV2State";
import { getNetworkConfigBBN } from "@/config/network/bbn";
import { getNetworkConfigBTC } from "@/config/network/btc";
import { ubbnToBbn } from "@/utils/bbn";
Expand All @@ -31,6 +33,9 @@ export function PersonalBalance() {
} = useBTCWallet();
const { connected: cosmosConnected, bech32Address } = useCosmosWallet();

const { totalBalance: availableBalance } = useAppState();
const { getStakedBalance } = useDelegationV2State();

const {
balanceQuery: { data: cosmosBalance, isLoading: cosmosBalanceLoading },
} = useBbnQuery();
Expand All @@ -49,6 +54,11 @@ export function PersonalBalance() {
enabled: btcConnected,
});

const totalBalance = useMemo(
() => (btcBalance ?? 0) + getStakedBalance(),
[btcBalance, getStakedBalance],
);

if (!btcConnected || !cosmosConnected) {
return null;
}
Expand All @@ -61,20 +71,18 @@ export function PersonalBalance() {
Wallet Balance
</Heading>
<div className="flex flex-col justify-between bg-secondary-contrast rounded p-6 text-base md:flex-row">
{/* TODO: Need to add the staker tvl value for the bitcoin balance
as well as remove the filtering on inscription balance*/}
<StatItem
loading={btcBalanceLoading}
title={`${coinName} Balance`}
value={`${satoshiToBtc(btcBalance ?? 0)} ${coinSymbol}`}
title={`Total ${coinName} Balance`}
value={`${satoshiToBtc(totalBalance)} ${coinSymbol}`}
/>

<div className="divider mx-0 my-2 md:divider-horizontal" />

<StatItem
loading={cosmosBalanceLoading}
title={"Stakable Balance"}
value={`${satoshiToBtc(btcBalance ?? 0)} ${coinSymbol}`}
value={`${satoshiToBtc(availableBalance)} ${coinSymbol}`}
/>

<div className="divider mx-0 my-2 md:divider-horizontal" />
Expand Down
15 changes: 0 additions & 15 deletions src/app/hooks/client/api/useDelegationV2.ts

This file was deleted.

48 changes: 47 additions & 1 deletion src/app/state/DelegationV2State.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { useCallback, useMemo, type PropsWithChildren } from "react";

import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider";
import type { DelegationLike, DelegationV2 } from "@/app/types/delegationsV2";
import {
DelegationV2StakingState,
type DelegationLike,
type DelegationV2,
} from "@/app/types/delegationsV2";
import { createStateUtils } from "@/utils/createStateUtils";
import { getDelegationsV2LocalStorageKey } from "@/utils/local_storage/getDelegationsLocalStorageKey";

Expand All @@ -16,8 +20,22 @@ interface DelegationV2State {
updateDelegationStatus: (is: string, status: DelegationV2["state"]) => void;
fetchMoreDelegations: () => void;
findDelegationByTxHash: (txHash: string) => DelegationV2 | undefined;
getStakedBalance: () => number;
}

const STAKED_BALANCE_STATUSES = [
DelegationV2StakingState.ACTIVE,
DelegationV2StakingState.TIMELOCK_UNBONDING,
DelegationV2StakingState.EARLY_UNBONDING,
DelegationV2StakingState.TIMELOCK_WITHDRAWABLE,
DelegationV2StakingState.EARLY_UNBONDING_WITHDRAWABLE,
DelegationV2StakingState.TIMELOCK_SLASHING_WITHDRAWABLE,
DelegationV2StakingState.EARLY_UNBONDING_SLASHING_WITHDRAWABLE,
DelegationV2StakingState.SLASHED,
DelegationV2StakingState.INTERMEDIATE_PENDING_BTC_CONFIRMATION,
DelegationV2StakingState.INTERMEDIATE_UNBONDING_SUBMITTED,
];

const { StateProvider, useState } = createStateUtils<DelegationV2State>({
isLoading: false,
delegations: [],
Expand All @@ -26,6 +44,7 @@ const { StateProvider, useState } = createStateUtils<DelegationV2State>({
updateDelegationStatus: () => {},
fetchMoreDelegations: () => {},
findDelegationByTxHash: () => undefined,
getStakedBalance: () => 0,
});

export function DelegationV2State({ children }: PropsWithChildren) {
Expand All @@ -45,6 +64,31 @@ export function DelegationV2State({ children }: PropsWithChildren) {
(txHash: string) => delegations.find((d) => d.stakingTxHashHex === txHash),
[delegations],
);
// Temporary solution to calculate total staked balance while waiting for API support.
// Once the API is complete, it will directly provide the staker's total balance
// (active + unbonding + withdrawing). For now, we manually sum up all delegation
// amounts that are in relevant states, including intermediate states.
const getStakedBalance = useCallback(() => {
// First create a map of status -> amounts array
const statusAmountMap = delegations.reduce(
(acc, delegation) => {
if (!STAKED_BALANCE_STATUSES.includes(delegation.state)) {
return acc;
}
if (!acc[delegation.state]) {
acc[delegation.state] = [];
}
acc[delegation.state].push(delegation.stakingAmount);
return acc;
},
{} as Record<DelegationV2StakingState, number[]>,
);

// Then sum up all amounts across all statuses into a single number
return Object.values(statusAmountMap)
.flat()
.reduce((total, amount) => total + amount, 0);
}, [delegations]);

// Context
const state = useMemo(
Expand All @@ -56,6 +100,7 @@ export function DelegationV2State({ children }: PropsWithChildren) {
updateDelegationStatus,
findDelegationByTxHash,
fetchMoreDelegations: fetchNextPage,
getStakedBalance,
}),
[
delegations,
Expand All @@ -65,6 +110,7 @@ export function DelegationV2State({ children }: PropsWithChildren) {
updateDelegationStatus,
findDelegationByTxHash,
fetchNextPage,
getStakedBalance,
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface StatusTooltipProps {
const STATUS_LABELS = {
PENDING: "Pending",
VERIFIED: "Verified",
PENDING_BTC_CONFIRMATION: "Pending BTC Confirmation",
ACTIVE: "Active",
UNBONDING: "Unbonding",
WITHDRAWABLE: "Withdrawable",
Expand Down Expand Up @@ -144,7 +145,7 @@ const STATUSES: Record<
tooltip: STATUS_MESSAGES.PENDING,
}),
[State.INTERMEDIATE_PENDING_BTC_CONFIRMATION]: ({ params }) => ({
label: STATUS_LABELS.PENDING,
label: STATUS_LABELS.PENDING_BTC_CONFIRMATION,
tooltip: STATUS_MESSAGES.PENDING_BTC_CONFIRMATION(
params?.btcEpochCheckParams.latestParam.btcConfirmationDepth ?? 0,
),
Expand Down