mirror of
https://github.com/luxfi/explore.git
synced 2026-10-30 16:57:53 +00:00
luxd serves no P-Chain JSON-RPC, so every platform.* read the explorer sent
answered 404 and the validators, chains and heights widgets were empty on Lux
and Zoo. Each read is now GET /v1/chain/P/ops/{validators,blockchains,height},
coded against the node's OpenAPI 3.1 document, through GET
/v1/node/p-chain?op=<op>. The proxy's fixed table allows those three ops and one
NodeID parameter; a POST there answers 405.
ChainEntry.pChain is where the P-Chain that secures a chain is read: Lux reads
its own; Zoo, an L2 carried by Lux's validator set, reads Lux's and never its
own node's; Hanzo, on its own committee until hanzod joins as an L2, has none.
P-Chain UI names whose it is ("Lux primary network validators securing Zoo
Network") and prices stake in LUX. The cross-network validator sum is gone: it
counted Lux's validators again under Zoo.
The top bar shows a link only where its page has content: Chains, Bridge and
DEX on the Lux C-Chain host (their pages now 404 elsewhere), Validators where a
P-Chain secures the chain, Stats where there is a P-Chain panel or a stats
service. A P-Chain at genesis renders height #0 rather than nothing. The chain
page's uptime is no longer multiplied by 100.
Claude-Session: https://claude.ai/code/session_011Ge9UnfkEK37Lapx5nfPQK
128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
import React from 'react';
|
|
|
|
import config from 'configs/app';
|
|
import { getPChain } from 'configs/app/chainRegistry';
|
|
import { useCurrentValidators } from 'lib/api/pchain';
|
|
import { cn } from 'lib/utils/cn';
|
|
import PageTitle from 'ui/shared/Page/PageTitle';
|
|
|
|
import DelegatorsList from './DelegatorsList';
|
|
import ValidatorsDashboard from './ValidatorsDashboard';
|
|
import ValidatorsList from './ValidatorsList';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Tab definitions
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const TABS = {
|
|
dashboard: 'dashboard',
|
|
validators: 'validators',
|
|
delegators: 'delegators',
|
|
} as const;
|
|
|
|
type TabId = typeof TABS[keyof typeof TABS];
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Tab button
|
|
// ---------------------------------------------------------------------------
|
|
|
|
interface TabButtonProps {
|
|
readonly label: string;
|
|
readonly isActive: boolean;
|
|
readonly onClick: () => void;
|
|
}
|
|
|
|
const TabButton = ({ label, isActive, onClick }: TabButtonProps) => (
|
|
<button
|
|
className={ cn(
|
|
'px-4 py-2 text-sm border-b-2 bg-transparent cursor-pointer transition-all hover:text-[var(--color-text-primary)]',
|
|
isActive ?
|
|
'font-semibold text-[var(--color-text-primary)] border-[var(--color-text-primary)]' :
|
|
'font-normal text-[var(--color-text-secondary)] border-transparent',
|
|
) }
|
|
onClick={ onClick }
|
|
>
|
|
{ label }
|
|
</button>
|
|
);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Main page
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const ValidatorsPage = () => {
|
|
const [ activeTab, setActiveTab ] = React.useState<TabId>(TABS.dashboard);
|
|
const { validators, stats, isLoading, isKnown } = useCurrentValidators();
|
|
|
|
const handleDashboardClick = React.useCallback(() => {
|
|
setActiveTab(TABS.dashboard);
|
|
}, []);
|
|
|
|
const handleValidatorsClick = React.useCallback(() => {
|
|
setActiveTab(TABS.validators);
|
|
}, []);
|
|
|
|
const handleDelegatorsClick = React.useCallback(() => {
|
|
setActiveTab(TABS.delegators);
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<PageTitle
|
|
title="Validators"
|
|
secondRow={ (
|
|
<div>
|
|
{ getPChain()?.name } validators securing { config.chain.name || 'the network' }
|
|
</div>
|
|
) }
|
|
/>
|
|
|
|
{ /* Tabs */ }
|
|
<div className="flex"
|
|
>
|
|
<TabButton
|
|
label="Dashboard"
|
|
isActive={ activeTab === TABS.dashboard }
|
|
onClick={ handleDashboardClick }
|
|
/>
|
|
<TabButton
|
|
label={ isKnown ? `Validators (${ stats.validatorCount })` : 'Validators' }
|
|
isActive={ activeTab === TABS.validators }
|
|
onClick={ handleValidatorsClick }
|
|
/>
|
|
<TabButton
|
|
label={ isKnown ? `Delegators (${ stats.delegatorCount })` : 'Delegators' }
|
|
isActive={ activeTab === TABS.delegators }
|
|
onClick={ handleDelegatorsClick }
|
|
/>
|
|
</div>
|
|
|
|
{ /* Tab content */ }
|
|
{ activeTab === TABS.dashboard && (
|
|
<ValidatorsDashboard
|
|
validators={ validators }
|
|
stats={ stats }
|
|
isLoading={ isLoading }
|
|
isKnown={ isKnown }
|
|
/>
|
|
) }
|
|
|
|
{ activeTab === TABS.validators && (
|
|
<ValidatorsList
|
|
validators={ validators }
|
|
isLoading={ isLoading }
|
|
/>
|
|
) }
|
|
|
|
{ activeTab === TABS.delegators && (
|
|
<DelegatorsList
|
|
validators={ validators }
|
|
isLoading={ isLoading }
|
|
/>
|
|
) }
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default ValidatorsPage;
|