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