explorer: Introduce flagged accounts provider (#15161)
This commit is contained in:
parent
9e39b815f7
commit
0da11af827
|
@ -28,7 +28,7 @@ import { SlotHashesCard } from "components/account/SlotHashesCard";
|
||||||
import { StakeHistoryCard } from "components/account/StakeHistoryCard";
|
import { StakeHistoryCard } from "components/account/StakeHistoryCard";
|
||||||
import { BlockhashesCard } from "components/account/BlockhashesCard";
|
import { BlockhashesCard } from "components/account/BlockhashesCard";
|
||||||
import { ConfigAccountSection } from "components/account/ConfigAccountSection";
|
import { ConfigAccountSection } from "components/account/ConfigAccountSection";
|
||||||
import { isScamAccount } from "scamRegistry";
|
import { useFlaggedAccounts } from "providers/accounts/flagged-accounts";
|
||||||
|
|
||||||
const TABS_LOOKUP: { [id: string]: Tab } = {
|
const TABS_LOOKUP: { [id: string]: Tab } = {
|
||||||
"spl-token:mint": {
|
"spl-token:mint": {
|
||||||
|
@ -130,7 +130,7 @@ function DetailsSections({ pubkey, tab }: { pubkey: PublicKey; tab?: string }) {
|
||||||
const info = useAccountInfo(address);
|
const info = useAccountInfo(address);
|
||||||
const { status } = useCluster();
|
const { status } = useCluster();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const isScam = isScamAccount(address);
|
const { flaggedAccounts } = useFlaggedAccounts();
|
||||||
|
|
||||||
// Fetch account on load
|
// Fetch account on load
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -159,7 +159,7 @@ function DetailsSections({ pubkey, tab }: { pubkey: PublicKey; tab?: string }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isScam && (
|
{flaggedAccounts.has(address) && (
|
||||||
<div className="alert alert-danger alert-scam" role="alert">
|
<div className="alert alert-danger alert-scam" role="alert">
|
||||||
Warning! This account has been flagged as a scam account. Please be
|
Warning! This account has been flagged as a scam account. Please be
|
||||||
cautious sending SOL to this account.
|
cautious sending SOL to this account.
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const initialState = new Map();
|
||||||
|
const FlaggedContext = React.createContext<Map<string, boolean>>(initialState);
|
||||||
|
|
||||||
|
type ProviderProps = { children: React.ReactNode };
|
||||||
|
|
||||||
|
export function FlaggedAccountsProvider({ children }: ProviderProps) {
|
||||||
|
const [flaggedAccounts, setFlaggedAccounts] = React.useState<
|
||||||
|
Map<string, boolean>
|
||||||
|
>(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<string, boolean>();
|
||||||
|
body
|
||||||
|
.split("\n")
|
||||||
|
.forEach((account) => flaggedAccounts.set(account, true));
|
||||||
|
setFlaggedAccounts(flaggedAccounts);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FlaggedContext.Provider value={flaggedAccounts}>
|
||||||
|
{children}
|
||||||
|
</FlaggedContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useFlaggedAccounts() {
|
||||||
|
const flaggedAccounts = React.useContext(FlaggedContext);
|
||||||
|
if (!flaggedAccounts) {
|
||||||
|
throw new Error(
|
||||||
|
`useFlaggedAccounts must be used within a AccountsProvider`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { flaggedAccounts };
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import { VoteAccount } from "validators/accounts/vote";
|
||||||
import { NonceAccount } from "validators/accounts/nonce";
|
import { NonceAccount } from "validators/accounts/nonce";
|
||||||
import { SysvarAccount } from "validators/accounts/sysvar";
|
import { SysvarAccount } from "validators/accounts/sysvar";
|
||||||
import { ConfigAccount } from "validators/accounts/config";
|
import { ConfigAccount } from "validators/accounts/config";
|
||||||
|
import { FlaggedAccountsProvider } from "./flagged-accounts";
|
||||||
export { useAccountHistory } from "./history";
|
export { useAccountHistory } from "./history";
|
||||||
|
|
||||||
export type StakeProgramData = {
|
export type StakeProgramData = {
|
||||||
|
@ -92,7 +93,9 @@ export function AccountsProvider({ children }: AccountsProviderProps) {
|
||||||
<StateContext.Provider value={state}>
|
<StateContext.Provider value={state}>
|
||||||
<DispatchContext.Provider value={dispatch}>
|
<DispatchContext.Provider value={dispatch}>
|
||||||
<TokensProvider>
|
<TokensProvider>
|
||||||
<HistoryProvider>{children}</HistoryProvider>
|
<HistoryProvider>
|
||||||
|
<FlaggedAccountsProvider>{children}</FlaggedAccountsProvider>
|
||||||
|
</HistoryProvider>
|
||||||
</TokensProvider>
|
</TokensProvider>
|
||||||
</DispatchContext.Provider>
|
</DispatchContext.Provider>
|
||||||
</StateContext.Provider>
|
</StateContext.Provider>
|
||||||
|
|
|
@ -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;
|
|
||||||
}, {});
|
|
||||||
}
|
|
Loading…
Reference in New Issue