Fix owned token validation in explorer (#11581)
This commit is contained in:
parent
c300748884
commit
8ddb116659
|
@ -4,7 +4,6 @@ import { FetchStatus } from "providers/accounts";
|
|||
import {
|
||||
useFetchAccountOwnedTokens,
|
||||
useAccountOwnedTokens,
|
||||
TokenAccountData,
|
||||
} from "providers/accounts/tokens";
|
||||
import { ErrorCard } from "components/common/ErrorCard";
|
||||
import { LoadingCard } from "components/common/LoadingCard";
|
||||
|
@ -43,26 +42,27 @@ export function OwnedTokensCard({ pubkey }: { pubkey: PublicKey }) {
|
|||
);
|
||||
}
|
||||
|
||||
const mappedTokens = new Map<string, TokenAccountData>();
|
||||
for (const token of tokens) {
|
||||
const mappedTokens = new Map<string, number>();
|
||||
for (const { info: token } of tokens) {
|
||||
const mintAddress = token.mint.toBase58();
|
||||
const tokenInfo = mappedTokens.get(mintAddress);
|
||||
if (tokenInfo) {
|
||||
tokenInfo.amount += token.amount;
|
||||
} else {
|
||||
mappedTokens.set(mintAddress, { ...token });
|
||||
const totalByMint = mappedTokens.get(mintAddress);
|
||||
|
||||
let amount = token?.amount || (token?.tokenAmount?.uiAmount as number);
|
||||
if (totalByMint !== undefined) {
|
||||
amount += totalByMint;
|
||||
}
|
||||
|
||||
mappedTokens.set(mintAddress, amount);
|
||||
}
|
||||
|
||||
const detailsList: React.ReactNode[] = [];
|
||||
mappedTokens.forEach((tokenInfo, mintAddress) => {
|
||||
const balance = tokenInfo.amount;
|
||||
mappedTokens.forEach((totalByMint, mintAddress) => {
|
||||
detailsList.push(
|
||||
<tr key={mintAddress}>
|
||||
<td>
|
||||
<Address pubkey={new PublicKey(mintAddress)} link />
|
||||
</td>
|
||||
<td>{balance}</td>
|
||||
<td>{totalByMint}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from "providers/accounts/history";
|
||||
import {
|
||||
useAccountOwnedTokens,
|
||||
TokenAccountData,
|
||||
TokenInfoWithPubkey,
|
||||
} from "providers/accounts/tokens";
|
||||
import { ErrorCard } from "components/common/ErrorCard";
|
||||
import { LoadingCard } from "components/common/LoadingCard";
|
||||
|
@ -40,7 +40,7 @@ export function TokenHistoryCard({ pubkey }: { pubkey: PublicKey }) {
|
|||
return <TokenHistoryTable tokens={tokens} />;
|
||||
}
|
||||
|
||||
function TokenHistoryTable({ tokens }: { tokens: TokenAccountData[] }) {
|
||||
function TokenHistoryTable({ tokens }: { tokens: TokenInfoWithPubkey[] }) {
|
||||
const accountHistories = useAccountHistories();
|
||||
const fetchAccountHistory = useFetchAccountHistory();
|
||||
|
||||
|
@ -77,7 +77,7 @@ function TokenHistoryTable({ tokens }: { tokens: TokenAccountData[] }) {
|
|||
|
||||
const mintAndTxs = tokens
|
||||
.map((token) => ({
|
||||
mint: token.mint,
|
||||
mint: token.info.mint,
|
||||
history: accountHistories[token.pubkey.toBase58()],
|
||||
}))
|
||||
.filter(({ history }) => {
|
||||
|
|
|
@ -1,31 +1,18 @@
|
|||
import React from "react";
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
import { FetchStatus } from "./index";
|
||||
import { TokenAccountInfo } from "validators/accounts/token";
|
||||
import { useCluster } from "../cluster";
|
||||
import { number, string, boolean, coerce, object, nullable } from "superstruct";
|
||||
import { coerce } from "superstruct";
|
||||
|
||||
export type TokenAccountData = {
|
||||
export type TokenInfoWithPubkey = {
|
||||
info: TokenAccountInfo;
|
||||
pubkey: PublicKey;
|
||||
mint: PublicKey;
|
||||
owner: PublicKey;
|
||||
amount: number;
|
||||
isInitialized: boolean;
|
||||
isNative: boolean;
|
||||
};
|
||||
|
||||
const TokenAccountInfo = object({
|
||||
mint: string(),
|
||||
owner: string(),
|
||||
amount: number(),
|
||||
delegate: nullable(string()),
|
||||
delegatedAmount: number(),
|
||||
isInitialized: boolean(),
|
||||
isNative: boolean(),
|
||||
});
|
||||
|
||||
interface AccountTokens {
|
||||
status: FetchStatus;
|
||||
tokens?: TokenAccountData[];
|
||||
tokens?: TokenInfoWithPubkey[];
|
||||
}
|
||||
|
||||
interface Update {
|
||||
|
@ -33,7 +20,7 @@ interface Update {
|
|||
url: string;
|
||||
pubkey: PublicKey;
|
||||
status: FetchStatus;
|
||||
tokens?: TokenAccountData[];
|
||||
tokens?: TokenInfoWithPubkey[];
|
||||
}
|
||||
|
||||
interface Clear {
|
||||
|
@ -129,14 +116,7 @@ async function fetchAccountTokens(
|
|||
tokens = value.map((accountInfo) => {
|
||||
const parsedInfo = accountInfo.account.data.parsed.info;
|
||||
const info = coerce(parsedInfo, TokenAccountInfo);
|
||||
return {
|
||||
pubkey: accountInfo.pubkey,
|
||||
mint: new PublicKey(info.mint),
|
||||
owner: new PublicKey(info.owner),
|
||||
amount: info.amount,
|
||||
isInitialized: info.isInitialized,
|
||||
isNative: info.isNative,
|
||||
};
|
||||
return { info, pubkey: accountInfo.pubkey };
|
||||
});
|
||||
status = FetchStatus.Fetched;
|
||||
} catch (error) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
boolean,
|
||||
string,
|
||||
array,
|
||||
pick,
|
||||
nullable,
|
||||
} from "superstruct";
|
||||
import { Pubkey } from "validators/pubkey";
|
||||
|
@ -16,7 +17,9 @@ export type TokenAccountType = StructType<typeof TokenAccountType>;
|
|||
export const TokenAccountType = enums(["mint", "account", "multisig"]);
|
||||
|
||||
export type TokenAccountInfo = StructType<typeof TokenAccountInfo>;
|
||||
export const TokenAccountInfo = object({
|
||||
export const TokenAccountInfo = pick({
|
||||
isInitialized: boolean(),
|
||||
isNative: boolean(),
|
||||
mint: Pubkey,
|
||||
owner: Pubkey,
|
||||
amount: optional(number()), // TODO remove when ui amount is deployed
|
||||
|
@ -28,9 +31,7 @@ export const TokenAccountInfo = object({
|
|||
})
|
||||
),
|
||||
delegate: nullable(optional(Pubkey)),
|
||||
isInitialized: boolean(),
|
||||
isNative: boolean(),
|
||||
delegatedAmount: number(),
|
||||
delegatedAmount: optional(number()),
|
||||
});
|
||||
|
||||
export type MintAccountInfo = StructType<typeof MintAccountInfo>;
|
||||
|
|
Loading…
Reference in New Issue