feat: add solana-token-registry to explorer (#15496)

* feat: add solana-token-registry to explorer

* feat: bump version for token-registry

* fix: ensure tokenName and tokenSymbol exist in incoming json
This commit is contained in:
Josh 2021-02-24 12:30:55 -08:00 committed by GitHub
parent 5b54aed1c0
commit 2483a05786
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 148 additions and 358 deletions

View File

@ -2598,6 +2598,14 @@
"@sinonjs/commons": "^1.7.0"
}
},
"@solana/spl-token-registry": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/@solana/spl-token-registry/-/spl-token-registry-0.1.4.tgz",
"integrity": "sha512-gJ7dW8G3sYy/kgrYykjt5+01Tpl3jGxOg+5cmLAcgrFIt9zbD22gXdINxznObIaviahiFCfpLPiTfqHmW9fvEA==",
"requires": {
"cross-fetch": "^3.0.6"
}
},
"@solana/web3.js": {
"version": "0.92.2",
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-0.92.2.tgz",

View File

@ -6,6 +6,7 @@
"@project-serum/serum": "^0.13.23",
"@react-hook/debounce": "^3.0.0",
"@sentry/react": "^6.2.0",
"@solana/spl-token-registry": "^0.1.4",
"@solana/web3.js": "^0.92.2",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",

View File

@ -10,14 +10,16 @@ import {
LoaderName,
SEARCHABLE_PROGRAMS,
} from "utils/tx";
import { TokenRegistry } from "tokenRegistry";
import { Cluster, useCluster } from "providers/cluster";
import { useTokenRegistry } from "providers/mints/token-registry";
import { KnownTokenMap } from "@solana/spl-token-registry";
export function SearchBar() {
const [search, setSearch] = React.useState("");
const selectRef = React.useRef<StateManager<any> | null>(null);
const history = useHistory();
const location = useLocation();
const { tokenRegistry } = useTokenRegistry();
const { cluster } = useCluster();
const onChange = (
@ -41,7 +43,7 @@ export function SearchBar() {
<div className="col">
<Select
ref={(ref) => (selectRef.current = ref)}
options={buildOptions(search, cluster)}
options={buildOptions(search, cluster, tokenRegistry)}
noOptionsMessage={() => "No Results"}
placeholder="Search for blocks, accounts, transactions, programs, and tokens"
value={resetValue}
@ -138,13 +140,17 @@ function buildSysvarOptions(search: string) {
}
}
function buildTokenOptions(search: string, cluster: Cluster) {
const matchedTokens = Object.entries(TokenRegistry.all(cluster)).filter(
function buildTokenOptions(
search: string,
cluster: Cluster,
tokenRegistry: KnownTokenMap
) {
const matchedTokens = Array.from(tokenRegistry.entries()).filter(
([address, details]) => {
const searchLower = search.toLowerCase();
return (
details.name.toLowerCase().includes(searchLower) ||
details.symbol.toLowerCase().includes(searchLower) ||
details.tokenName.toLowerCase().includes(searchLower) ||
details.tokenSymbol.toLowerCase().includes(searchLower) ||
address.includes(search)
);
}
@ -154,15 +160,19 @@ function buildTokenOptions(search: string, cluster: Cluster) {
return {
label: "Tokens",
options: matchedTokens.map(([id, details]) => ({
label: details.name,
value: [details.name, details.symbol, id],
label: details.tokenName,
value: [details.tokenName, details.tokenSymbol, id],
pathname: "/address/" + id,
})),
};
}
}
function buildOptions(rawSearch: string, cluster: Cluster) {
function buildOptions(
rawSearch: string,
cluster: Cluster,
tokenRegistry: KnownTokenMap
) {
const search = rawSearch.trim();
if (search.length === 0) return [];
@ -183,7 +193,7 @@ function buildOptions(rawSearch: string, cluster: Cluster) {
options.push(sysvarOptions);
}
const tokenOptions = buildTokenOptions(search, cluster);
const tokenOptions = buildTokenOptions(search, cluster, tokenRegistry);
if (tokenOptions) {
options.push(tokenOptions);
}

View File

@ -9,11 +9,10 @@ import {
import { ErrorCard } from "components/common/ErrorCard";
import { LoadingCard } from "components/common/LoadingCard";
import { Address } from "components/common/Address";
import { TokenRegistry } from "tokenRegistry";
import { useQuery } from "utils/url";
import { Link } from "react-router-dom";
import { Location } from "history";
import { useCluster } from "providers/cluster";
import { useTokenRegistry } from "providers/mints/token-registry";
type Display = "summary" | "detail" | null;
@ -90,15 +89,14 @@ export function OwnedTokensCard({ pubkey }: { pubkey: PublicKey }) {
function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
const detailsList: React.ReactNode[] = [];
const { cluster } = useCluster();
const { tokenRegistry } = useTokenRegistry();
const showLogos = tokens.some(
(t) =>
TokenRegistry.get(t.info.mint.toBase58(), cluster)?.icon !== undefined
(t) => tokenRegistry.get(t.info.mint.toBase58())?.icon !== undefined
);
tokens.forEach((tokenAccount) => {
const address = tokenAccount.pubkey.toBase58();
const mintAddress = tokenAccount.info.mint.toBase58();
const tokenDetails = TokenRegistry.get(mintAddress, cluster);
const tokenDetails = tokenRegistry.get(mintAddress);
detailsList.push(
<tr key={address}>
{showLogos && (
@ -120,7 +118,7 @@ function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
</td>
<td>
{tokenAccount.info.tokenAmount.uiAmount}{" "}
{tokenDetails && tokenDetails.symbol}
{tokenDetails && tokenDetails.tokenSymbol}
</td>
</tr>
);
@ -146,7 +144,7 @@ function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
}
function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
const { cluster } = useCluster();
const { tokenRegistry } = useTokenRegistry();
const mappedTokens = new Map<string, number>();
for (const { info: token } of tokens) {
const mintAddress = token.mint.toBase58();
@ -162,11 +160,10 @@ function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
const detailsList: React.ReactNode[] = [];
const showLogos = tokens.some(
(t) =>
TokenRegistry.get(t.info.mint.toBase58(), cluster)?.icon !== undefined
(t) => tokenRegistry.get(t.info.mint.toBase58())?.icon !== undefined
);
mappedTokens.forEach((totalByMint, mintAddress) => {
const tokenDetails = TokenRegistry.get(mintAddress, cluster);
const tokenDetails = tokenRegistry.get(mintAddress);
detailsList.push(
<tr key={mintAddress}>
{showLogos && (
@ -184,7 +181,7 @@ function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
<Address pubkey={new PublicKey(mintAddress)} link />
</td>
<td>
{totalByMint} {tokenDetails && tokenDetails.symbol}
{totalByMint} {tokenDetails && tokenDetails.tokenSymbol}
</td>
</tr>
);

View File

@ -10,11 +10,11 @@ import { coerce } from "superstruct";
import { TableCardBody } from "components/common/TableCardBody";
import { Address } from "components/common/Address";
import { UnknownAccountCard } from "./UnknownAccountCard";
import { TokenRegistry } from "tokenRegistry";
import { useCluster } from "providers/cluster";
import { normalizeTokenAmount } from "utils";
import { addressLabel } from "utils/tx";
import { reportError } from "utils/sentry";
import { useTokenRegistry } from "providers/mints/token-registry";
export function TokenAccountSection({
account,
@ -53,12 +53,12 @@ function MintAccountCard({
account: Account;
info: MintAccountInfo;
}) {
const { cluster } = useCluster();
const { tokenRegistry } = useTokenRegistry();
const mintAddress = account.pubkey.toBase58();
const fetchInfo = useFetchAccountInfo();
const refresh = () => fetchInfo(account.pubkey);
const tokenInfo = TokenRegistry.get(mintAddress, cluster);
const tokenInfo = tokenRegistry.get(mintAddress);
return (
<div className="card">
<div className="card-header">
@ -143,8 +143,8 @@ function TokenAccountCard({
}) {
const refresh = useFetchAccountInfo();
const { cluster } = useCluster();
const label = addressLabel(account.pubkey.toBase58(), cluster);
const { tokenRegistry } = useTokenRegistry();
const label = addressLabel(account.pubkey.toBase58(), cluster, tokenRegistry);
let unit, balance;
if (info.isNative) {
@ -161,7 +161,7 @@ function TokenAccountCard({
);
} else {
balance = <>{info.tokenAmount.uiAmount}</>;
unit = TokenRegistry.get(info.mint.toBase58(), cluster)?.symbol || "tokens";
unit = tokenRegistry.get(info.mint.toBase58())?.tokenSymbol || "tokens";
}
return (

View File

@ -50,6 +50,8 @@ import { useCluster, Cluster } from "providers/cluster";
import { Link } from "react-router-dom";
import { Location } from "history";
import { useQuery } from "utils/url";
import { KnownTokenMap } from "@solana/spl-token-registry";
import { useTokenRegistry } from "providers/mints/token-registry";
const TRUNCATE_TOKEN_LENGTH = 10;
const ALL_TOKENS = "";
@ -299,6 +301,7 @@ function TokenHistoryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
const FilterDropdown = ({ filter, toggle, show, tokens }: FilterProps) => {
const { cluster } = useCluster();
const { tokenRegistry } = useTokenRegistry();
const buildLocation = (location: Location, filter: string) => {
const params = new URLSearchParams(location.search);
@ -319,7 +322,7 @@ const FilterDropdown = ({ filter, toggle, show, tokens }: FilterProps) => {
tokens.forEach((token) => {
const pubkey = token.info.mint.toBase58();
filterOptions.push(pubkey);
nameLookup[pubkey] = formatTokenName(pubkey, cluster);
nameLookup[pubkey] = formatTokenName(pubkey, cluster, tokenRegistry);
});
return (
@ -349,7 +352,7 @@ const FilterDropdown = ({ filter, toggle, show, tokens }: FilterProps) => {
>
{filterOption === ALL_TOKENS
? "All Tokens"
: formatTokenName(filterOption, cluster)}
: formatTokenName(filterOption, cluster, tokenRegistry)}
</Link>
);
})}
@ -602,8 +605,12 @@ function InstructionDetails({
);
}
function formatTokenName(pubkey: string, cluster: Cluster): string {
let display = displayAddress(pubkey, cluster);
function formatTokenName(
pubkey: string,
cluster: Cluster,
tokenRegistry: KnownTokenMap
): string {
let display = displayAddress(pubkey, cluster, tokenRegistry);
if (display === pubkey) {
display = display.slice(0, TRUNCATE_TOKEN_LENGTH) + "\u2026";

View File

@ -9,10 +9,9 @@ import {
TokenAccountBalancePairWithOwner,
} from "providers/mints/largest";
import { FetchStatus } from "providers/cache";
import { TokenRegistry } from "tokenRegistry";
import { useCluster } from "providers/cluster";
import { useMintAccountInfo } from "providers/accounts";
import { normalizeTokenAmount } from "utils";
import { useTokenRegistry } from "providers/mints/token-registry";
export function TokenLargestAccountsCard({ pubkey }: { pubkey: PublicKey }) {
const mintAddress = pubkey.toBase58();
@ -23,8 +22,8 @@ export function TokenLargestAccountsCard({ pubkey }: { pubkey: PublicKey }) {
pubkey,
fetchLargestAccounts,
]);
const { cluster } = useCluster();
const unit = TokenRegistry.get(mintAddress, cluster)?.symbol;
const { tokenRegistry } = useTokenRegistry();
const unit = tokenRegistry.get(mintAddress)?.tokenSymbol;
const unitLabel = unit ? `(${unit})` : "";
React.useEffect(() => {

View File

@ -5,13 +5,15 @@ import { TableCardBody } from "components/common/TableCardBody";
import { Address } from "components/common/Address";
import { addressLabel } from "utils/tx";
import { useCluster } from "providers/cluster";
import { useTokenRegistry } from "providers/mints/token-registry";
export function UnknownAccountCard({ account }: { account: Account }) {
const { details, lamports } = account;
const { cluster } = useCluster();
const { tokenRegistry } = useTokenRegistry();
if (lamports === undefined) return null;
const label = addressLabel(account.pubkey.toBase58(), cluster);
const label = addressLabel(account.pubkey.toBase58(), cluster, tokenRegistry);
return (
<div className="card">
<div className="card-header align-items-center">

View File

@ -5,6 +5,7 @@ import { clusterPath } from "utils/url";
import { displayAddress } from "utils/tx";
import { useCluster } from "providers/cluster";
import { Copyable } from "./Copyable";
import { useTokenRegistry } from "providers/mints/token-registry";
type Props = {
pubkey: PublicKey;
@ -24,9 +25,13 @@ export function Address({
truncateUnknown,
}: Props) {
const address = pubkey.toBase58();
const { tokenRegistry } = useTokenRegistry();
const { cluster } = useCluster();
if (truncateUnknown && address === displayAddress(address, cluster)) {
if (
truncateUnknown &&
address === displayAddress(address, cluster, tokenRegistry)
) {
truncate = true;
}
@ -38,11 +43,11 @@ export function Address({
className={truncate ? "text-truncate address-truncate" : ""}
to={clusterPath(`/address/${address}`)}
>
{raw ? address : displayAddress(address, cluster)}
{raw ? address : displayAddress(address, cluster, tokenRegistry)}
</Link>
) : (
<span className={truncate ? "text-truncate address-truncate" : ""}>
{raw ? address : displayAddress(address, cluster)}
{raw ? address : displayAddress(address, cluster, tokenRegistry)}
</span>
)}
</span>

View File

@ -24,8 +24,7 @@ import {
} from "providers/accounts";
import { normalizeTokenAmount } from "utils";
import { reportError } from "utils/sentry";
import { useCluster } from "providers/cluster";
import { TokenRegistry } from "tokenRegistry";
import { useTokenRegistry } from "providers/mints/token-registry";
type DetailsProps = {
tx: ParsedTransaction;
@ -92,7 +91,7 @@ function TokenInstruction(props: InfoProps) {
const tokenInfo = useTokenAccountInfo(tokenAddress);
const mintAddress = infoMintAddress || tokenInfo?.mint.toBase58();
const mintInfo = useMintAccountInfo(mintAddress);
const { cluster } = useCluster();
const { tokenRegistry } = useTokenRegistry();
const fetchAccountInfo = useFetchAccountInfo();
React.useEffect(() => {
@ -116,10 +115,10 @@ function TokenInstruction(props: InfoProps) {
}
if (mintAddress) {
const tokenDetails = TokenRegistry.get(mintAddress, cluster);
const tokenDetails = tokenRegistry.get(mintAddress);
if (tokenDetails && "symbol" in tokenDetails) {
tokenSymbol = tokenDetails.symbol;
if (tokenDetails) {
tokenSymbol = tokenDetails.tokenSymbol;
}
attributes.push(

View File

@ -9,9 +9,8 @@ import { BigNumber } from "bignumber.js";
import { Address } from "components/common/Address";
import { BalanceDelta } from "components/common/BalanceDelta";
import { SignatureProps } from "pages/TransactionDetailsPage";
import { useCluster } from "providers/cluster";
import { useTransactionDetails } from "providers/transactions";
import { TokenRegistry } from "tokenRegistry";
import { useTokenRegistry } from "providers/mints/token-registry";
type TokenBalanceRow = {
account: PublicKey;
@ -23,7 +22,7 @@ type TokenBalanceRow = {
export function TokenBalancesCard({ signature }: SignatureProps) {
const details = useTransactionDetails(signature);
const { cluster } = useCluster();
const { tokenRegistry } = useTokenRegistry();
if (!details) {
return null;
@ -51,7 +50,7 @@ export function TokenBalancesCard({ signature }: SignatureProps) {
const accountRows = rows.map(({ account, delta, balance, mint }) => {
const key = account.toBase58() + mint;
const units = TokenRegistry.get(mint, cluster)?.symbol || "tokens";
const units = tokenRegistry.get(mint)?.tokenSymbol || "tokens";
return (
<tr key={key}>

View File

@ -19,7 +19,6 @@ import { OwnedTokensCard } from "components/account/OwnedTokensCard";
import { TransactionHistoryCard } from "components/account/TransactionHistoryCard";
import { TokenHistoryCard } from "components/account/TokenHistoryCard";
import { TokenLargestAccountsCard } from "components/account/TokenLargestAccountsCard";
import { TokenRegistry } from "tokenRegistry";
import { VoteAccountSection } from "components/account/VoteAccountSection";
import { NonceAccountSection } from "components/account/NonceAccountSection";
import { VotesCard } from "components/account/VotesCard";
@ -30,6 +29,7 @@ import { BlockhashesCard } from "components/account/BlockhashesCard";
import { ConfigAccountSection } from "components/account/ConfigAccountSection";
import { useFlaggedAccounts } from "providers/accounts/flagged-accounts";
import { UpgradeableProgramSection } from "components/account/UpgradeableProgramSection";
import { useTokenRegistry } from "providers/mints/token-registry";
const TABS_LOOKUP: { [id: string]: Tab } = {
"spl-token:mint": {
@ -92,16 +92,16 @@ export function AccountDetailsPage({ address, tab }: Props) {
}
export function AccountHeader({ address }: { address: string }) {
const { cluster } = useCluster();
const tokenDetails = TokenRegistry.get(address, cluster);
const { tokenRegistry } = useTokenRegistry();
const tokenDetails = tokenRegistry.get(address);
if (tokenDetails) {
return (
<div className="row align-items-end">
{tokenDetails.logo && (
{tokenDetails.icon && (
<div className="col-auto">
<div className="avatar avatar-lg header-avatar-top">
<img
src={tokenDetails.logo}
src={tokenDetails.icon}
alt="token logo"
className="avatar-img rounded-circle border border-4 border-body"
/>
@ -111,7 +111,7 @@ export function AccountHeader({ address }: { address: string }) {
<div className="col mb-3 ml-n3 ml-md-n2">
<h6 className="header-pretitle">Token</h6>
<h2 className="header-title">{tokenDetails.name}</h2>
<h2 className="header-title">{tokenDetails.tokenName}</h2>
</div>
</div>
);

View File

@ -1,7 +1,12 @@
import React from "react";
import { LargestAccountsProvider } from "./largest";
import { TokenRegistryProvider } from "./token-registry";
type ProviderProps = { children: React.ReactNode };
export function MintsProvider({ children }: ProviderProps) {
return <LargestAccountsProvider>{children}</LargestAccountsProvider>;
return (
<TokenRegistryProvider>
<LargestAccountsProvider>{children}</LargestAccountsProvider>
</TokenRegistryProvider>
);
}

View File

@ -0,0 +1,49 @@
import React from "react";
import {
TokenListProvider,
KnownToken,
KnownTokenMap,
} from "@solana/spl-token-registry";
import { clusterSlug, useCluster } from "providers/cluster";
const TokenRegistryContext = React.createContext<KnownTokenMap>(new Map());
type ProviderProps = { children: React.ReactNode };
export function TokenRegistryProvider({ children }: ProviderProps) {
const [tokenRegistry, setTokenRegistry] = React.useState<KnownTokenMap>(
new Map()
);
const { cluster } = useCluster();
React.useEffect(() => {
new TokenListProvider()
.resolve(clusterSlug(cluster))
.then((tokens: KnownToken[]) => {
setTokenRegistry(
tokens.reduce((map: KnownTokenMap, item: KnownToken) => {
if (item.tokenName && item.tokenSymbol) {
map.set(item.mintAddress, item);
}
return map;
}, new Map())
);
});
}, [cluster]);
return (
<TokenRegistryContext.Provider value={tokenRegistry}>
{children}
</TokenRegistryContext.Provider>
);
}
export function useTokenRegistry() {
const tokenRegistry = React.useContext(TokenRegistryContext);
if (!tokenRegistry) {
throw new Error(`useTokenRegistry must be used within a MintsProvider`);
}
return { tokenRegistry };
}

View File

@ -1,296 +0,0 @@
import { Cluster } from "providers/cluster";
export type TokenDetails = {
name: string;
symbol: string;
logo?: string;
icon?: string;
website?: string;
};
function get(address: string, cluster: Cluster): TokenDetails | undefined {
if (cluster === Cluster.MainnetBeta) return MAINNET_TOKENS[address];
}
function all(cluster: Cluster) {
if (cluster === Cluster.MainnetBeta) return MAINNET_TOKENS;
return {};
}
export const TokenRegistry = {
get,
all,
};
const MAINNET_TOKENS: { [key: string]: TokenDetails } = {
SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt: {
name: "Serum",
symbol: "SRM",
logo: "/tokens/serum-64.png",
icon: "/tokens/serum-32.png",
website: "https://projectserum.com",
},
MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L: {
name: "MegaSerum",
symbol: "MSRM",
logo: "/tokens/serum-64.png",
icon: "/tokens/serum-32.png",
website: "https://projectserum.com",
},
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v: {
symbol: "USDC",
name: "USD Coin",
logo: "/tokens/usdc.svg",
icon: "/tokens/usdc.svg",
website: "https://www.centre.io/",
},
"9S4t2NEAiJVMvPdRYKVrfJpBafPBLtvbvyS3DecojQHw": {
symbol: "FRONT",
name: "Wrapped FRONT",
logo: "/tokens/front.svg",
icon: "/tokens/front.svg",
website: "https://frontier.xyz/",
},
"9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E": {
symbol: "BTC",
name: "Wrapped Bitcoin",
logo: "/tokens/bitcoin.svg",
icon: "/tokens/bitcoin.svg",
},
"2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk": {
symbol: "ETH",
name: "Wrapped Ethereum",
logo: "/tokens/ethereum.svg",
icon: "/tokens/ethereum.svg",
},
AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3: {
symbol: "FTT",
name: "Wrapped FTT",
logo: "/tokens/ftt.svg",
icon: "/tokens/ftt.svg",
},
"3JSf5tPeuscJGtaCp5giEiDhv51gQ4v3zWg8DGgyLfAB": {
symbol: "YFI",
name: "Wrapped YFI",
logo: "/tokens/yfi.svg",
icon: "/tokens/yfi.svg",
},
CWE8jPTUYhdCTZYWPTe1o5DFqfdjzWKc9WKz6rSjQUdG: {
symbol: "LINK",
name: "Wrapped Chainlink",
logo: "/tokens/link.svg",
icon: "/tokens/link.svg",
},
Ga2AXHpfAF6mv2ekZwcsJFqu7wB4NV331qNH7fW9Nst8: {
symbol: "XRP",
name: "Wrapped XRP",
logo: "/tokens/xrp.svg",
icon: "/tokens/xrp.svg",
},
BQcdHdAQW1hczDbBi9hiegXAR7A98Q9jx3X3iBBBDiq4: {
symbol: "USDT",
name: "Wrapped USDT",
logo: "/tokens/usdt.svg",
icon: "/tokens/usdt.svg",
},
BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW: {
symbol: "USDC",
name: "Wrapped USDC",
},
So11111111111111111111111111111111111111112: {
symbol: "SOL",
name: "Wrapped SOL",
},
SF3oTvfWzEP3DTwGSvUXRrGTvr75pdZNnBLAH9bzMuX: {
symbol: "SXP",
name: "Wrapped Swipe",
logo: "/tokens/sxp.svg",
icon: "/tokens/sxp.svg",
},
BtZQfWqDGbk9Wf2rXEiWyQBdBY1etnUUn6zEphvVS7yN: {
symbol: "HGET",
name: "Wrapped Hedget",
},
"873KLxCbz7s9Kc4ZzgYRtNmhfkQrhfyWGZJBmyCbC3ei": {
symbol: "UBXT",
name: "Wrapped Upbots",
},
CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K: {
symbol: "ALEPH",
name: "Wrapped Aleph",
},
"5Fu5UUgbjpUvdBveb3a1JTNirL8rXtiYeSMWvKjtUNQv": {
symbol: "CREAM",
name: "Wrapped Cream Finance",
logo: "/tokens/cream.svg",
icon: "/tokens/cream.svg",
},
HqB7uswoVg4suaQiDP3wjxob1G5WdZ144zhdStwMCq7e: {
symbol: "HNT",
name: "Wrapped Helium",
},
AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy: {
symbol: "SUSHI",
name: "Wrapped Sushi",
},
AcstFzGGawvvdVhYV9bftr7fmBHbePUjhv53YK1W3dZo: {
symbol: "LSD",
name: "LSD",
website: "https://solible.com",
},
"91fSFQsPzMLat9DHwLdQacW3i3EGnWds5tA5mt7yLiT9": {
symbol: "Unlimited Energy",
name: "Unlimited Energy",
website: "https://solible.com",
},
"29PEpZeuqWf9tS2gwCjpeXNdXLkaZSMR2s1ibkvGsfnP": {
symbol: "Need for Speed",
name: "Need for Speed",
website: "https://solible.com",
},
HsY8PNar8VExU335ZRYzg89fX7qa4upYu6vPMPFyCDdK: {
symbol: "ADOR OPENS",
name: "ADOR OPENS",
website: "https://solible.com",
},
EDP8TpLJ77M3KiDgFkZW4v4mhmKJHZi9gehYXenfFZuL: {
symbol: "CMS - Rare",
name: "CMS - Rare",
website: "https://solible.com",
},
BrUKFwAABkExb1xzYU4NkRWzjBihVQdZ3PBz4m5S8if3: {
symbol: "Tesla",
name: "Tesla",
website: "https://solible.com",
},
"9CmQwpvVXRyixjiE3LrbSyyopPZohNDN1RZiTk8rnXsQ": {
symbol: "DeceFi",
name: "DeceFi",
website: "https://solible.com",
},
F6ST1wWkx2PeH45sKmRxo1boyuzzWCfpnvyKL4BGeLxF: {
symbol: "Power User",
name: "Power User",
website: "https://solible.com",
},
dZytJ7iPDcCu9mKe3srL7bpUeaR3zzkcVqbtqsmxtXZ: {
symbol: "VIP Member",
name: "VIP Member",
website: "https://solible.com",
},
"8T4vXgwZUWwsbCDiptHFHjdfexvLG9UP8oy1psJWEQdS": {
symbol: "Uni Christmas",
name: "Uni Christmas",
website: "https://solible.com",
},
EjFGGJSyp9UDS8aqafET5LX49nsG326MeNezYzpiwgpQ: {
symbol: "BNB",
name: "BNB",
website: "https://solible.com",
},
FkmkTr4en8CXkfo9jAwEMov6PVNLpYMzWr3Udqf9so8Z: {
symbol: "Seldom",
name: "Seldom",
website: "https://solible.com",
},
"2gn1PJdMAU92SU5inLSp4Xp16ZC5iLF6ScEi7UBvp8ZD": {
symbol: "Satoshi Closeup",
name: "Satoshi Closeup",
website: "https://solible.com",
},
"7mhZHtPL4GFkquQR4Y6h34Q8hNkQvGc1FaNtyE43NvUR": {
symbol: "Satoshi GB",
name: "Satoshi GB",
website: "https://solible.com",
},
"8RoKfLx5RCscbtVh8kYb81TF7ngFJ38RPomXtUREKsT2": {
symbol: "Satoshi OG",
name: "Satoshi OG",
website: "https://solible.com",
},
"9rw5hyDngBQ3yDsCRHqgzGHERpU2zaLh1BXBUjree48J": {
symbol: "Satoshi BTC",
name: "Satoshi BTC",
website: "https://solible.com",
},
AiD7J6D5Hny5DJB1MrYBc2ePQqy2Yh4NoxWwYfR7PzxH: {
symbol: "Satoshi GB",
name: "Satoshi GB",
website: "https://solible.com",
},
bxiA13fpU1utDmYuUvxvyMT8odew5FEm96MRv7ij3eb: {
symbol: "Satoshi",
name: "Satoshi",
website: "https://solible.com",
},
GoC24kpj6TkvjzspXrjSJC2CVb5zMWhLyRcHJh9yKjRF: {
symbol: "Satoshi Closeup",
name: "Satoshi Closeup",
website: "https://solible.com",
},
oCUduD44ETuZ65bpWdPzPDSnAdreg1sJrugfwyFZVHV: {
symbol: "Satoshi BTC",
name: "Satoshi BTC",
website: "https://solible.com",
},
"9Vvre2DxBB9onibwYDHeMsY1cj6BDKtEDccBPWRN215E": {
symbol: "Satoshi Nakamoto",
name: "Satoshi Nakamoto",
website: "https://solible.com",
},
"7RpFk44cMTAUt9CcjEMWnZMypE9bYQsjBiSNLn5qBvhP": {
symbol: "Charles Hoskinson",
name: "Charles Hoskinson",
website: "https://solible.com",
},
GyRkPAxpd9XrMHcBF6fYHVRSZQvQBwAGKAGQeBPSKzMq: {
symbol: "SBF",
name: "SBF",
website: "https://solible.com",
},
AgdBQN2Sy2abiZ2KToWeUsQ9PHdCv95wt6kVWRf5zDkx: {
symbol: "Bitcoin Tram",
name: "Bitcoin Tram",
website: "https://solible.com",
},
"7TRzvCqXN8KSXggbSyeEG2Z9YBBhEFmbtmv6FLbd4mmd": {
symbol: "SRM tee-shirt",
name: "SRM tee-shirt",
website: "https://solible.com",
},
EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp: {
symbol: "FIDA",
name: "FIDA",
logo: "/tokens/fida.svg",
icon: "/tokens/fida.svg",
website: "https://bonfida.com",
},
kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6: {
symbol: "KIN",
name: "KIN",
logo: "/tokens/kin.svg",
icon: "/tokens/kin.svg",
website: "https://kin.org",
},
FtgGSFADXBtroxq8VCausXRr2of47QBf5AS1NtZCu4GD: {
symbol: "BRZ",
name: "BRZ",
logo: "/tokens/brz.png",
icon: "/tokens/brz.png",
website: "https://brztoken.io",
},
MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb: {
symbol: "MAPS",
name: "MAPS",
logo: "/tokens/maps.svg",
icon: "/tokens/maps.svg",
website: "https://maps.me/",
},
Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB: {
symbol: "USDT",
name: "USDT",
logo: "/tokens/usdt.svg",
icon: "/tokens/usdt.svg",
website: "https://tether.to",
},
};

View File

@ -15,9 +15,9 @@ import {
PartiallyDecodedInstruction,
ParsedInstruction,
} from "@solana/web3.js";
import { TokenRegistry } from "tokenRegistry";
import { Cluster } from "providers/cluster";
import { SerumMarketRegistry } from "serumMarketRegistry";
import { KnownTokenMap } from "@solana/spl-token-registry";
export type ProgramName = typeof PROGRAM_NAME_BY_ID[keyof typeof PROGRAM_NAME_BY_ID];
@ -102,20 +102,25 @@ export const SYSVAR_IDS = {
export function addressLabel(
address: string,
cluster: Cluster
cluster: Cluster,
tokenRegistry: KnownTokenMap
): string | undefined {
return (
PROGRAM_NAME_BY_ID[address] ||
LOADER_IDS[address] ||
SYSVAR_IDS[address] ||
SYSVAR_ID[address] ||
TokenRegistry.get(address, cluster)?.name ||
tokenRegistry.get(address)?.tokenName ||
SerumMarketRegistry.get(address, cluster)
);
}
export function displayAddress(address: string, cluster: Cluster): string {
return addressLabel(address, cluster) || address;
export function displayAddress(
address: string,
cluster: Cluster,
tokenRegistry: KnownTokenMap
): string {
return addressLabel(address, cluster, tokenRegistry) || address;
}
export function intoTransactionInstruction(