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:
8
explorer/package-lock.json
generated
8
explorer/package-lock.json
generated
@ -2598,6 +2598,14 @@
|
|||||||
"@sinonjs/commons": "^1.7.0"
|
"@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": {
|
"@solana/web3.js": {
|
||||||
"version": "0.92.2",
|
"version": "0.92.2",
|
||||||
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-0.92.2.tgz",
|
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-0.92.2.tgz",
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"@project-serum/serum": "^0.13.23",
|
"@project-serum/serum": "^0.13.23",
|
||||||
"@react-hook/debounce": "^3.0.0",
|
"@react-hook/debounce": "^3.0.0",
|
||||||
"@sentry/react": "^6.2.0",
|
"@sentry/react": "^6.2.0",
|
||||||
|
"@solana/spl-token-registry": "^0.1.4",
|
||||||
"@solana/web3.js": "^0.92.2",
|
"@solana/web3.js": "^0.92.2",
|
||||||
"@testing-library/jest-dom": "^5.11.9",
|
"@testing-library/jest-dom": "^5.11.9",
|
||||||
"@testing-library/react": "^11.2.5",
|
"@testing-library/react": "^11.2.5",
|
||||||
|
@ -10,14 +10,16 @@ import {
|
|||||||
LoaderName,
|
LoaderName,
|
||||||
SEARCHABLE_PROGRAMS,
|
SEARCHABLE_PROGRAMS,
|
||||||
} from "utils/tx";
|
} from "utils/tx";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
|
||||||
import { Cluster, useCluster } from "providers/cluster";
|
import { Cluster, useCluster } from "providers/cluster";
|
||||||
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
|
import { KnownTokenMap } from "@solana/spl-token-registry";
|
||||||
|
|
||||||
export function SearchBar() {
|
export function SearchBar() {
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
const selectRef = React.useRef<StateManager<any> | null>(null);
|
const selectRef = React.useRef<StateManager<any> | null>(null);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const { cluster } = useCluster();
|
const { cluster } = useCluster();
|
||||||
|
|
||||||
const onChange = (
|
const onChange = (
|
||||||
@ -41,7 +43,7 @@ export function SearchBar() {
|
|||||||
<div className="col">
|
<div className="col">
|
||||||
<Select
|
<Select
|
||||||
ref={(ref) => (selectRef.current = ref)}
|
ref={(ref) => (selectRef.current = ref)}
|
||||||
options={buildOptions(search, cluster)}
|
options={buildOptions(search, cluster, tokenRegistry)}
|
||||||
noOptionsMessage={() => "No Results"}
|
noOptionsMessage={() => "No Results"}
|
||||||
placeholder="Search for blocks, accounts, transactions, programs, and tokens"
|
placeholder="Search for blocks, accounts, transactions, programs, and tokens"
|
||||||
value={resetValue}
|
value={resetValue}
|
||||||
@ -138,13 +140,17 @@ function buildSysvarOptions(search: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTokenOptions(search: string, cluster: Cluster) {
|
function buildTokenOptions(
|
||||||
const matchedTokens = Object.entries(TokenRegistry.all(cluster)).filter(
|
search: string,
|
||||||
|
cluster: Cluster,
|
||||||
|
tokenRegistry: KnownTokenMap
|
||||||
|
) {
|
||||||
|
const matchedTokens = Array.from(tokenRegistry.entries()).filter(
|
||||||
([address, details]) => {
|
([address, details]) => {
|
||||||
const searchLower = search.toLowerCase();
|
const searchLower = search.toLowerCase();
|
||||||
return (
|
return (
|
||||||
details.name.toLowerCase().includes(searchLower) ||
|
details.tokenName.toLowerCase().includes(searchLower) ||
|
||||||
details.symbol.toLowerCase().includes(searchLower) ||
|
details.tokenSymbol.toLowerCase().includes(searchLower) ||
|
||||||
address.includes(search)
|
address.includes(search)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -154,15 +160,19 @@ function buildTokenOptions(search: string, cluster: Cluster) {
|
|||||||
return {
|
return {
|
||||||
label: "Tokens",
|
label: "Tokens",
|
||||||
options: matchedTokens.map(([id, details]) => ({
|
options: matchedTokens.map(([id, details]) => ({
|
||||||
label: details.name,
|
label: details.tokenName,
|
||||||
value: [details.name, details.symbol, id],
|
value: [details.tokenName, details.tokenSymbol, id],
|
||||||
pathname: "/address/" + id,
|
pathname: "/address/" + id,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOptions(rawSearch: string, cluster: Cluster) {
|
function buildOptions(
|
||||||
|
rawSearch: string,
|
||||||
|
cluster: Cluster,
|
||||||
|
tokenRegistry: KnownTokenMap
|
||||||
|
) {
|
||||||
const search = rawSearch.trim();
|
const search = rawSearch.trim();
|
||||||
if (search.length === 0) return [];
|
if (search.length === 0) return [];
|
||||||
|
|
||||||
@ -183,7 +193,7 @@ function buildOptions(rawSearch: string, cluster: Cluster) {
|
|||||||
options.push(sysvarOptions);
|
options.push(sysvarOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokenOptions = buildTokenOptions(search, cluster);
|
const tokenOptions = buildTokenOptions(search, cluster, tokenRegistry);
|
||||||
if (tokenOptions) {
|
if (tokenOptions) {
|
||||||
options.push(tokenOptions);
|
options.push(tokenOptions);
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,10 @@ import {
|
|||||||
import { ErrorCard } from "components/common/ErrorCard";
|
import { ErrorCard } from "components/common/ErrorCard";
|
||||||
import { LoadingCard } from "components/common/LoadingCard";
|
import { LoadingCard } from "components/common/LoadingCard";
|
||||||
import { Address } from "components/common/Address";
|
import { Address } from "components/common/Address";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
|
||||||
import { useQuery } from "utils/url";
|
import { useQuery } from "utils/url";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Location } from "history";
|
import { Location } from "history";
|
||||||
import { useCluster } from "providers/cluster";
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
|
|
||||||
type Display = "summary" | "detail" | null;
|
type Display = "summary" | "detail" | null;
|
||||||
|
|
||||||
@ -90,15 +89,14 @@ export function OwnedTokensCard({ pubkey }: { pubkey: PublicKey }) {
|
|||||||
|
|
||||||
function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
||||||
const detailsList: React.ReactNode[] = [];
|
const detailsList: React.ReactNode[] = [];
|
||||||
const { cluster } = useCluster();
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const showLogos = tokens.some(
|
const showLogos = tokens.some(
|
||||||
(t) =>
|
(t) => tokenRegistry.get(t.info.mint.toBase58())?.icon !== undefined
|
||||||
TokenRegistry.get(t.info.mint.toBase58(), cluster)?.icon !== undefined
|
|
||||||
);
|
);
|
||||||
tokens.forEach((tokenAccount) => {
|
tokens.forEach((tokenAccount) => {
|
||||||
const address = tokenAccount.pubkey.toBase58();
|
const address = tokenAccount.pubkey.toBase58();
|
||||||
const mintAddress = tokenAccount.info.mint.toBase58();
|
const mintAddress = tokenAccount.info.mint.toBase58();
|
||||||
const tokenDetails = TokenRegistry.get(mintAddress, cluster);
|
const tokenDetails = tokenRegistry.get(mintAddress);
|
||||||
detailsList.push(
|
detailsList.push(
|
||||||
<tr key={address}>
|
<tr key={address}>
|
||||||
{showLogos && (
|
{showLogos && (
|
||||||
@ -120,7 +118,7 @@ function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{tokenAccount.info.tokenAmount.uiAmount}{" "}
|
{tokenAccount.info.tokenAmount.uiAmount}{" "}
|
||||||
{tokenDetails && tokenDetails.symbol}
|
{tokenDetails && tokenDetails.tokenSymbol}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
@ -146,7 +144,7 @@ function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
||||||
const { cluster } = useCluster();
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const mappedTokens = new Map<string, number>();
|
const mappedTokens = new Map<string, number>();
|
||||||
for (const { info: token } of tokens) {
|
for (const { info: token } of tokens) {
|
||||||
const mintAddress = token.mint.toBase58();
|
const mintAddress = token.mint.toBase58();
|
||||||
@ -162,11 +160,10 @@ function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
|||||||
|
|
||||||
const detailsList: React.ReactNode[] = [];
|
const detailsList: React.ReactNode[] = [];
|
||||||
const showLogos = tokens.some(
|
const showLogos = tokens.some(
|
||||||
(t) =>
|
(t) => tokenRegistry.get(t.info.mint.toBase58())?.icon !== undefined
|
||||||
TokenRegistry.get(t.info.mint.toBase58(), cluster)?.icon !== undefined
|
|
||||||
);
|
);
|
||||||
mappedTokens.forEach((totalByMint, mintAddress) => {
|
mappedTokens.forEach((totalByMint, mintAddress) => {
|
||||||
const tokenDetails = TokenRegistry.get(mintAddress, cluster);
|
const tokenDetails = tokenRegistry.get(mintAddress);
|
||||||
detailsList.push(
|
detailsList.push(
|
||||||
<tr key={mintAddress}>
|
<tr key={mintAddress}>
|
||||||
{showLogos && (
|
{showLogos && (
|
||||||
@ -184,7 +181,7 @@ function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
|||||||
<Address pubkey={new PublicKey(mintAddress)} link />
|
<Address pubkey={new PublicKey(mintAddress)} link />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{totalByMint} {tokenDetails && tokenDetails.symbol}
|
{totalByMint} {tokenDetails && tokenDetails.tokenSymbol}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
@ -10,11 +10,11 @@ import { coerce } from "superstruct";
|
|||||||
import { TableCardBody } from "components/common/TableCardBody";
|
import { TableCardBody } from "components/common/TableCardBody";
|
||||||
import { Address } from "components/common/Address";
|
import { Address } from "components/common/Address";
|
||||||
import { UnknownAccountCard } from "./UnknownAccountCard";
|
import { UnknownAccountCard } from "./UnknownAccountCard";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
|
||||||
import { useCluster } from "providers/cluster";
|
import { useCluster } from "providers/cluster";
|
||||||
import { normalizeTokenAmount } from "utils";
|
import { normalizeTokenAmount } from "utils";
|
||||||
import { addressLabel } from "utils/tx";
|
import { addressLabel } from "utils/tx";
|
||||||
import { reportError } from "utils/sentry";
|
import { reportError } from "utils/sentry";
|
||||||
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
|
|
||||||
export function TokenAccountSection({
|
export function TokenAccountSection({
|
||||||
account,
|
account,
|
||||||
@ -53,12 +53,12 @@ function MintAccountCard({
|
|||||||
account: Account;
|
account: Account;
|
||||||
info: MintAccountInfo;
|
info: MintAccountInfo;
|
||||||
}) {
|
}) {
|
||||||
const { cluster } = useCluster();
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const mintAddress = account.pubkey.toBase58();
|
const mintAddress = account.pubkey.toBase58();
|
||||||
const fetchInfo = useFetchAccountInfo();
|
const fetchInfo = useFetchAccountInfo();
|
||||||
const refresh = () => fetchInfo(account.pubkey);
|
const refresh = () => fetchInfo(account.pubkey);
|
||||||
|
|
||||||
const tokenInfo = TokenRegistry.get(mintAddress, cluster);
|
const tokenInfo = tokenRegistry.get(mintAddress);
|
||||||
return (
|
return (
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
@ -143,8 +143,8 @@ function TokenAccountCard({
|
|||||||
}) {
|
}) {
|
||||||
const refresh = useFetchAccountInfo();
|
const refresh = useFetchAccountInfo();
|
||||||
const { cluster } = useCluster();
|
const { cluster } = useCluster();
|
||||||
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const label = addressLabel(account.pubkey.toBase58(), cluster);
|
const label = addressLabel(account.pubkey.toBase58(), cluster, tokenRegistry);
|
||||||
|
|
||||||
let unit, balance;
|
let unit, balance;
|
||||||
if (info.isNative) {
|
if (info.isNative) {
|
||||||
@ -161,7 +161,7 @@ function TokenAccountCard({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
balance = <>{info.tokenAmount.uiAmount}</>;
|
balance = <>{info.tokenAmount.uiAmount}</>;
|
||||||
unit = TokenRegistry.get(info.mint.toBase58(), cluster)?.symbol || "tokens";
|
unit = tokenRegistry.get(info.mint.toBase58())?.tokenSymbol || "tokens";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -50,6 +50,8 @@ import { useCluster, Cluster } from "providers/cluster";
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Location } from "history";
|
import { Location } from "history";
|
||||||
import { useQuery } from "utils/url";
|
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 TRUNCATE_TOKEN_LENGTH = 10;
|
||||||
const ALL_TOKENS = "";
|
const ALL_TOKENS = "";
|
||||||
@ -299,6 +301,7 @@ function TokenHistoryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
|||||||
|
|
||||||
const FilterDropdown = ({ filter, toggle, show, tokens }: FilterProps) => {
|
const FilterDropdown = ({ filter, toggle, show, tokens }: FilterProps) => {
|
||||||
const { cluster } = useCluster();
|
const { cluster } = useCluster();
|
||||||
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
|
|
||||||
const buildLocation = (location: Location, filter: string) => {
|
const buildLocation = (location: Location, filter: string) => {
|
||||||
const params = new URLSearchParams(location.search);
|
const params = new URLSearchParams(location.search);
|
||||||
@ -319,7 +322,7 @@ const FilterDropdown = ({ filter, toggle, show, tokens }: FilterProps) => {
|
|||||||
tokens.forEach((token) => {
|
tokens.forEach((token) => {
|
||||||
const pubkey = token.info.mint.toBase58();
|
const pubkey = token.info.mint.toBase58();
|
||||||
filterOptions.push(pubkey);
|
filterOptions.push(pubkey);
|
||||||
nameLookup[pubkey] = formatTokenName(pubkey, cluster);
|
nameLookup[pubkey] = formatTokenName(pubkey, cluster, tokenRegistry);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -349,7 +352,7 @@ const FilterDropdown = ({ filter, toggle, show, tokens }: FilterProps) => {
|
|||||||
>
|
>
|
||||||
{filterOption === ALL_TOKENS
|
{filterOption === ALL_TOKENS
|
||||||
? "All Tokens"
|
? "All Tokens"
|
||||||
: formatTokenName(filterOption, cluster)}
|
: formatTokenName(filterOption, cluster, tokenRegistry)}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -602,8 +605,12 @@ function InstructionDetails({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTokenName(pubkey: string, cluster: Cluster): string {
|
function formatTokenName(
|
||||||
let display = displayAddress(pubkey, cluster);
|
pubkey: string,
|
||||||
|
cluster: Cluster,
|
||||||
|
tokenRegistry: KnownTokenMap
|
||||||
|
): string {
|
||||||
|
let display = displayAddress(pubkey, cluster, tokenRegistry);
|
||||||
|
|
||||||
if (display === pubkey) {
|
if (display === pubkey) {
|
||||||
display = display.slice(0, TRUNCATE_TOKEN_LENGTH) + "\u2026";
|
display = display.slice(0, TRUNCATE_TOKEN_LENGTH) + "\u2026";
|
||||||
|
@ -9,10 +9,9 @@ import {
|
|||||||
TokenAccountBalancePairWithOwner,
|
TokenAccountBalancePairWithOwner,
|
||||||
} from "providers/mints/largest";
|
} from "providers/mints/largest";
|
||||||
import { FetchStatus } from "providers/cache";
|
import { FetchStatus } from "providers/cache";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
|
||||||
import { useCluster } from "providers/cluster";
|
|
||||||
import { useMintAccountInfo } from "providers/accounts";
|
import { useMintAccountInfo } from "providers/accounts";
|
||||||
import { normalizeTokenAmount } from "utils";
|
import { normalizeTokenAmount } from "utils";
|
||||||
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
|
|
||||||
export function TokenLargestAccountsCard({ pubkey }: { pubkey: PublicKey }) {
|
export function TokenLargestAccountsCard({ pubkey }: { pubkey: PublicKey }) {
|
||||||
const mintAddress = pubkey.toBase58();
|
const mintAddress = pubkey.toBase58();
|
||||||
@ -23,8 +22,8 @@ export function TokenLargestAccountsCard({ pubkey }: { pubkey: PublicKey }) {
|
|||||||
pubkey,
|
pubkey,
|
||||||
fetchLargestAccounts,
|
fetchLargestAccounts,
|
||||||
]);
|
]);
|
||||||
const { cluster } = useCluster();
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const unit = TokenRegistry.get(mintAddress, cluster)?.symbol;
|
const unit = tokenRegistry.get(mintAddress)?.tokenSymbol;
|
||||||
const unitLabel = unit ? `(${unit})` : "";
|
const unitLabel = unit ? `(${unit})` : "";
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -5,13 +5,15 @@ import { TableCardBody } from "components/common/TableCardBody";
|
|||||||
import { Address } from "components/common/Address";
|
import { Address } from "components/common/Address";
|
||||||
import { addressLabel } from "utils/tx";
|
import { addressLabel } from "utils/tx";
|
||||||
import { useCluster } from "providers/cluster";
|
import { useCluster } from "providers/cluster";
|
||||||
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
|
|
||||||
export function UnknownAccountCard({ account }: { account: Account }) {
|
export function UnknownAccountCard({ account }: { account: Account }) {
|
||||||
const { details, lamports } = account;
|
const { details, lamports } = account;
|
||||||
const { cluster } = useCluster();
|
const { cluster } = useCluster();
|
||||||
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
if (lamports === undefined) return null;
|
if (lamports === undefined) return null;
|
||||||
|
|
||||||
const label = addressLabel(account.pubkey.toBase58(), cluster);
|
const label = addressLabel(account.pubkey.toBase58(), cluster, tokenRegistry);
|
||||||
return (
|
return (
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card-header align-items-center">
|
<div className="card-header align-items-center">
|
||||||
|
@ -5,6 +5,7 @@ import { clusterPath } from "utils/url";
|
|||||||
import { displayAddress } from "utils/tx";
|
import { displayAddress } from "utils/tx";
|
||||||
import { useCluster } from "providers/cluster";
|
import { useCluster } from "providers/cluster";
|
||||||
import { Copyable } from "./Copyable";
|
import { Copyable } from "./Copyable";
|
||||||
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
pubkey: PublicKey;
|
pubkey: PublicKey;
|
||||||
@ -24,9 +25,13 @@ export function Address({
|
|||||||
truncateUnknown,
|
truncateUnknown,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const address = pubkey.toBase58();
|
const address = pubkey.toBase58();
|
||||||
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const { cluster } = useCluster();
|
const { cluster } = useCluster();
|
||||||
|
|
||||||
if (truncateUnknown && address === displayAddress(address, cluster)) {
|
if (
|
||||||
|
truncateUnknown &&
|
||||||
|
address === displayAddress(address, cluster, tokenRegistry)
|
||||||
|
) {
|
||||||
truncate = true;
|
truncate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,11 +43,11 @@ export function Address({
|
|||||||
className={truncate ? "text-truncate address-truncate" : ""}
|
className={truncate ? "text-truncate address-truncate" : ""}
|
||||||
to={clusterPath(`/address/${address}`)}
|
to={clusterPath(`/address/${address}`)}
|
||||||
>
|
>
|
||||||
{raw ? address : displayAddress(address, cluster)}
|
{raw ? address : displayAddress(address, cluster, tokenRegistry)}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span className={truncate ? "text-truncate address-truncate" : ""}>
|
<span className={truncate ? "text-truncate address-truncate" : ""}>
|
||||||
{raw ? address : displayAddress(address, cluster)}
|
{raw ? address : displayAddress(address, cluster, tokenRegistry)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
@ -24,8 +24,7 @@ import {
|
|||||||
} from "providers/accounts";
|
} from "providers/accounts";
|
||||||
import { normalizeTokenAmount } from "utils";
|
import { normalizeTokenAmount } from "utils";
|
||||||
import { reportError } from "utils/sentry";
|
import { reportError } from "utils/sentry";
|
||||||
import { useCluster } from "providers/cluster";
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
|
||||||
|
|
||||||
type DetailsProps = {
|
type DetailsProps = {
|
||||||
tx: ParsedTransaction;
|
tx: ParsedTransaction;
|
||||||
@ -92,7 +91,7 @@ function TokenInstruction(props: InfoProps) {
|
|||||||
const tokenInfo = useTokenAccountInfo(tokenAddress);
|
const tokenInfo = useTokenAccountInfo(tokenAddress);
|
||||||
const mintAddress = infoMintAddress || tokenInfo?.mint.toBase58();
|
const mintAddress = infoMintAddress || tokenInfo?.mint.toBase58();
|
||||||
const mintInfo = useMintAccountInfo(mintAddress);
|
const mintInfo = useMintAccountInfo(mintAddress);
|
||||||
const { cluster } = useCluster();
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const fetchAccountInfo = useFetchAccountInfo();
|
const fetchAccountInfo = useFetchAccountInfo();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -116,10 +115,10 @@ function TokenInstruction(props: InfoProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mintAddress) {
|
if (mintAddress) {
|
||||||
const tokenDetails = TokenRegistry.get(mintAddress, cluster);
|
const tokenDetails = tokenRegistry.get(mintAddress);
|
||||||
|
|
||||||
if (tokenDetails && "symbol" in tokenDetails) {
|
if (tokenDetails) {
|
||||||
tokenSymbol = tokenDetails.symbol;
|
tokenSymbol = tokenDetails.tokenSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes.push(
|
attributes.push(
|
||||||
|
@ -9,9 +9,8 @@ import { BigNumber } from "bignumber.js";
|
|||||||
import { Address } from "components/common/Address";
|
import { Address } from "components/common/Address";
|
||||||
import { BalanceDelta } from "components/common/BalanceDelta";
|
import { BalanceDelta } from "components/common/BalanceDelta";
|
||||||
import { SignatureProps } from "pages/TransactionDetailsPage";
|
import { SignatureProps } from "pages/TransactionDetailsPage";
|
||||||
import { useCluster } from "providers/cluster";
|
|
||||||
import { useTransactionDetails } from "providers/transactions";
|
import { useTransactionDetails } from "providers/transactions";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
|
|
||||||
type TokenBalanceRow = {
|
type TokenBalanceRow = {
|
||||||
account: PublicKey;
|
account: PublicKey;
|
||||||
@ -23,7 +22,7 @@ type TokenBalanceRow = {
|
|||||||
|
|
||||||
export function TokenBalancesCard({ signature }: SignatureProps) {
|
export function TokenBalancesCard({ signature }: SignatureProps) {
|
||||||
const details = useTransactionDetails(signature);
|
const details = useTransactionDetails(signature);
|
||||||
const { cluster } = useCluster();
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
|
|
||||||
if (!details) {
|
if (!details) {
|
||||||
return null;
|
return null;
|
||||||
@ -51,7 +50,7 @@ export function TokenBalancesCard({ signature }: SignatureProps) {
|
|||||||
|
|
||||||
const accountRows = rows.map(({ account, delta, balance, mint }) => {
|
const accountRows = rows.map(({ account, delta, balance, mint }) => {
|
||||||
const key = account.toBase58() + mint;
|
const key = account.toBase58() + mint;
|
||||||
const units = TokenRegistry.get(mint, cluster)?.symbol || "tokens";
|
const units = tokenRegistry.get(mint)?.tokenSymbol || "tokens";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={key}>
|
<tr key={key}>
|
||||||
|
@ -19,7 +19,6 @@ import { OwnedTokensCard } from "components/account/OwnedTokensCard";
|
|||||||
import { TransactionHistoryCard } from "components/account/TransactionHistoryCard";
|
import { TransactionHistoryCard } from "components/account/TransactionHistoryCard";
|
||||||
import { TokenHistoryCard } from "components/account/TokenHistoryCard";
|
import { TokenHistoryCard } from "components/account/TokenHistoryCard";
|
||||||
import { TokenLargestAccountsCard } from "components/account/TokenLargestAccountsCard";
|
import { TokenLargestAccountsCard } from "components/account/TokenLargestAccountsCard";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
|
||||||
import { VoteAccountSection } from "components/account/VoteAccountSection";
|
import { VoteAccountSection } from "components/account/VoteAccountSection";
|
||||||
import { NonceAccountSection } from "components/account/NonceAccountSection";
|
import { NonceAccountSection } from "components/account/NonceAccountSection";
|
||||||
import { VotesCard } from "components/account/VotesCard";
|
import { VotesCard } from "components/account/VotesCard";
|
||||||
@ -30,6 +29,7 @@ import { BlockhashesCard } from "components/account/BlockhashesCard";
|
|||||||
import { ConfigAccountSection } from "components/account/ConfigAccountSection";
|
import { ConfigAccountSection } from "components/account/ConfigAccountSection";
|
||||||
import { useFlaggedAccounts } from "providers/accounts/flagged-accounts";
|
import { useFlaggedAccounts } from "providers/accounts/flagged-accounts";
|
||||||
import { UpgradeableProgramSection } from "components/account/UpgradeableProgramSection";
|
import { UpgradeableProgramSection } from "components/account/UpgradeableProgramSection";
|
||||||
|
import { useTokenRegistry } from "providers/mints/token-registry";
|
||||||
|
|
||||||
const TABS_LOOKUP: { [id: string]: Tab } = {
|
const TABS_LOOKUP: { [id: string]: Tab } = {
|
||||||
"spl-token:mint": {
|
"spl-token:mint": {
|
||||||
@ -92,16 +92,16 @@ export function AccountDetailsPage({ address, tab }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AccountHeader({ address }: { address: string }) {
|
export function AccountHeader({ address }: { address: string }) {
|
||||||
const { cluster } = useCluster();
|
const { tokenRegistry } = useTokenRegistry();
|
||||||
const tokenDetails = TokenRegistry.get(address, cluster);
|
const tokenDetails = tokenRegistry.get(address);
|
||||||
if (tokenDetails) {
|
if (tokenDetails) {
|
||||||
return (
|
return (
|
||||||
<div className="row align-items-end">
|
<div className="row align-items-end">
|
||||||
{tokenDetails.logo && (
|
{tokenDetails.icon && (
|
||||||
<div className="col-auto">
|
<div className="col-auto">
|
||||||
<div className="avatar avatar-lg header-avatar-top">
|
<div className="avatar avatar-lg header-avatar-top">
|
||||||
<img
|
<img
|
||||||
src={tokenDetails.logo}
|
src={tokenDetails.icon}
|
||||||
alt="token logo"
|
alt="token logo"
|
||||||
className="avatar-img rounded-circle border border-4 border-body"
|
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">
|
<div className="col mb-3 ml-n3 ml-md-n2">
|
||||||
<h6 className="header-pretitle">Token</h6>
|
<h6 className="header-pretitle">Token</h6>
|
||||||
<h2 className="header-title">{tokenDetails.name}</h2>
|
<h2 className="header-title">{tokenDetails.tokenName}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { LargestAccountsProvider } from "./largest";
|
import { LargestAccountsProvider } from "./largest";
|
||||||
|
import { TokenRegistryProvider } from "./token-registry";
|
||||||
|
|
||||||
type ProviderProps = { children: React.ReactNode };
|
type ProviderProps = { children: React.ReactNode };
|
||||||
export function MintsProvider({ children }: ProviderProps) {
|
export function MintsProvider({ children }: ProviderProps) {
|
||||||
return <LargestAccountsProvider>{children}</LargestAccountsProvider>;
|
return (
|
||||||
|
<TokenRegistryProvider>
|
||||||
|
<LargestAccountsProvider>{children}</LargestAccountsProvider>
|
||||||
|
</TokenRegistryProvider>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
49
explorer/src/providers/mints/token-registry.tsx
Normal file
49
explorer/src/providers/mints/token-registry.tsx
Normal 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 };
|
||||||
|
}
|
@ -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",
|
|
||||||
},
|
|
||||||
};
|
|
@ -15,9 +15,9 @@ import {
|
|||||||
PartiallyDecodedInstruction,
|
PartiallyDecodedInstruction,
|
||||||
ParsedInstruction,
|
ParsedInstruction,
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
|
||||||
import { Cluster } from "providers/cluster";
|
import { Cluster } from "providers/cluster";
|
||||||
import { SerumMarketRegistry } from "serumMarketRegistry";
|
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];
|
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(
|
export function addressLabel(
|
||||||
address: string,
|
address: string,
|
||||||
cluster: Cluster
|
cluster: Cluster,
|
||||||
|
tokenRegistry: KnownTokenMap
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
return (
|
return (
|
||||||
PROGRAM_NAME_BY_ID[address] ||
|
PROGRAM_NAME_BY_ID[address] ||
|
||||||
LOADER_IDS[address] ||
|
LOADER_IDS[address] ||
|
||||||
SYSVAR_IDS[address] ||
|
SYSVAR_IDS[address] ||
|
||||||
SYSVAR_ID[address] ||
|
SYSVAR_ID[address] ||
|
||||||
TokenRegistry.get(address, cluster)?.name ||
|
tokenRegistry.get(address)?.tokenName ||
|
||||||
SerumMarketRegistry.get(address, cluster)
|
SerumMarketRegistry.get(address, cluster)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function displayAddress(address: string, cluster: Cluster): string {
|
export function displayAddress(
|
||||||
return addressLabel(address, cluster) || address;
|
address: string,
|
||||||
|
cluster: Cluster,
|
||||||
|
tokenRegistry: KnownTokenMap
|
||||||
|
): string {
|
||||||
|
return addressLabel(address, cluster, tokenRegistry) || address;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function intoTransactionInstruction(
|
export function intoTransactionInstruction(
|
||||||
|
Reference in New Issue
Block a user