explorer: 11938 display owner in token distribution table (#11953)

* include owner on largest token distribution tab

* run format:fix
This commit is contained in:
Josh 2020-09-01 09:21:47 -07:00 committed by GitHub
parent 839b926e0b
commit 53a900a28c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 5 deletions

View File

@ -1,11 +1,12 @@
import React from "react";
import { PublicKey, TokenAccountBalancePair } from "@solana/web3.js";
import { PublicKey } from "@solana/web3.js";
import { LoadingCard } from "components/common/LoadingCard";
import { ErrorCard } from "components/common/ErrorCard";
import { Address } from "components/common/Address";
import {
useTokenLargestTokens,
useFetchTokenLargestAccounts,
TokenAccountBalancePairWithOwner,
} from "providers/mints/largest";
import { FetchStatus } from "providers/cache";
import { TokenRegistry } from "tokenRegistry";
@ -64,11 +65,12 @@ export function TokenLargestAccountsCard({ pubkey }: { pubkey: PublicKey }) {
</div>
<div className="table-responsive mb-0">
<table className="table table-sm table-nowrap card-table">
<table className="table table-sm card-table">
<thead>
<tr>
<th className="text-muted">Rank</th>
<th className="text-muted">Address</th>
<th className="text-muted">Owner</th>
<th className="text-muted text-right">Balance {unitLabel}</th>
<th className="text-muted text-right">% of Total Supply</th>
</tr>
@ -86,7 +88,7 @@ export function TokenLargestAccountsCard({ pubkey }: { pubkey: PublicKey }) {
}
const renderAccountRow = (
account: TokenAccountBalancePair,
account: TokenAccountBalancePairWithOwner,
index: number,
supply: number
) => {
@ -99,8 +101,13 @@ const renderAccountRow = (
<td>
<span className="badge badge-soft-gray badge-pill">{index + 1}</span>
</td>
<td className="td">
<Address pubkey={account.address} link truncate />
</td>
<td>
<Address pubkey={account.address} link />
{account.owner && (
<Address pubkey={account.owner} alignRight link truncate />
)}
</td>
<td className="text-right">{account.uiAmount}</td>
<td className="text-right">{percent}</td>

View File

@ -127,6 +127,7 @@ async function fetchAccountInfo(
try {
const info = coerce(result.data.parsed, ParsedInfo);
const parsed = coerce(info, TokenAccount);
data = {
program: "spl-token",
parsed,

View File

@ -7,10 +7,14 @@ import {
PublicKey,
Connection,
TokenAccountBalancePair,
ParsedAccountData,
} from "@solana/web3.js";
import { TokenAccountInfo, TokenAccount } from "validators/accounts/token";
import { ParsedInfo } from "validators";
import { coerce } from "superstruct";
type LargestAccounts = {
largest: TokenAccountBalancePair[];
largest: TokenAccountBalancePairWithOwner[];
};
type State = Cache.State<LargestAccounts>;
@ -38,6 +42,13 @@ export function LargestAccountsProvider({ children }: ProviderProps) {
);
}
type OptionalOwner = {
owner?: PublicKey;
};
export type TokenAccountBalancePairWithOwner = TokenAccountBalancePair &
OptionalOwner;
async function fetchLargestAccounts(
dispatch: Dispatch,
pubkey: PublicKey,
@ -59,6 +70,33 @@ async function fetchLargestAccounts(
await new Connection(url, "single").getTokenLargestAccounts(pubkey)
).value,
};
data.largest = await Promise.all(
data.largest.map(
async (account): Promise<TokenAccountBalancePairWithOwner> => {
try {
const accountInfo = (
await new Connection(url, "single").getParsedAccountInfo(
account.address
)
).value;
if (accountInfo && "parsed" in accountInfo.data) {
const info = coerceParsedAccountInfo(accountInfo.data);
return {
...account,
owner: info.owner,
};
}
} catch (error) {
if (cluster !== Cluster.Custom) {
Sentry.captureException(error, { tags: { url } });
}
}
return account;
}
)
);
fetchStatus = FetchStatus.Fetched;
} catch (error) {
if (cluster !== Cluster.Custom) {
@ -105,3 +143,15 @@ export function useTokenLargestTokens(
return context.entries[address];
}
function coerceParsedAccountInfo(
parsedData: ParsedAccountData
): TokenAccountInfo {
try {
const data = coerce(parsedData.parsed, ParsedInfo);
const parsed = coerce(data, TokenAccount);
return coerce(parsed.info, TokenAccountInfo);
} catch (error) {
throw error;
}
}