diff --git a/explorer/src/providers/accounts/history.tsx b/explorer/src/providers/accounts/history.tsx index e09e0755c3..391d6b9364 100644 --- a/explorer/src/providers/accounts/history.tsx +++ b/explorer/src/providers/accounts/history.tsx @@ -6,7 +6,7 @@ import { TransactionSignature, Connection, } from "@solana/web3.js"; -import { useCluster } from "../cluster"; +import { useCluster, Cluster } from "../cluster"; import * as Cache from "providers/cache"; import { ActionType, FetchStatus } from "providers/cache"; @@ -78,6 +78,7 @@ export function HistoryProvider({ children }: HistoryProviderProps) { async function fetchAccountHistory( dispatch: Dispatch, pubkey: PublicKey, + cluster: Cluster, url: string, options: { before?: TransactionSignature; limit: number } ) { @@ -102,7 +103,9 @@ async function fetchAccountHistory( }; status = FetchStatus.Fetched; } catch (error) { - Sentry.captureException(error, { tags: { url } }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(error, { tags: { url } }); + } status = FetchStatus.FetchFailed; } dispatch({ @@ -142,7 +145,7 @@ export function useAccountHistory( } export function useFetchAccountHistory() { - const { url } = useCluster(); + const { cluster, url } = useCluster(); const state = React.useContext(StateContext); const dispatch = React.useContext(DispatchContext); if (!state || !dispatch) { @@ -151,15 +154,21 @@ export function useFetchAccountHistory() { ); } - return (pubkey: PublicKey, refresh?: boolean) => { - const before = state.entries[pubkey.toBase58()]; - if (!refresh && before?.data?.fetched && before.data.fetched.length > 0) { - if (before.data.foundOldest) return; - const oldest = - before.data.fetched[before.data.fetched.length - 1].signature; - fetchAccountHistory(dispatch, pubkey, url, { before: oldest, limit: 25 }); - } else { - fetchAccountHistory(dispatch, pubkey, url, { limit: 25 }); - } - }; + return React.useCallback( + (pubkey: PublicKey, refresh?: boolean) => { + const before = state.entries[pubkey.toBase58()]; + if (!refresh && before?.data?.fetched && before.data.fetched.length > 0) { + if (before.data.foundOldest) return; + const oldest = + before.data.fetched[before.data.fetched.length - 1].signature; + fetchAccountHistory(dispatch, pubkey, cluster, url, { + before: oldest, + limit: 25, + }); + } else { + fetchAccountHistory(dispatch, pubkey, cluster, url, { limit: 25 }); + } + }, + [state, dispatch, cluster, url] + ); } diff --git a/explorer/src/providers/accounts/index.tsx b/explorer/src/providers/accounts/index.tsx index 2a5414cd01..3bdd225d18 100644 --- a/explorer/src/providers/accounts/index.tsx +++ b/explorer/src/providers/accounts/index.tsx @@ -2,7 +2,7 @@ import React from "react"; import * as Sentry from "@sentry/react"; import { StakeAccount as StakeAccountWasm } from "solana-sdk-wasm"; import { PublicKey, Connection, StakeProgram } from "@solana/web3.js"; -import { useCluster } from "../cluster"; +import { useCluster, Cluster } from "../cluster"; import { HistoryProvider } from "./history"; import { TokensProvider, TOKEN_PROGRAM_ID } from "./tokens"; import { coerce } from "superstruct"; @@ -72,6 +72,7 @@ export function AccountsProvider({ children }: AccountsProviderProps) { async function fetchAccountInfo( dispatch: Dispatch, pubkey: PublicKey, + cluster: Cluster, url: string ) { dispatch({ @@ -149,7 +150,9 @@ async function fetchAccountInfo( data = { pubkey, lamports, details }; fetchStatus = FetchStatus.Fetched; } catch (error) { - Sentry.captureException(error, { tags: { url } }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(error, { tags: { url } }); + } fetchStatus = FetchStatus.FetchFailed; } dispatch({ @@ -231,11 +234,11 @@ export function useFetchAccountInfo() { ); } - const { url } = useCluster(); + const { cluster, url } = useCluster(); return React.useCallback( (pubkey: PublicKey) => { - fetchAccountInfo(dispatch, pubkey, url); + fetchAccountInfo(dispatch, pubkey, cluster, url); }, - [dispatch, url] + [dispatch, cluster, url] ); } diff --git a/explorer/src/providers/accounts/tokens.tsx b/explorer/src/providers/accounts/tokens.tsx index d04ca5f8ad..9932771a71 100644 --- a/explorer/src/providers/accounts/tokens.tsx +++ b/explorer/src/providers/accounts/tokens.tsx @@ -4,7 +4,7 @@ import { Connection, PublicKey } from "@solana/web3.js"; import * as Cache from "providers/cache"; import { ActionType, FetchStatus } from "providers/cache"; import { TokenAccountInfo } from "validators/accounts/token"; -import { useCluster } from "../cluster"; +import { useCluster, Cluster } from "../cluster"; import { coerce } from "superstruct"; export type TokenInfoWithPubkey = { @@ -47,6 +47,7 @@ export const TOKEN_PROGRAM_ID = new PublicKey( async function fetchAccountTokens( dispatch: Dispatch, pubkey: PublicKey, + cluster: Cluster, url: string ) { const key = pubkey.toBase58(); @@ -73,7 +74,9 @@ async function fetchAccountTokens( }; status = FetchStatus.Fetched; } catch (error) { - Sentry.captureException(error, { tags: { url } }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(error, { tags: { url } }); + } status = FetchStatus.FetchFailed; } dispatch({ type: ActionType.Update, url, status, data, key }); @@ -101,8 +104,11 @@ export function useFetchAccountOwnedTokens() { ); } - const { url } = useCluster(); - return (pubkey: PublicKey) => { - fetchAccountTokens(dispatch, pubkey, url); - }; + const { cluster, url } = useCluster(); + return React.useCallback( + (pubkey: PublicKey) => { + fetchAccountTokens(dispatch, pubkey, cluster, url); + }, + [dispatch, cluster, url] + ); } diff --git a/explorer/src/providers/cluster.tsx b/explorer/src/providers/cluster.tsx index 9591e5d5ec..99177df960 100644 --- a/explorer/src/providers/cluster.tsx +++ b/explorer/src/providers/cluster.tsx @@ -183,9 +183,11 @@ async function updateCluster( firstAvailableBlock, }); } catch (error) { - Sentry.captureException(error, { - tags: { clusterUrl: clusterUrl(cluster, customUrl) }, - }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(error, { + tags: { clusterUrl: clusterUrl(cluster, customUrl) }, + }); + } dispatch({ status: ClusterStatus.Failure, cluster, customUrl }); } } diff --git a/explorer/src/providers/mints/largest.tsx b/explorer/src/providers/mints/largest.tsx index 7595abf68e..17780b9edd 100644 --- a/explorer/src/providers/mints/largest.tsx +++ b/explorer/src/providers/mints/largest.tsx @@ -1,6 +1,6 @@ import React from "react"; import * as Sentry from "@sentry/react"; -import { useCluster } from "providers/cluster"; +import { useCluster, Cluster } from "providers/cluster"; import * as Cache from "providers/cache"; import { ActionType, FetchStatus } from "providers/cache"; import { @@ -41,6 +41,7 @@ export function LargestAccountsProvider({ children }: ProviderProps) { async function fetchLargestAccounts( dispatch: Dispatch, pubkey: PublicKey, + cluster: Cluster, url: string ) { dispatch({ @@ -60,7 +61,9 @@ async function fetchLargestAccounts( }; fetchStatus = FetchStatus.Fetched; } catch (error) { - Sentry.captureException(error, { tags: { url } }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(error, { tags: { url } }); + } fetchStatus = FetchStatus.FetchFailed; } dispatch({ @@ -80,10 +83,13 @@ export function useFetchTokenLargestAccounts() { ); } - const { url } = useCluster(); - return (pubkey: PublicKey) => { - fetchLargestAccounts(dispatch, pubkey, url); - }; + const { cluster, url } = useCluster(); + return React.useCallback( + (pubkey: PublicKey) => { + fetchLargestAccounts(dispatch, pubkey, cluster, url); + }, + [dispatch, cluster, url] + ); } export function useTokenLargestTokens( diff --git a/explorer/src/providers/richList.tsx b/explorer/src/providers/richList.tsx index ecfa8c0457..b3f59b94d8 100644 --- a/explorer/src/providers/richList.tsx +++ b/explorer/src/providers/richList.tsx @@ -2,7 +2,7 @@ import React from "react"; import * as Sentry from "@sentry/react"; import { AccountBalancePair, Connection } from "@solana/web3.js"; -import { useCluster, ClusterStatus } from "./cluster"; +import { useCluster, ClusterStatus, Cluster } from "./cluster"; export enum Status { Idle, @@ -25,7 +25,7 @@ const DispatchContext = React.createContext(undefined); type Props = { children: React.ReactNode }; export function RichListProvider({ children }: Props) { const [state, setState] = React.useState(Status.Idle); - const { status: clusterStatus, url } = useCluster(); + const { status: clusterStatus, cluster, url } = useCluster(); React.useEffect(() => { if (state !== Status.Idle) { @@ -35,12 +35,12 @@ export function RichListProvider({ children }: Props) { break; } case ClusterStatus.Connected: { - fetch(setState, url); + fetch(setState, cluster, url); break; } } } - }, [clusterStatus, url]); // eslint-disable-line react-hooks/exhaustive-deps + }, [clusterStatus, cluster, url]); // eslint-disable-line react-hooks/exhaustive-deps return ( @@ -51,7 +51,7 @@ export function RichListProvider({ children }: Props) { ); } -async function fetch(dispatch: Dispatch, url: string) { +async function fetch(dispatch: Dispatch, cluster: Cluster, url: string) { dispatch(Status.Connecting); try { @@ -71,7 +71,9 @@ async function fetch(dispatch: Dispatch, url: string) { return { total, circulating, nonCirculating }; }); } catch (err) { - Sentry.captureException(err, { tags: { url } }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(err, { tags: { url } }); + } dispatch("Failed to fetch top accounts"); } } @@ -90,6 +92,8 @@ export function useFetchRichList() { throw new Error(`useFetchRichList must be used within a RichListProvider`); } - const { url } = useCluster(); - return () => fetch(dispatch, url); + const { cluster, url } = useCluster(); + return React.useCallback(() => { + fetch(dispatch, cluster, url); + }, [dispatch, cluster, url]); } diff --git a/explorer/src/providers/supply.tsx b/explorer/src/providers/supply.tsx index e7a6bad709..b456cac330 100644 --- a/explorer/src/providers/supply.tsx +++ b/explorer/src/providers/supply.tsx @@ -2,7 +2,7 @@ import React from "react"; import * as Sentry from "@sentry/react"; import { Supply, Connection } from "@solana/web3.js"; -import { useCluster, ClusterStatus } from "./cluster"; +import { useCluster, ClusterStatus, Cluster } from "./cluster"; export enum Status { Idle, @@ -19,15 +19,16 @@ const DispatchContext = React.createContext(undefined); type Props = { children: React.ReactNode }; export function SupplyProvider({ children }: Props) { const [state, setState] = React.useState(Status.Idle); - const { status: clusterStatus, url } = useCluster(); + const { status: clusterStatus, cluster, url } = useCluster(); React.useEffect(() => { if (state !== Status.Idle) { if (clusterStatus === ClusterStatus.Connecting) setState(Status.Disconnected); - if (clusterStatus === ClusterStatus.Connected) fetch(setState, url); + if (clusterStatus === ClusterStatus.Connected) + fetch(setState, cluster, url); } - }, [clusterStatus, url]); // eslint-disable-line react-hooks/exhaustive-deps + }, [clusterStatus, cluster, url]); // eslint-disable-line react-hooks/exhaustive-deps return ( @@ -38,7 +39,7 @@ export function SupplyProvider({ children }: Props) { ); } -async function fetch(dispatch: Dispatch, url: string) { +async function fetch(dispatch: Dispatch, cluster: Cluster, url: string) { dispatch(Status.Connecting); try { @@ -51,7 +52,9 @@ async function fetch(dispatch: Dispatch, url: string) { return supply; }); } catch (err) { - Sentry.captureException(err, { tags: { url } }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(err, { tags: { url } }); + } dispatch("Failed to fetch supply"); } } @@ -70,6 +73,8 @@ export function useFetchSupply() { throw new Error(`useFetchSupply must be used within a SupplyProvider`); } - const { url } = useCluster(); - return () => fetch(dispatch, url); + const { cluster, url } = useCluster(); + return React.useCallback(() => { + fetch(dispatch, cluster, url); + }, [dispatch, cluster, url]); } diff --git a/explorer/src/providers/transactions/details.tsx b/explorer/src/providers/transactions/details.tsx index 623f36e77a..594627d842 100644 --- a/explorer/src/providers/transactions/details.tsx +++ b/explorer/src/providers/transactions/details.tsx @@ -5,7 +5,7 @@ import { TransactionSignature, ParsedConfirmedTransaction, } from "@solana/web3.js"; -import { useCluster } from "../cluster"; +import { useCluster, Cluster } from "../cluster"; import { CACHED_DETAILS, isCached } from "./cached"; import * as Cache from "providers/cache"; import { ActionType, FetchStatus } from "providers/cache"; @@ -43,6 +43,7 @@ export function DetailsProvider({ children }: DetailsProviderProps) { async function fetchDetails( dispatch: Dispatch, signature: TransactionSignature, + cluster: Cluster, url: string ) { dispatch({ @@ -64,7 +65,9 @@ async function fetchDetails( ); fetchStatus = FetchStatus.Fetched; } catch (error) { - Sentry.captureException(error, { tags: { url } }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(error, { tags: { url } }); + } fetchStatus = FetchStatus.FetchFailed; } } @@ -85,10 +88,13 @@ export function useFetchTransactionDetails() { ); } - const { url } = useCluster(); - return (signature: TransactionSignature) => { - url && fetchDetails(dispatch, signature, url); - }; + const { cluster, url } = useCluster(); + return React.useCallback( + (signature: TransactionSignature) => { + url && fetchDetails(dispatch, signature, cluster, url); + }, + [dispatch, cluster, url] + ); } export function useTransactionDetails( diff --git a/explorer/src/providers/transactions/index.tsx b/explorer/src/providers/transactions/index.tsx index d4d66f3e94..344f5c2e71 100644 --- a/explorer/src/providers/transactions/index.tsx +++ b/explorer/src/providers/transactions/index.tsx @@ -5,7 +5,7 @@ import { Connection, SignatureResult, } from "@solana/web3.js"; -import { useCluster } from "../cluster"; +import { useCluster, Cluster } from "../cluster"; import { DetailsProvider } from "./details"; import * as Cache from "providers/cache"; import { ActionType, FetchStatus } from "providers/cache"; @@ -56,6 +56,7 @@ export function TransactionsProvider({ children }: TransactionsProviderProps) { export async function fetchTransactionStatus( dispatch: Dispatch, signature: TransactionSignature, + cluster: Cluster, url: string ) { dispatch({ @@ -84,7 +85,9 @@ export async function fetchTransactionStatus( try { blockTime = await connection.getBlockTime(value.slot); } catch (error) { - Sentry.captureException(error, { tags: { slot: `${value.slot}` } }); + Sentry.captureException(error, { + tags: { slot: `${value.slot}`, url }, + }); } let timestamp: Timestamp = blockTime !== null ? blockTime : "unavailable"; @@ -106,7 +109,9 @@ export async function fetchTransactionStatus( data = { signature, info }; fetchStatus = FetchStatus.Fetched; } catch (error) { - Sentry.captureException(error, { tags: { url } }); + if (cluster !== Cluster.Custom) { + Sentry.captureException(error, { tags: { url } }); + } fetchStatus = FetchStatus.FetchFailed; } } @@ -156,8 +161,11 @@ export function useFetchTransactionStatus() { ); } - const { url } = useCluster(); - return (signature: TransactionSignature) => { - fetchTransactionStatus(dispatch, signature, url); - }; + const { cluster, url } = useCluster(); + return React.useCallback( + (signature: TransactionSignature) => { + fetchTransactionStatus(dispatch, signature, cluster, url); + }, + [dispatch, cluster, url] + ); }