diff --git a/explorer/src/pages/AccountDetailsPage.tsx b/explorer/src/pages/AccountDetailsPage.tsx index 79f34c1c10..b9b0ae77ce 100644 --- a/explorer/src/pages/AccountDetailsPage.tsx +++ b/explorer/src/pages/AccountDetailsPage.tsx @@ -28,7 +28,7 @@ import { SlotHashesCard } from "components/account/SlotHashesCard"; import { StakeHistoryCard } from "components/account/StakeHistoryCard"; import { BlockhashesCard } from "components/account/BlockhashesCard"; import { ConfigAccountSection } from "components/account/ConfigAccountSection"; -import { isScamAccount } from "scamRegistry"; +import { useFlaggedAccounts } from "providers/accounts/flagged-accounts"; const TABS_LOOKUP: { [id: string]: Tab } = { "spl-token:mint": { @@ -130,7 +130,7 @@ function DetailsSections({ pubkey, tab }: { pubkey: PublicKey; tab?: string }) { const info = useAccountInfo(address); const { status } = useCluster(); const location = useLocation(); - const isScam = isScamAccount(address); + const { flaggedAccounts } = useFlaggedAccounts(); // Fetch account on load React.useEffect(() => { @@ -159,7 +159,7 @@ function DetailsSections({ pubkey, tab }: { pubkey: PublicKey; tab?: string }) { return ( <> - {isScam && ( + {flaggedAccounts.has(address) && (
Warning! This account has been flagged as a scam account. Please be cautious sending SOL to this account. diff --git a/explorer/src/providers/accounts/flagged-accounts.tsx b/explorer/src/providers/accounts/flagged-accounts.tsx new file mode 100644 index 0000000000..bd62a93f7f --- /dev/null +++ b/explorer/src/providers/accounts/flagged-accounts.tsx @@ -0,0 +1,46 @@ +import React from "react"; + +const initialState = new Map(); +const FlaggedContext = React.createContext>(initialState); + +type ProviderProps = { children: React.ReactNode }; + +export function FlaggedAccountsProvider({ children }: ProviderProps) { + const [flaggedAccounts, setFlaggedAccounts] = React.useState< + Map + >(initialState); + + React.useEffect(() => { + window + .fetch( + "https://solana-labs.github.io/solana-flagged-accounts/flagged.txt" + ) + .then((res) => { + return res.text(); + }) + .then((body: string) => { + const flaggedAccounts = new Map(); + body + .split("\n") + .forEach((account) => flaggedAccounts.set(account, true)); + setFlaggedAccounts(flaggedAccounts); + }); + }, []); + + return ( + + {children} + + ); +} + +export function useFlaggedAccounts() { + const flaggedAccounts = React.useContext(FlaggedContext); + if (!flaggedAccounts) { + throw new Error( + `useFlaggedAccounts must be used within a AccountsProvider` + ); + } + + return { flaggedAccounts }; +} diff --git a/explorer/src/providers/accounts/index.tsx b/explorer/src/providers/accounts/index.tsx index b317b888c5..283ebc54c0 100644 --- a/explorer/src/providers/accounts/index.tsx +++ b/explorer/src/providers/accounts/index.tsx @@ -18,6 +18,7 @@ import { VoteAccount } from "validators/accounts/vote"; import { NonceAccount } from "validators/accounts/nonce"; import { SysvarAccount } from "validators/accounts/sysvar"; import { ConfigAccount } from "validators/accounts/config"; +import { FlaggedAccountsProvider } from "./flagged-accounts"; export { useAccountHistory } from "./history"; export type StakeProgramData = { @@ -92,7 +93,9 @@ export function AccountsProvider({ children }: AccountsProviderProps) { - {children} + + {children} + diff --git a/explorer/src/scamRegistry.ts b/explorer/src/scamRegistry.ts deleted file mode 100644 index 413ccb30da..0000000000 --- a/explorer/src/scamRegistry.ts +++ /dev/null @@ -1,12 +0,0 @@ -const scamAddresses = toHash(["GACpXND1SSfTSQMmqGuFvGwXB3jGEYBDRGNzmLfTYwSP"]); - -export function isScamAccount(address: string) { - return address in scamAddresses; -} - -function toHash(addresses: string[]) { - return addresses.reduce((prev: { [addr: string]: boolean }, addr) => { - prev[addr] = true; - return prev; - }, {}); -}