fix: query nominators from Asset Hub, treasury balances from both chains

NetworkStats now queries staking.nominators from Asset Hub instead of
Relay Chain (staking migrated to AH). Treasury hook fetches HEZ from RC
and PEZ from AH (asset 1) for accurate balance display.
This commit is contained in:
2026-02-22 06:36:15 +03:00
parent 3d43d2edf7
commit ef93735ef4
3 changed files with 45 additions and 15 deletions
+7 -5
View File
@@ -81,15 +81,17 @@ export const NetworkStats: React.FC = () => {
if (import.meta.env.DEV) console.warn('Failed to fetch People Chain collators', err);
}
// 3. Count Nominators
// 3. Count Nominators from Asset Hub (staking migrated to AH)
let nCount = 0;
try {
const nominators = await api.query.staking?.nominators.entries();
if (nominators) {
nCount = nominators.length;
if (isAssetHubReady && assetHubApi?.query.staking?.nominators) {
const nominators = await assetHubApi.query.staking.nominators.entries();
if (nominators) {
nCount = nominators.length;
}
}
} catch {
if (import.meta.env.DEV) console.warn('Staking pallet not available, nominators = 0');
if (import.meta.env.DEV) console.warn('Staking pallet not available on AH, nominators = 0');
}
setValidatorCount(vCount);
@@ -77,7 +77,7 @@ export const TreasuryOverview: React.FC = () => {
{t('treasury.liveData')}
</Badge>
<span className="text-sm text-muted-foreground">
{t('treasury.activeProposals', { count: proposals.length })} {t('treasury.hezInTreasury', { amount: metrics.totalBalance.toFixed(2) })}
{t('treasury.activeProposals', { count: proposals.length })} {metrics.pezBalance.toLocaleString(undefined, { maximumFractionDigits: 2 })} PEZ {metrics.hezBalance.toLocaleString(undefined, { maximumFractionDigits: 4 })} HEZ
</span>
</div>
@@ -117,7 +117,8 @@ export const TreasuryOverview: React.FC = () => {
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground">{t('treasury.totalBalance')}</p>
<p className="text-2xl font-bold">${(metrics.totalBalance / 1000000).toFixed(2)}M</p>
<p className="text-lg font-bold">{metrics.pezBalance.toLocaleString(undefined, { maximumFractionDigits: 2 })} PEZ</p>
<p className="text-sm font-semibold text-muted-foreground">{metrics.hezBalance.toLocaleString(undefined, { maximumFractionDigits: 4 })} HEZ</p>
<p className="text-xs text-green-500 flex items-center mt-1">
<ArrowUpRight className="h-3 w-3 mr-1" />
{t('treasury.thisMonth', { percent: '12.5' })}
+35 -8
View File
@@ -3,6 +3,8 @@ import { usePezkuwi } from '@/contexts/PezkuwiContext';
export interface TreasuryMetrics {
totalBalance: number;
pezBalance: number;
hezBalance: number;
monthlyIncome: number;
monthlyExpenses: number;
pendingProposals: number;
@@ -21,9 +23,11 @@ export interface TreasuryProposal {
}
export function useTreasury() {
const { api, isConnected } = usePezkuwi();
const { api, assetHubApi, isConnected, isAssetHubReady } = usePezkuwi();
const [metrics, setMetrics] = useState<TreasuryMetrics>({
totalBalance: 0,
pezBalance: 0,
hezBalance: 0,
monthlyIncome: 0,
monthlyExpenses: 0,
pendingProposals: 0,
@@ -45,14 +49,34 @@ export function useTreasury() {
setLoading(true);
setError(null);
// Get treasury account balance
const treasuryAccount = await api.query.treasury?.treasury?.();
let totalBalance = 0;
const TREASURY_ACCOUNT = '5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z'; // py/trsry
if (treasuryAccount) {
totalBalance = parseInt(treasuryAccount.toString()) / 1e12; // Convert from planck to tokens
// Get HEZ balance from Relay Chain treasury account
let hezBalance = 0;
try {
const rcAccount = await api.query.system.account(TREASURY_ACCOUNT);
hezBalance = parseInt(rcAccount.data.free.toString()) / 1e12;
} catch {
if (import.meta.env.DEV) console.warn('Failed to fetch RC treasury HEZ balance');
}
// Get PEZ balance from Asset Hub (asset ID 1)
let pezBalance = 0;
try {
if (isAssetHubReady && assetHubApi?.query.assets) {
const pezAccount = await assetHubApi.query.assets.account(1, TREASURY_ACCOUNT);
if (pezAccount && !pezAccount.isEmpty) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const unwrapped = (pezAccount as any).unwrap?.() ? (pezAccount as any).unwrap() : pezAccount;
pezBalance = parseInt(unwrapped.balance?.toString() || '0') / 1e12;
}
}
} catch {
if (import.meta.env.DEV) console.warn('Failed to fetch AH treasury PEZ balance');
}
const totalBalance = hezBalance + pezBalance;
// Fetch all treasury proposals
const proposalsData = await api.query.treasury?.proposals?.entries();
const proposalsList: TreasuryProposal[] = [];
@@ -60,7 +84,8 @@ export function useTreasury() {
let pendingCount = 0;
if (proposalsData) {
proposalsData.forEach(([key, value]: [unknown, unknown]) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
proposalsData.forEach(([key, value]: [any, any]) => {
const index = key.args[0].toNumber();
const proposal = value.unwrap();
const valueAmount = parseInt(proposal.value.toString()) / 1e12;
@@ -86,6 +111,8 @@ export function useTreasury() {
setMetrics({
totalBalance,
pezBalance,
hezBalance,
monthlyIncome: 0, // This would require historical data
monthlyExpenses: 0, // This would require historical data
pendingProposals: pendingCount,
@@ -108,7 +135,7 @@ export function useTreasury() {
// Subscribe to updates
const interval = setInterval(fetchTreasuryData, 30000); // Refresh every 30 seconds
return () => clearInterval(interval);
}, [api, isConnected]);
}, [api, assetHubApi, isConnected, isAssetHubReady]);
return {
metrics,