diff --git a/explorer/src/components/account/StakeAccountSection.tsx b/explorer/src/components/account/StakeAccountSection.tsx index bebb36dfeb..1c911c40f5 100644 --- a/explorer/src/components/account/StakeAccountSection.tsx +++ b/explorer/src/components/account/StakeAccountSection.tsx @@ -11,17 +11,20 @@ import { StakeAccountType, } from "validators/accounts/stake"; import BN from "bn.js"; +import { StakeActivationData } from "@solana/web3.js"; const MAX_EPOCH = new BN(2).pow(new BN(64)).sub(new BN(1)); export function StakeAccountSection({ account, stakeAccount, + activation, stakeAccountType, }: { account: Account; stakeAccount: StakeAccountInfo | StakeAccountWasm; stakeAccountType: StakeAccountType; + activation?: StakeActivationData; }) { return ( <> @@ -35,6 +38,7 @@ export function StakeAccountSection({ <> @@ -129,17 +133,22 @@ function OverviewCard({ function DelegationCard({ stakeAccount, stakeAccountType, + activation, }: { stakeAccount: StakeAccountInfo | StakeAccountWasm; stakeAccountType: StakeAccountType; + activation?: StakeActivationData; }) { const displayStatus = () => { - // TODO check epoch let status = TYPE_NAMES[stakeAccountType]; + let activationState = ""; if (stakeAccountType !== "delegated") { status = "Not delegated"; + } else { + activationState = activation ? `(${activation.state})` : ""; } - return status; + + return [status, activationState].join(" "); }; let voterPubkey, activationEpoch, deactivationEpoch; @@ -190,6 +199,24 @@ function DelegationCard({ + {activation && ( + <> + + Active Stake (SOL) + + {lamportsToSolString(activation.active)} + + + + + Inactive Stake (SOL) + + {lamportsToSolString(activation.inactive)} + + + + )} + {voterPubkey && ( Delegated Vote Address diff --git a/explorer/src/pages/AccountDetailsPage.tsx b/explorer/src/pages/AccountDetailsPage.tsx index 2d54fb26c5..a759731a9a 100644 --- a/explorer/src/pages/AccountDetailsPage.tsx +++ b/explorer/src/pages/AccountDetailsPage.tsx @@ -143,6 +143,7 @@ function DetailsSections({ pubkey, tab }: { pubkey: PublicKey; tab?: string }) { function InfoSection({ account }: { account: Account }) { const data = account?.details?.data; + if (data && data.program === "stake") { let stakeAccountType, stakeAccount; if ("accountType" in data.parsed) { @@ -157,6 +158,7 @@ function InfoSection({ account }: { account: Account }) { ); diff --git a/explorer/src/providers/accounts/index.tsx b/explorer/src/providers/accounts/index.tsx index 8f72caef03..fb924053aa 100644 --- a/explorer/src/providers/accounts/index.tsx +++ b/explorer/src/providers/accounts/index.tsx @@ -1,6 +1,11 @@ import React from "react"; import { StakeAccount as StakeAccountWasm } from "solana-sdk-wasm"; -import { PublicKey, Connection, StakeProgram } from "@solana/web3.js"; +import { + PublicKey, + Connection, + StakeProgram, + StakeActivationData, +} from "@solana/web3.js"; import { useCluster, Cluster } from "../cluster"; import { HistoryProvider } from "./history"; import { TokensProvider, TOKEN_PROGRAM_ID } from "./tokens"; @@ -20,6 +25,7 @@ export { useAccountHistory } from "./history"; export type StakeProgramData = { program: "stake"; parsed: StakeAccount | StakeAccountWasm; + activation?: StakeActivationData; }; export type TokenProgramData = { @@ -85,9 +91,8 @@ async function fetchAccountInfo( let data; let fetchStatus; try { - const result = ( - await new Connection(url, "single").getParsedAccountInfo(pubkey) - ).value; + const connection = new Connection(url, "single"); + const result = (await connection.getParsedAccountInfo(pubkey)).value; let lamports, details; if (result === null) { @@ -104,17 +109,26 @@ async function fetchAccountInfo( let data: ProgramData | undefined; if (result.owner.equals(StakeProgram.programId)) { try { - let parsed; + let parsed: StakeAccount | StakeAccountWasm; + let isDelegated: boolean = false; if ("parsed" in result.data) { const info = coerce(result.data.parsed, ParsedInfo); parsed = coerce(info, StakeAccount); + isDelegated = parsed.type === "delegated"; } else { const wasm = await import("solana-sdk-wasm"); parsed = wasm.StakeAccount.fromAccountData(result.data); + isDelegated = (parsed.accountType as any) === "delegated"; } + + const activation = isDelegated + ? await connection.getStakeActivation(pubkey) + : undefined; + data = { program: "stake", parsed, + activation, }; } catch (err) { reportError(err, { url, address: pubkey.toBase58() });