Skip to content

Commit

Permalink
move rpc provider to context
Browse files Browse the repository at this point in the history
  • Loading branch information
jrwbabylonlab committed Dec 11, 2024
1 parent a4576d4 commit bc967a9
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 66 deletions.
19 changes: 9 additions & 10 deletions src/app/components/PersonalBalance/PersonalBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider";
import { useCosmosWallet } from "@/app/context/wallet/CosmosWalletProvider";
import { useBbnQueryClient } from "@/app/hooks/client/query/useBbnQueryClient";
import { useRewardsService } from "@/app/hooks/services/useRewardsService";
import { getNetworkConfig } from "@/config/network.config";
import { ubbnToBbn } from "@/utils/bbn";
import { satoshiToBtc } from "@/utils/btc";

Expand All @@ -17,12 +18,14 @@ const QUERY_KEYS = {
};

export function PersonalBalance() {
const { coinName } = getNetworkConfig();
const { getBalance: getBTCBalance, connected: btcConnected } = useBTCWallet();
const { connected: cosmosConnected } = useCosmosWallet();

const { getBalance } = useBbnQueryClient();
const { getRewards } = useRewardsService();
const { claimRewards } = useRewardsService();
const {
balanceQuery: { data: cosmosBalance, isLoading: cosmosBalanceLoading },
} = useBbnQueryClient();
const { getRewards, claimRewards } = useRewardsService();

const { data: rewards, isLoading: rewardsLoading } = useQuery({
queryKey: [QUERY_KEYS.REWARDS],
Expand All @@ -32,11 +35,7 @@ export function PersonalBalance() {
const { data: btcBalance, isLoading: btcBalanceLoading } = useQuery({
queryKey: [QUERY_KEYS.BTC_BALANCE],
queryFn: getBTCBalance,
});

const { data: cosmosBalance, isLoading: cosmosBalanceLoading } = useQuery({
queryKey: [QUERY_KEYS.COSMOS_BALANCE],
queryFn: getBalance,
enabled: btcConnected,
});

if (!btcConnected || !cosmosConnected) {
Expand All @@ -54,15 +53,15 @@ export function PersonalBalance() {
<StatItem
loading={btcBalanceLoading}
title="Bitcoin Balance"
value={`${satoshiToBtc(btcBalance ?? 0)} BTC`}
value={`${satoshiToBtc(btcBalance ?? 0)} ${coinName}`}
/>

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

<StatItem
loading={cosmosBalanceLoading}
title="Stakable Bitcoin"
value={`${satoshiToBtc(btcBalance ?? 0)} BTC`}
value={`${satoshiToBtc(btcBalance ?? 0)} ${coinName}`}
/>

<div className="divider mx-0 my-2 md:divider-horizontal" />
Expand Down
58 changes: 58 additions & 0 deletions src/app/context/rpc/BbnRpcProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { QueryClient } from "@cosmjs/stargate";
import { Tendermint34Client } from "@cosmjs/tendermint-rpc";
import { createContext, useContext, useEffect, useState } from "react";

import { BBN_RPC_URL } from "@/app/common/rpc";

interface BbnRpcContextType {
queryClient: QueryClient | undefined;
isLoading: boolean;
error: Error | null;
}

const BbnRpcContext = createContext<BbnRpcContextType>({
queryClient: undefined,
isLoading: true,
error: null,
});

export function BbnRpcProvider({ children }: { children: React.ReactNode }) {
const [queryClient, setQueryClient] = useState<QueryClient>();
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);

useEffect(() => {
let mounted = true;

const init = async () => {
try {
const tmClient = await Tendermint34Client.connect(BBN_RPC_URL);
const client = QueryClient.withExtensions(tmClient);

if (mounted) {
setQueryClient(client);
setIsLoading(false);
}
} catch (err) {
if (mounted) {
setError(err instanceof Error ? err : new Error("Failed to connect"));
setIsLoading(false);
}
}
};

init();

return () => {
mounted = false;
};
}, []);

return (
<BbnRpcContext.Provider value={{ queryClient, isLoading, error }}>
{children}
</BbnRpcContext.Provider>
);
}

export const useBbnRpc = () => useContext(BbnRpcContext);
86 changes: 47 additions & 39 deletions src/app/hooks/client/query/useBbnQueryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,65 +7,72 @@ import {
createProtobufRpcClient,
setupBankExtension,
} from "@cosmjs/stargate";
import { Tendermint34Client } from "@cosmjs/tendermint-rpc";
import { useCallback, useEffect, useState } from "react";

import { BBN_RPC_URL } from "@/app/common/rpc";
import { ONE_MINUTE } from "@/app/constants";
import { useBbnRpc } from "@/app/context/rpc/BbnRpcProvider";
import { useCosmosWallet } from "@/app/context/wallet/CosmosWalletProvider";

import { useAPIQuery } from "../api/useApi";

export const BBN_BTCLIGHTCLIENT_TIP_KEY = "BBN_BTCLIGHTCLIENT_TIP";
const BBN_BTCLIGHTCLIENT_TIP_KEY = "BBN_BTCLIGHTCLIENT_TIP";
const BBN_BALANCE_KEY = "BBN_BALANCE";
const BBN_REWARDS_KEY = "BBN_REWARDS";

/**
* Query service for Babylon which contains all the queries for
* interacting with Babylon RPC nodes
*/
export const useBbnQueryClient = () => {
const { bech32Address, connected } = useCosmosWallet();
const [queryClient, setQueryClient] = useState<QueryClient>();

useEffect(() => {
const initQueryClient = async () => {
const tmClient = await Tendermint34Client.connect(BBN_RPC_URL);
const queryClient = QueryClient.withExtensions(tmClient);
setQueryClient(queryClient);
};

initQueryClient();
}, []);
const { queryClient } = useBbnRpc();

/**
* Gets the rewards from the user's account.
* @returns {Promise<Object>} - The rewards from the user's account.
*/
const getRewards = useCallback(async (): Promise<
incentivequery.QueryRewardGaugesResponse | undefined
> => {
if (!connected || !queryClient || !bech32Address) {
return undefined;
}
const { incentive } = setupIncentiveExtension(queryClient);

const req: incentivequery.QueryRewardGaugesRequest =
incentivequery.QueryRewardGaugesRequest.fromPartial({
address: bech32Address,
});
const rewardsQuery = useAPIQuery({
queryKey: [BBN_REWARDS_KEY, bech32Address],
queryFn: async () => {
if (!connected || !queryClient || !bech32Address) {
return undefined;
}
const { incentive } = setupIncentiveExtension(queryClient);

return incentive.RewardGauges(req);
}, [connected, queryClient, bech32Address]);
const req: incentivequery.QueryRewardGaugesRequest =
incentivequery.QueryRewardGaugesRequest.fromPartial({
address: bech32Address,
});

const getBalance = useCallback(async (): Promise<number> => {
if (!connected || !queryClient || !bech32Address) {
return 0;
}
return incentive.RewardGauges(req);
},
enabled: Boolean(queryClient && connected && bech32Address),
staleTime: ONE_MINUTE,
refetchInterval: ONE_MINUTE,
});

const { bank } = setupBankExtension(queryClient);
const balance = await bank.balance(bech32Address, "ubbn");
return Number(balance?.amount ?? 0);
}, [connected, queryClient, bech32Address]);
/**
* Gets the balance of the user's account.
* @returns {Promise<Object>} - The balance of the user's account.
*/
const balanceQuery = useAPIQuery({
queryKey: [BBN_BALANCE_KEY, bech32Address],
queryFn: async () => {
if (!connected || !queryClient || !bech32Address) {
return 0;
}
const { bank } = setupBankExtension(queryClient);
const balance = await bank.balance(bech32Address, "ubbn");
return Number(balance?.amount ?? 0);
},
enabled: Boolean(queryClient && connected && bech32Address),
staleTime: ONE_MINUTE,
refetchInterval: ONE_MINUTE,
});

/**
* Gets the tip of the Bitcoin blockchain.
* @returns {Promise<Object>} - The tip of the Bitcoin blockchain.
*/
const btcTipQuery = useAPIQuery({
queryKey: [BBN_BTCLIGHTCLIENT_TIP_KEY],
queryFn: async () => {
Expand All @@ -79,11 +86,12 @@ export const useBbnQueryClient = () => {
},
enabled: Boolean(queryClient),
staleTime: ONE_MINUTE,
refetchInterval: false, // Disable automatic periodic refetching
});

return {
getRewards,
getBalance,
rewardsQuery,
balanceQuery,
btcTipQuery,
};
};
Expand Down
9 changes: 5 additions & 4 deletions src/app/hooks/services/useRewardsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ const REWARD_GAUGE_KEY_BTC_DELEGATION = "btc_delegation";
export const useRewardsService = () => {
const { bech32Address } = useCosmosWallet();

const { getRewards: getBbnRewards } = useBbnQueryClient();
const { rewardsQuery } = useBbnQueryClient();
const { estimateBbnGasFee, sendBbnTx } = useBbnTransaction();

/**
* Gets the rewards from the user's account.
* @returns {Promise<number>} The rewards from the user's account.
*/
const getRewards = useCallback(async (): Promise<number> => {
const rewards = await getBbnRewards();
const rewards = rewardsQuery.data;
if (!rewards) {
return 0;
}
Expand All @@ -38,7 +38,7 @@ export const useRewardsService = () => {
coins.reduce((acc, coin) => acc + Number(coin.amount), 0) -
(withdrawnCoins || 0)
);
}, [getBbnRewards]);
}, [rewardsQuery.data]);

/**
* Estimates the gas fee for claiming rewards.
Expand All @@ -58,7 +58,8 @@ export const useRewardsService = () => {
const msg = createWithdrawRewardMsg(bech32Address);

await sendBbnTx(msg);
}, [bech32Address, sendBbnTx]);
rewardsQuery.refetch();
}, [bech32Address, sendBbnTx, rewardsQuery]);

return {
getRewards,
Expand Down
1 change: 1 addition & 0 deletions src/app/hooks/services/useTransactionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const useTransactionService = () => {

// Get the param based on the tip height
// EOI should always be created based on the BTC tip height from BBN chain
console.log("tipHeader.height", tipHeader.height);
const p = getBbnParamByBtcHeight(tipHeader.height, versionedParams);

const staking = new Staking(
Expand Down
29 changes: 16 additions & 13 deletions src/app/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React from "react";
import { NotificationContainer } from "./components/Notification/NotificationContainer";
import { ErrorProvider } from "./context/Error/ErrorContext";
import { StakingStatsProvider } from "./context/api/StakingStatsProvider";
import { BbnRpcProvider } from "./context/rpc/BbnRpcProvider";
import { BTCWalletProvider } from "./context/wallet/BTCWalletProvider";
import { CosmosWalletProvider } from "./context/wallet/CosmosWalletProvider";
import { WalletConnectionProvider } from "./context/wallet/WalletConnectionProvider";
Expand All @@ -23,19 +24,21 @@ function Providers({ children }: React.PropsWithChildren) {
<ThemeProvider defaultTheme="dark" attribute="data-theme">
<QueryClientProvider client={client}>
<ErrorProvider>
<WalletConnectionProvider>
<BTCWalletProvider>
<CosmosWalletProvider>
<AppState>
<StakingStatsProvider>
<ReactQueryStreamedHydration>
{children}
</ReactQueryStreamedHydration>
</StakingStatsProvider>
</AppState>
</CosmosWalletProvider>
</BTCWalletProvider>
</WalletConnectionProvider>
<BbnRpcProvider>
<WalletConnectionProvider>
<BTCWalletProvider>
<CosmosWalletProvider>
<AppState>
<StakingStatsProvider>
<ReactQueryStreamedHydration>
{children}
</ReactQueryStreamedHydration>
</StakingStatsProvider>
</AppState>
</CosmosWalletProvider>
</BTCWalletProvider>
</WalletConnectionProvider>
</BbnRpcProvider>
</ErrorProvider>
<ReactQueryDevtools
buttonPosition="bottom-left"
Expand Down

0 comments on commit bc967a9

Please sign in to comment.