Explorer: update to new spl-token-registry standard (#15765)

* feat: update tokenlist

* feat: bump spl-token-registry version to 0.2.0
This commit is contained in:
Josh
2021-03-08 14:23:07 -08:00
committed by GitHub
parent 2204898ded
commit 5bde399499
12 changed files with 52 additions and 51 deletions

View File

@ -2599,9 +2599,9 @@
} }
}, },
"@solana/spl-token-registry": { "@solana/spl-token-registry": {
"version": "0.1.9", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/@solana/spl-token-registry/-/spl-token-registry-0.1.9.tgz", "resolved": "https://registry.npmjs.org/@solana/spl-token-registry/-/spl-token-registry-0.2.0.tgz",
"integrity": "sha512-cXjNg3MQVC+LWoFOMYSNRZrnJLCjOXEioIJPBX2V8Ft9v4f4THV/lim6JLddKGXZC2wr5NTOaI2zLYRbtpXW0w==", "integrity": "sha512-DC1gQDthODgCa0Nd5sPuoGpgEG3xdxQRoggfFFLQpwX689zILabvmVj6v6hF8bN8fGEpADZK1Fp8pwD427jkUQ==",
"requires": { "requires": {
"cross-fetch": "^3.0.6" "cross-fetch": "^3.0.6"
} }

View File

@ -6,7 +6,7 @@
"@project-serum/serum": "^0.13.25", "@project-serum/serum": "^0.13.25",
"@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.9", "@solana/spl-token-registry": "^0.2.0",
"@solana/web3.js": "^0.94.2", "@solana/web3.js": "^0.94.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",

View File

@ -12,7 +12,7 @@ import {
} from "utils/tx"; } from "utils/tx";
import { Cluster, useCluster } from "providers/cluster"; import { Cluster, useCluster } from "providers/cluster";
import { useTokenRegistry } from "providers/mints/token-registry"; import { useTokenRegistry } from "providers/mints/token-registry";
import { KnownTokenMap } from "@solana/spl-token-registry"; import { TokenInfoMap } from "@solana/spl-token-registry";
export function SearchBar() { export function SearchBar() {
const [search, setSearch] = React.useState(""); const [search, setSearch] = React.useState("");
@ -143,14 +143,14 @@ function buildSysvarOptions(search: string) {
function buildTokenOptions( function buildTokenOptions(
search: string, search: string,
cluster: Cluster, cluster: Cluster,
tokenRegistry: KnownTokenMap tokenRegistry: TokenInfoMap
) { ) {
const matchedTokens = Array.from(tokenRegistry.entries()).filter( const matchedTokens = Array.from(tokenRegistry.entries()).filter(
([address, details]) => { ([address, details]) => {
const searchLower = search.toLowerCase(); const searchLower = search.toLowerCase();
return ( return (
details.tokenName.toLowerCase().includes(searchLower) || details.name.toLowerCase().includes(searchLower) ||
details.tokenSymbol.toLowerCase().includes(searchLower) || details.symbol.toLowerCase().includes(searchLower) ||
address.includes(search) address.includes(search)
); );
} }
@ -160,8 +160,8 @@ function buildTokenOptions(
return { return {
label: "Tokens", label: "Tokens",
options: matchedTokens.map(([id, details]) => ({ options: matchedTokens.map(([id, details]) => ({
label: details.tokenName, label: details.name,
value: [details.tokenName, details.tokenSymbol, id], value: [details.name, details.symbol, id],
pathname: "/address/" + id, pathname: "/address/" + id,
})), })),
}; };
@ -171,7 +171,7 @@ function buildTokenOptions(
function buildOptions( function buildOptions(
rawSearch: string, rawSearch: string,
cluster: Cluster, cluster: Cluster,
tokenRegistry: KnownTokenMap tokenRegistry: TokenInfoMap
) { ) {
const search = rawSearch.trim(); const search = rawSearch.trim();
if (search.length === 0) return []; if (search.length === 0) return [];

View File

@ -92,7 +92,7 @@ function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
const detailsList: React.ReactNode[] = []; const detailsList: React.ReactNode[] = [];
const { tokenRegistry } = useTokenRegistry(); const { tokenRegistry } = useTokenRegistry();
const showLogos = tokens.some( const showLogos = tokens.some(
(t) => tokenRegistry.get(t.info.mint.toBase58())?.icon !== undefined (t) => tokenRegistry.get(t.info.mint.toBase58())?.logoURI !== undefined
); );
tokens.forEach((tokenAccount) => { tokens.forEach((tokenAccount) => {
const address = tokenAccount.pubkey.toBase58(); const address = tokenAccount.pubkey.toBase58();
@ -102,9 +102,9 @@ function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
<tr key={address}> <tr key={address}>
{showLogos && ( {showLogos && (
<td className="w-1 p-0 text-center"> <td className="w-1 p-0 text-center">
{tokenDetails?.icon && ( {tokenDetails?.logoURI && (
<img <img
src={tokenDetails.icon} src={tokenDetails.logoURI}
alt="token icon" alt="token icon"
className="token-icon rounded-circle border border-4 border-gray-dark" className="token-icon rounded-circle border border-4 border-gray-dark"
/> />
@ -119,7 +119,7 @@ function HoldingsDetailTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
</td> </td>
<td> <td>
{tokenAccount.info.tokenAmount.uiAmountString}{" "} {tokenAccount.info.tokenAmount.uiAmountString}{" "}
{tokenDetails && tokenDetails.tokenSymbol} {tokenDetails && tokenDetails.symbol}
</td> </td>
</tr> </tr>
); );
@ -161,7 +161,7 @@ function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
const detailsList: React.ReactNode[] = []; const detailsList: React.ReactNode[] = [];
const showLogos = tokens.some( const showLogos = tokens.some(
(t) => tokenRegistry.get(t.info.mint.toBase58())?.icon !== undefined (t) => tokenRegistry.get(t.info.mint.toBase58())?.logoURI !== undefined
); );
mappedTokens.forEach((totalByMint, mintAddress) => { mappedTokens.forEach((totalByMint, mintAddress) => {
const tokenDetails = tokenRegistry.get(mintAddress); const tokenDetails = tokenRegistry.get(mintAddress);
@ -169,9 +169,9 @@ function HoldingsSummaryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
<tr key={mintAddress}> <tr key={mintAddress}>
{showLogos && ( {showLogos && (
<td className="w-1 p-0 text-center"> <td className="w-1 p-0 text-center">
{tokenDetails?.icon && ( {tokenDetails?.logoURI && (
<img <img
src={tokenDetails.icon} src={tokenDetails.logoURI}
alt="token icon" alt="token icon"
className="token-icon rounded-circle border border-4 border-gray-dark" className="token-icon rounded-circle border border-4 border-gray-dark"
/> />
@ -182,7 +182,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.tokenSymbol} {totalByMint} {tokenDetails && tokenDetails.symbol}
</td> </td>
</tr> </tr>
); );

View File

@ -89,16 +89,16 @@ function MintAccountCard({
)} )}
</td> </td>
</tr> </tr>
{tokenInfo?.website && ( {tokenInfo?.extensions?.website && (
<tr> <tr>
<td>Website</td> <td>Website</td>
<td className="text-lg-right"> <td className="text-lg-right">
<a <a
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
href={tokenInfo.website} href={tokenInfo.extensions.website}
> >
{tokenInfo.website} {tokenInfo.extensions.website}
<span className="fe fe-external-link ml-2"></span> <span className="fe fe-external-link ml-2"></span>
</a> </a>
</td> </td>
@ -160,7 +160,7 @@ function TokenAccountCard({
); );
} else { } else {
balance = <>{info.tokenAmount.uiAmountString}</>; balance = <>{info.tokenAmount.uiAmountString}</>;
unit = tokenRegistry.get(info.mint.toBase58())?.tokenSymbol || "tokens"; unit = tokenRegistry.get(info.mint.toBase58())?.symbol || "tokens";
} }
return ( return (

View File

@ -50,7 +50,7 @@ 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 { TokenInfoMap } from "@solana/spl-token-registry";
import { useTokenRegistry } from "providers/mints/token-registry"; import { useTokenRegistry } from "providers/mints/token-registry";
const TRUNCATE_TOKEN_LENGTH = 10; const TRUNCATE_TOKEN_LENGTH = 10;
@ -608,7 +608,7 @@ function InstructionDetails({
function formatTokenName( function formatTokenName(
pubkey: string, pubkey: string,
cluster: Cluster, cluster: Cluster,
tokenRegistry: KnownTokenMap tokenRegistry: TokenInfoMap
): string { ): string {
let display = displayAddress(pubkey, cluster, tokenRegistry); let display = displayAddress(pubkey, cluster, tokenRegistry);

View File

@ -24,7 +24,7 @@ export function TokenLargestAccountsCard({ pubkey }: { pubkey: PublicKey }) {
fetchLargestAccounts, fetchLargestAccounts,
]); ]);
const { tokenRegistry } = useTokenRegistry(); const { tokenRegistry } = useTokenRegistry();
const unit = tokenRegistry.get(mintAddress)?.tokenSymbol; const unit = tokenRegistry.get(mintAddress)?.symbol;
const unitLabel = unit ? `(${unit})` : ""; const unitLabel = unit ? `(${unit})` : "";
React.useEffect(() => { React.useEffect(() => {

View File

@ -118,7 +118,7 @@ function TokenInstruction(props: InfoProps) {
const tokenDetails = tokenRegistry.get(mintAddress); const tokenDetails = tokenRegistry.get(mintAddress);
if (tokenDetails) { if (tokenDetails) {
tokenSymbol = tokenDetails.tokenSymbol; tokenSymbol = tokenDetails.symbol;
} }
attributes.push( attributes.push(

View File

@ -50,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)?.tokenSymbol || "tokens"; const units = tokenRegistry.get(mint)?.symbol || "tokens";
return ( return (
<tr key={key}> <tr key={key}>

View File

@ -97,11 +97,11 @@ export function AccountHeader({ address }: { address: string }) {
if (tokenDetails) { if (tokenDetails) {
return ( return (
<div className="row align-items-end"> <div className="row align-items-end">
{tokenDetails.icon && ( {tokenDetails.logoURI && (
<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.icon} src={tokenDetails.logoURI}
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.tokenName}</h2> <h2 className="header-title">{tokenDetails.name}</h2>
</div> </div>
</div> </div>
); );

View File

@ -1,34 +1,35 @@
import React from "react"; import React from "react";
import { import {
TokenListProvider, TokenListProvider,
KnownToken, TokenInfoMap,
KnownTokenMap, TokenInfo,
TokenListContainer,
} from "@solana/spl-token-registry"; } from "@solana/spl-token-registry";
import { clusterSlug, useCluster } from "providers/cluster"; import { clusterSlug, useCluster } from "providers/cluster";
const TokenRegistryContext = React.createContext<KnownTokenMap>(new Map()); const TokenRegistryContext = React.createContext<TokenInfoMap>(new Map());
type ProviderProps = { children: React.ReactNode }; type ProviderProps = { children: React.ReactNode };
export function TokenRegistryProvider({ children }: ProviderProps) { export function TokenRegistryProvider({ children }: ProviderProps) {
const [tokenRegistry, setTokenRegistry] = React.useState<KnownTokenMap>( const [tokenRegistry, setTokenRegistry] = React.useState<TokenInfoMap>(
new Map() new Map()
); );
const { cluster } = useCluster(); const { cluster } = useCluster();
React.useEffect(() => { React.useEffect(() => {
new TokenListProvider() new TokenListProvider().resolve().then((tokens: TokenListContainer) => {
.resolve(clusterSlug(cluster)) const tokenList = tokens
.then((tokens: KnownToken[]) => { .filterByClusterSlug(clusterSlug(cluster))
setTokenRegistry( .getList();
tokens.reduce((map: KnownTokenMap, item: KnownToken) => {
if (item.tokenName && item.tokenSymbol) { setTokenRegistry(
map.set(item.mintAddress, item); tokenList.reduce((map: TokenInfoMap, item: TokenInfo) => {
} map.set(item.address, item);
return map; return map;
}, new Map()) }, new Map())
); );
}); });
}, [cluster]); }, [cluster]);
return ( return (

View File

@ -17,7 +17,7 @@ import {
} from "@solana/web3.js"; } from "@solana/web3.js";
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"; import { TokenInfoMap } 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];
@ -109,14 +109,14 @@ export const SYSVAR_IDS = {
export function addressLabel( export function addressLabel(
address: string, address: string,
cluster: Cluster, cluster: Cluster,
tokenRegistry?: KnownTokenMap tokenRegistry?: TokenInfoMap
): 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)?.tokenName || tokenRegistry?.get(address)?.name ||
SerumMarketRegistry.get(address, cluster) SerumMarketRegistry.get(address, cluster)
); );
} }
@ -124,7 +124,7 @@ export function addressLabel(
export function displayAddress( export function displayAddress(
address: string, address: string,
cluster: Cluster, cluster: Cluster,
tokenRegistry: KnownTokenMap tokenRegistry: TokenInfoMap
): string { ): string {
return addressLabel(address, cluster, tokenRegistry) || address; return addressLabel(address, cluster, tokenRegistry) || address;
} }