Skip to content

Commit 8a06510

Browse files
committed
dashboard: show details for enqueued VAAs
1 parent 6fbfcb8 commit 8a06510

File tree

6 files changed

+70
-21
lines changed

6 files changed

+70
-21
lines changed

dashboard/src/components/Alerts.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function getWarningCount(environment: Environment): number {
4040
return Math.max(getNumGuardians(environment) - CHAIN_LESS_THAN_MAX_WARNING_THRESHOLD + 1, 1);
4141
}
4242

43-
function getQuorumLossCount(environment: Environment): number {
43+
export function getQuorumLossCount(environment: Environment): number {
4444
return getNumGuardians(environment) - getQuorumCount(environment) + 1;
4545
}
4646

dashboard/src/components/EnqueuedVAAChecker.tsx

+1-6
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,9 @@ import { useEffect, useState } from 'react';
33
import { useNetworkContext } from '../contexts/NetworkContext';
44
import { ChainId } from '@wormhole-foundation/sdk-base';
55
import getSignedVAAWithRetry, { getSignedVAA } from '../utils/getSignedVaa';
6+
import { WORMHOLE_RPC_HOSTS } from '../utils/consts';
67

78
const VAA_CHECK_TIMEOUT = 60000;
8-
const WORMHOLE_RPC_HOSTS = [
9-
'https://wormhole-v2-mainnet-api.certus.one',
10-
'https://wormhole-v2-mainnet-api.mcf.rocks',
11-
'https://wormhole-v2-mainnet-api.chainlayer.network',
12-
'https://wormhole-v2-mainnet-api.staking.fund',
13-
];
149

1510
function EnqueuedVAAChecker({
1611
vaa: { emitterAddress, emitterChain, sequence },

dashboard/src/components/Governor.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
import numeral from 'numeral';
3030
import { useCallback, useMemo, useState } from 'react';
3131
import useGovernorInfo from '../hooks/useGovernorInfo';
32-
import { CHAIN_ICON_MAP } from '../utils/consts';
32+
import { CHAIN_ICON_MAP, WORMHOLE_RPC_HOSTS } from '../utils/consts';
3333
import CollapsibleSection from './CollapsibleSection';
3434
import EnqueuedVAAChecker from './EnqueuedVAAChecker';
3535
import { ExplorerAssetURL } from './ExplorerAssetURL';
@@ -106,7 +106,7 @@ const enqueuedColumns = [
106106
header: () => 'Sequence',
107107
cell: (info) => (
108108
<Link
109-
href={`https://wormhole-v2-mainnet-api.certus.one/v1/signed_vaa/${info.row.original.emitterChain}/${info.row.original.emitterAddress}/${info.row.original.sequence}`}
109+
href={`${WORMHOLE_RPC_HOSTS[0]}/v1/signed_vaa/${info.row.original.emitterChain}/${info.row.original.emitterAddress}/${info.row.original.sequence}`}
110110
target="_blank"
111111
rel="noopener noreferrer"
112112
>

dashboard/src/components/MainnetGovernor.tsx

+51-8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
getSortedRowModel,
3131
useReactTable,
3232
} from '@tanstack/react-table';
33+
import { GUARDIAN_SET_4, chainIdToName } from '@wormhole-foundation/wormhole-monitor-common';
3334
import numeral from 'numeral';
3435
import React, { useCallback, useMemo, useState } from 'react';
3536
import {
@@ -38,13 +39,13 @@ import {
3839
EnqueuedVAA,
3940
GovernorToken,
4041
} from '../hooks/useCloudGovernorInfo';
41-
import { CHAIN_ICON_MAP } from '../utils/consts';
42+
import { CHAIN_ICON_MAP, WORMHOLE_RPC_HOSTS } from '../utils/consts';
43+
import { getQuorumLossCount } from './Alerts';
4244
import CollapsibleSection from './CollapsibleSection';
4345
import EnqueuedVAAChecker from './EnqueuedVAAChecker';
4446
import { ExplorerAssetURL } from './ExplorerAssetURL';
4547
import { ExplorerTxHash } from './ExplorerTxHash';
4648
import Table from './Table';
47-
import { GUARDIAN_SET_4, chainIdToName } from '@wormhole-foundation/wormhole-monitor-common';
4849

4950
const calculatePercent = (notional: AvailableNotionalByChain): number => {
5051
try {
@@ -185,7 +186,26 @@ const enqueuedColumnHelper = createColumnHelper<EnqueuedVAA>();
185186
const enqueuedColumns = [
186187
enqueuedColumnHelper.accessor('emitterChain', {
187188
header: () => 'Chain',
188-
cell: (info) => `${chainIdToName(info.getValue())} (${info.getValue()})`,
189+
cell: (info) => (
190+
<Typography variant="body2" noWrap sx={{ pl: info.row.original.byGuardian ? 0 : 3 }}>
191+
{info.row.getCanExpand() ? (
192+
<IconButton
193+
size="small"
194+
sx={{ ml: -1 }}
195+
{...{
196+
onClick: info.row.getToggleExpandedHandler(),
197+
}}
198+
>
199+
{info.row.getIsExpanded() ? (
200+
<KeyboardArrowDown fontSize="inherit" />
201+
) : (
202+
<KeyboardArrowRight fontSize="inherit" />
203+
)}
204+
</IconButton>
205+
) : null}{' '}
206+
{chainIdToName(info.getValue())} ({info.getValue()})
207+
</Typography>
208+
),
189209
sortingFn: `text`,
190210
}),
191211
enqueuedColumnHelper.accessor('emitterAddress', {
@@ -195,7 +215,7 @@ const enqueuedColumns = [
195215
header: () => 'Sequence',
196216
cell: (info) => (
197217
<Link
198-
href={`https://wormhole-v2-mainnet-api.certus.one/v1/signed_vaa/${info.row.original.emitterChain}/${info.row.original.emitterAddress}/${info.row.original.sequence}`}
218+
href={`${WORMHOLE_RPC_HOSTS[0]}/v1/signed_vaa/${info.row.original.emitterChain}/${info.row.original.emitterAddress}/${info.row.original.sequence}`}
199219
target="_blank"
200220
rel="noopener noreferrer"
201221
>
@@ -206,12 +226,13 @@ const enqueuedColumns = [
206226
enqueuedColumnHelper.display({
207227
id: 'hasQuorum',
208228
header: () => 'Has Quorum?',
209-
cell: (info) => <EnqueuedVAAChecker vaa={info.row.original} />,
229+
cell: (info) =>
230+
info.row.original.byGuardian ? <EnqueuedVAAChecker vaa={info.row.original} /> : null,
210231
}),
211232
enqueuedColumnHelper.display({
212233
id: 'numGuardians',
213234
header: () => 'Num Holding',
214-
cell: (info) => Object.keys(info.row.original.byGuardian).length,
235+
cell: (info) => info.row.original.byGuardian?.length || info.row.original.guardianName || null,
215236
}),
216237
enqueuedColumnHelper.accessor('txHash', {
217238
header: () => 'Transaction Hash',
@@ -220,8 +241,19 @@ const enqueuedColumns = [
220241
),
221242
}),
222243
enqueuedColumnHelper.accessor('releaseTime', {
223-
header: () => 'Release Time',
224-
cell: (info) => new Date(info.getValue() * 1000).toLocaleString(),
244+
header: () => 'Estimated Release Time',
245+
cell: (info) => {
246+
const sortedTimes = info.row.original.byGuardian?.map((v) => v.releaseTime).sort();
247+
const quorumTime =
248+
sortedTimes && sortedTimes[Math.max(0, sortedTimes.length - getQuorumLossCount('Mainnet'))];
249+
const rawTime = quorumTime ? quorumTime : info.getValue();
250+
const date = new Date(rawTime * 1000);
251+
return (
252+
<>
253+
{date.toLocaleString()} ({date.toISOString()})
254+
</>
255+
);
256+
},
225257
}),
226258
enqueuedColumnHelper.accessor('notionalValue', {
227259
header: () => <Box order="1">Notional Value</Box>,
@@ -313,14 +345,25 @@ function MainnetGovernor({ governorInfo }: { governorInfo: CloudGovernorInfo })
313345
onSortingChange: setGuardianHoldingSorting,
314346
});
315347
const [enqueuedSorting, setEnqueuedSorting] = useState<SortingState>([]);
348+
const [enqueuedExpanded, setEnqueuedExpanded] = useState<ExpandedState>({});
316349
const enqueuedTable = useReactTable({
317350
columns: enqueuedColumns,
318351
data: governorInfo.enqueuedVAAs,
319352
state: {
353+
expanded: enqueuedExpanded,
320354
sorting: enqueuedSorting,
321355
},
356+
initialState: {
357+
pagination: {
358+
pageIndex: 0,
359+
pageSize: 50,
360+
},
361+
},
322362
getRowId: (vaa) => JSON.stringify(vaa),
363+
getSubRows: (row) => row.byGuardian,
323364
getCoreRowModel: getCoreRowModel(),
365+
getExpandedRowModel: getExpandedRowModel(),
366+
onExpandedChange: setEnqueuedExpanded,
324367
getPaginationRowModel: getPaginationRowModel(),
325368
getSortedRowModel: getSortedRowModel(),
326369
onSortingChange: setEnqueuedSorting,

dashboard/src/hooks/useCloudGovernorInfo.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,14 @@ export interface GovernorToken {
2424
}
2525

2626
export interface EnqueuedVAA {
27+
guardianName?: string;
2728
emitterChain: number;
2829
emitterAddress: string;
2930
sequence: string;
3031
releaseTime: number;
3132
notionalValue: string;
3233
txHash: string;
33-
byGuardian: {
34-
[guardianAddress: string]: EnqueuedVAAResponse;
35-
};
34+
byGuardian?: EnqueuedVAA[];
3635
}
3736

3837
export interface TotalEnqueuedVaasByGuardianByChain {
@@ -198,6 +197,9 @@ const getInfo = async (endpoint: string): Promise<CloudGovernorInfo> => {
198197
const vaaById: { [key: string]: EnqueuedVAA } = {};
199198
const totalEnqueuedVaas: TotalEnqueuedVaasByGuardianByChain = {};
200199
for (const s of status.data.governorStatus) {
200+
const guardianName =
201+
GUARDIAN_SET_4.find((g) => `0x${s.guardianAddress}`.toLowerCase() === g.pubkey.toLowerCase())
202+
?.name || s.guardianAddress;
201203
for (const chain of s.chains) {
202204
for (const emitter of chain.emitters) {
203205
if (!totalEnqueuedVaas[s.guardianAddress]) {
@@ -216,7 +218,10 @@ const getInfo = async (endpoint: string): Promise<CloudGovernorInfo> => {
216218
...vaa,
217219
emitterChain: chain.chainId,
218220
emitterAddress,
219-
byGuardian: { ...(vaaById[vaaId]?.byGuardian || {}), [s.guardianAddress]: vaa },
221+
byGuardian: [
222+
...(vaaById[vaaId]?.byGuardian || []),
223+
{ ...vaa, emitterChain: chain.chainId, emitterAddress, guardianName },
224+
],
220225
};
221226
}
222227
}

dashboard/src/utils/consts.ts

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ export const TESTNET_WORMCHAIN_URL = `https://corsproxy.io/?${encodeURIComponent
66
'https://gateway.testnet.xlabs.xyz'
77
)}`;
88

9+
export const WORMHOLE_RPC_HOSTS = [
10+
'https://wormhole-v2-mainnet-api.mcf.rocks',
11+
'https://wormhole-v2-mainnet-api.chainlayer.network',
12+
'https://wormhole-v2-mainnet-api.staking.fund',
13+
];
14+
915
export const CHAIN_ICON_MAP: { [key: string]: string } = chainIds.reduce<{ [key: string]: string }>(
1016
(icons, chainId) => {
1117
icons[chainId] = chainToIcon(chainIdToChain(chainId));

0 commit comments

Comments
 (0)