-
{timeFormatted}
+
+
+
diff --git a/apps/explorer/src/app/components/txs/details/tx-batch.tsx b/apps/explorer/src/app/components/txs/details/tx-batch.tsx
index 01008989b..d9d34932e 100644
--- a/apps/explorer/src/app/components/txs/details/tx-batch.tsx
+++ b/apps/explorer/src/app/components/txs/details/tx-batch.tsx
@@ -1,9 +1,5 @@
-import React from 'react';
import { t } from '@vegaprotocol/react-helpers';
-import type {
- BlockExplorerTransactionResult,
- BatchMarketInstructions,
-} from '../../../routes/types/block-explorer-response';
+import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import { TxDetailsShared } from './shared/tx-details-shared';
import { TableWithTbody, TableRow, TableCell } from '../../table';
@@ -26,16 +22,17 @@ export const TxDetailsBatch = ({
pubKey,
blockData,
}: TxDetailsBatchProps) => {
- if (!txData) {
+ if (!txData || !txData.command.batchMarketInstructions) {
return <>{t('Awaiting Block Explorer transaction details')}>;
}
- const cmd = txData.command as BatchMarketInstructions;
-
- const batchSubmissions = cmd.batchMarketInstructions.submissions.length;
- const batchAmendments = cmd.batchMarketInstructions.amendments.length;
- const batchCancellations = cmd.batchMarketInstructions.cancellations.length;
- const batchTotal = batchSubmissions + batchAmendments + batchCancellations;
+ const countSubmissions =
+ txData.command.batchMarketInstructions.submissions?.length || 0;
+ const countAmendments =
+ txData.command.batchMarketInstructions.amendments?.length || 0;
+ const countCancellations =
+ txData.command.batchMarketInstructions.cancellations?.length || 0;
+ const countTotal = countSubmissions + countAmendments + countCancellations;
return (
@@ -43,7 +40,7 @@ export const TxDetailsBatch = ({
{t('Batch size')}
- {batchTotal}
+ {countTotal}
@@ -51,7 +48,7 @@ export const TxDetailsBatch = ({
{t('Submissions')}
- {batchSubmissions}
+ {countSubmissions}
@@ -59,7 +56,7 @@ export const TxDetailsBatch = ({
{t('Amendments')}
- {batchAmendments}
+ {countAmendments}
@@ -67,7 +64,7 @@ export const TxDetailsBatch = ({
{t('Cancellations')}
- {batchCancellations}
+ {countCancellations}
diff --git a/apps/explorer/src/app/components/txs/details/tx-chain-event.tsx b/apps/explorer/src/app/components/txs/details/tx-chain-event.tsx
index 66d1cb09e..7d6c93822 100644
--- a/apps/explorer/src/app/components/txs/details/tx-chain-event.tsx
+++ b/apps/explorer/src/app/components/txs/details/tx-chain-event.tsx
@@ -1,13 +1,10 @@
-import React from 'react';
import { t } from '@vegaprotocol/react-helpers';
-import type {
- BlockExplorerTransactionResult,
- ChainEvent,
-} from '../../../routes/types/block-explorer-response';
-import { AssetLink, PartyLink } from '../../links';
-import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import { TxDetailsShared } from './shared/tx-details-shared';
-import { TableCell, TableRow, TableWithTbody } from '../../table';
+import { TableWithTbody } from '../../table';
+
+import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
+import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
+import { ChainEvent } from './chain-events';
interface TxDetailsChainEventProps {
txData: BlockExplorerTransactionResult | undefined;
@@ -20,10 +17,10 @@ interface TxDetailsChainEventProps {
* Multiple events will relay the same data, from each validator, so that the
* deposit/withdrawal can be verified independently.
*
- * Design considerations so far:
- * - The ethereum address should be a link to an Ethereum explorer
- * - Sender and recipient are shown because they are easy
- * - Amount is not shown because there is no formatter by asset component
+ * There are so many chain events that the specific components have been broken
+ * out in to individual components. `getChainEventComponent` determines which
+ * is the most appropriate based on the transaction shape. See that function
+ * for more information.
*/
export const TxDetailsChainEvent = ({
txData,
@@ -33,32 +30,11 @@ export const TxDetailsChainEvent = ({
if (!txData) {
return <>{t('Awaiting Block Explorer transaction details')}>;
}
- const cmd = txData.command as ChainEvent;
- const assetId = cmd.chainEvent.erc20.deposit.vegaAssetId;
- const sender = cmd.chainEvent.erc20.deposit.sourceEthereumAddress;
- const recipient = cmd.chainEvent.erc20.deposit.targetPartyId;
return (
-
- {t('Asset')}
-
-
-
-
-
- {t('Sender')}
-
- {sender}
-
-
-
- {t('Recipient')}
-
-
-
-
+
);
};
diff --git a/apps/explorer/src/app/components/txs/details/tx-details-wrapper.tsx b/apps/explorer/src/app/components/txs/details/tx-details-wrapper.tsx
index b6daec5fc..413a46c9a 100644
--- a/apps/explorer/src/app/components/txs/details/tx-details-wrapper.tsx
+++ b/apps/explorer/src/app/components/txs/details/tx-details-wrapper.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { DATA_SOURCES } from '../../../config';
import { t, useFetch } from '@vegaprotocol/react-helpers';
import { TxDetailsOrder } from './tx-order';
@@ -10,11 +10,10 @@ import { TxDetailsGeneric } from './tx-generic';
import { TxDetailsBatch } from './tx-batch';
import { TxDetailsChainEvent } from './tx-chain-event';
import { TxContent } from '../../../routes/txs/id/tx-content';
-
-type resultOrNull = BlockExplorerTransactionResult | undefined;
+import { TxDetailsNodeVote } from './tx-node-vote';
interface TxDetailsWrapperProps {
- txData: resultOrNull;
+ txData: BlockExplorerTransactionResult | undefined;
pubKey: string | undefined;
height: string;
}
@@ -61,7 +60,7 @@ export const TxDetailsWrapper = ({
* @param txData
* @returns JSX.Element
*/
-function getTransactionComponent(txData: resultOrNull) {
+function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
if (!txData) {
return TxDetailsGeneric;
}
@@ -77,6 +76,8 @@ function getTransactionComponent(txData: resultOrNull) {
return TxDetailsBatch;
case 'Chain Event':
return TxDetailsChainEvent;
+ case 'Node Vote':
+ return TxDetailsNodeVote;
default:
return TxDetailsGeneric;
}
diff --git a/apps/explorer/src/app/components/txs/details/tx-generic.tsx b/apps/explorer/src/app/components/txs/details/tx-generic.tsx
index eabd333cb..2d0ced7d5 100644
--- a/apps/explorer/src/app/components/txs/details/tx-generic.tsx
+++ b/apps/explorer/src/app/components/txs/details/tx-generic.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { t } from '@vegaprotocol/react-helpers';
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
diff --git a/apps/explorer/src/app/components/txs/details/tx-hearbeat.tsx b/apps/explorer/src/app/components/txs/details/tx-hearbeat.tsx
index 7db5f9147..2318bded0 100644
--- a/apps/explorer/src/app/components/txs/details/tx-hearbeat.tsx
+++ b/apps/explorer/src/app/components/txs/details/tx-hearbeat.tsx
@@ -1,9 +1,5 @@
-import React from 'react';
import { t } from '@vegaprotocol/react-helpers';
-import type {
- BlockExplorerTransactionResult,
- ValidatorHeartbeat,
-} from '../../../routes/types/block-explorer-response';
+import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import { BlockLink, NodeLink } from '../../links/';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import { TxDetailsShared } from './shared/tx-details-shared';
@@ -56,11 +52,12 @@ export const TxDetailsHeartbeat = ({
pubKey,
blockData,
}: TxDetailsHeartbeatProps) => {
- if (!txData) {
+ if (!txData || !txData.command.validatorHeartbeat) {
return <>{t('Awaiting Block Explorer transaction details')}>;
}
- const cmd = txData.command as ValidatorHeartbeat;
+ const nodeId = txData.command.validatorHeartbeat.nodeId || '';
+ const blockHeight = txData.command.blockHeight || '';
return (
@@ -68,18 +65,18 @@ export const TxDetailsHeartbeat = ({
{t('Node')}
-
+
{t('Signed block height')}
-
+
{t('Freshness (lower is better)')}
- {scoreFreshness(txData.block, cmd.blockHeight)}
+ {scoreFreshness(txData.block, blockHeight)}
);
diff --git a/apps/explorer/src/app/components/txs/details/tx-lp-amend.tsx b/apps/explorer/src/app/components/txs/details/tx-lp-amend.tsx
index b72403bf9..c44a40a0b 100644
--- a/apps/explorer/src/app/components/txs/details/tx-lp-amend.tsx
+++ b/apps/explorer/src/app/components/txs/details/tx-lp-amend.tsx
@@ -1,9 +1,5 @@
-import React from 'react';
import { t } from '@vegaprotocol/react-helpers';
-import type {
- AmendLiquidityProvisionOrder,
- BlockExplorerTransactionResult,
-} from '../../../routes/types/block-explorer-response';
+import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import { MarketLink } from '../../links/';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import { TxDetailsShared } from './shared/tx-details-shared';
@@ -29,7 +25,7 @@ export const TxDetailsLPAmend = ({
return <>{t('Awaiting Block Explorer transaction details')}>;
}
- const cmd = txData.command as AmendLiquidityProvisionOrder;
+ const marketId = txData.command.liquidityProvisionAmendment?.marketId || '';
return (
@@ -37,7 +33,7 @@ export const TxDetailsLPAmend = ({
{t('Market')}
-
+
diff --git a/apps/explorer/src/app/components/txs/details/tx-node-vote.tsx b/apps/explorer/src/app/components/txs/details/tx-node-vote.tsx
new file mode 100644
index 000000000..0ab5a54d1
--- /dev/null
+++ b/apps/explorer/src/app/components/txs/details/tx-node-vote.tsx
@@ -0,0 +1,144 @@
+import { t } from '@vegaprotocol/react-helpers';
+import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
+import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
+import { TxDetailsShared } from './shared/tx-details-shared';
+import { TableCell, TableRow, TableWithTbody } from '../../table';
+import type { ExplorerNodeVoteQueryResult } from './__generated___/node-vote';
+import { useExplorerNodeVoteQuery } from './__generated___/node-vote';
+import { PartyLink } from '../../links';
+import { Time } from '../../time';
+
+interface TxDetailsNodeVoteProps {
+ txData: BlockExplorerTransactionResult | undefined;
+ pubKey: string | undefined;
+ blockData: TendermintBlocksResponse | undefined;
+}
+
+/**
+ * If there is not yet a custom component for a transaction, just display
+ * the basic details. This allows someone to view the decoded transaction.
+ */
+export const TxDetailsNodeVote = ({
+ txData,
+ pubKey,
+ blockData,
+}: TxDetailsNodeVoteProps) => {
+ const id = txData?.command.nodeVote?.reference || '';
+
+ const { data } = useExplorerNodeVoteQuery({
+ variables: {
+ id,
+ },
+ // Required as one of these queries will needlessly error
+ errorPolicy: 'ignore',
+ });
+
+ if (!txData) {
+ return <>{t('Awaiting Block Explorer transaction details')}>;
+ }
+
+ return (
+
+
+ {data && !!data.deposit
+ ? TxDetailsNodeVoteDeposit({ deposit: data })
+ : data && !!data.withdrawal
+ ? TxDetailsNodeVoteWithdrawal({ withdrawal: data })
+ : null}
+
+ );
+};
+
+interface TxDetailsNodeVoteDepositProps {
+ deposit: ExplorerNodeVoteQueryResult['data'];
+}
+
+export function TxDetailsNodeVoteDeposit({
+ deposit,
+}: TxDetailsNodeVoteDepositProps) {
+ if (!deposit) {
+ return null;
+ }
+ return (
+ <>
+
+ {t('Witnessed Event type')}
+ {deposit?.deposit?.txHash ? (
+ {t('ERC20 deposit')}
+ ) : (
+ {t('Built-in asset deposit')}
+ )}
+
+
+ {t('To party')}:
+
+
+
+
+
+ {t('Credited on')}:
+
+
+
+ {deposit?.deposit?.txHash ? (
+
+ ) : null}
+
+ >
+ );
+}
+
+interface TxDetailsNodeVoteWithdrawalProps {
+ withdrawal: ExplorerNodeVoteQueryResult['data'];
+}
+
+export function TxDetailsNodeVoteWithdrawal({
+ withdrawal,
+}: TxDetailsNodeVoteWithdrawalProps) {
+ if (!withdrawal) {
+ return null;
+ }
+ return (
+ <>
+
+ {t('Witnessed Event type')}
+ {withdrawal?.withdrawal?.txHash ? (
+ {t('ERC20 withdrawal')}
+ ) : (
+ {t('Built-in asset withdrawal')}
+ )}
+
+
+ {t('From party')}:
+
+
+
+
+
+ {t('Withdrawn on')}:
+
+
+
+ {withdrawal?.withdrawal?.txHash ? (
+
+ ) : null}
+
+ >
+ );
+}
+
+interface TxDetailsEthTxHashProps {
+ hash: string;
+}
+
+export function TxHash({ hash }: TxDetailsEthTxHashProps) {
+ if (!hash) {
+ return null;
+ }
+ return (
+
+ Ethereum TX:
+ {hash}
+
+ );
+}
diff --git a/apps/explorer/src/app/components/txs/details/tx-order.tsx b/apps/explorer/src/app/components/txs/details/tx-order.tsx
index 3e0182b45..0f425fc5f 100644
--- a/apps/explorer/src/app/components/txs/details/tx-order.tsx
+++ b/apps/explorer/src/app/components/txs/details/tx-order.tsx
@@ -1,9 +1,5 @@
-import React from 'react';
import { t } from '@vegaprotocol/react-helpers';
-import type {
- BlockExplorerTransactionResult,
- SubmitOrder,
-} from '../../../routes/types/block-explorer-response';
+import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import { MarketLink } from '../../links/';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import { TxDetailsShared } from './shared/tx-details-shared';
@@ -26,11 +22,10 @@ export const TxDetailsOrder = ({
pubKey,
blockData,
}: TxDetailsOrderProps) => {
- if (!txData) {
+ if (!txData || !txData.command.orderSubmission) {
return <>{t('Awaiting Block Explorer transaction details')}>;
}
-
- const cmd = txData.command as SubmitOrder;
+ const marketId = txData.command.orderSubmission.marketId || '-';
return (
@@ -38,7 +33,7 @@ export const TxDetailsOrder = ({
{t('Market')}
-
+
diff --git a/apps/explorer/src/app/components/txs/tx-order-type.tsx b/apps/explorer/src/app/components/txs/tx-order-type.tsx
index 5c851255d..72ea9774a 100644
--- a/apps/explorer/src/app/components/txs/tx-order-type.tsx
+++ b/apps/explorer/src/app/components/txs/tx-order-type.tsx
@@ -1,5 +1,9 @@
+import { t } from '@vegaprotocol/react-helpers';
+import type { components } from '../../../types/explorer';
+
interface TxOrderTypeProps {
orderType: string;
+ chainEvent?: components['schemas']['v1ChainEvent'];
className?: string;
}
@@ -32,13 +36,73 @@ const displayString: StringMap = {
ValidatorHeartbeat: 'Validator Heartbeat',
};
-export const TxOrderType = ({ orderType }: TxOrderTypeProps) => {
+/**
+ * Given a chain event, will try to provide a more useful label
+ * @param chainEvent
+ * @returns
+ */
+export function getLabelForChainEvent(
+ chainEvent: components['schemas']['v1ChainEvent']
+): string {
+ if (chainEvent.builtin) {
+ if (chainEvent.builtin.deposit) {
+ return t('Built-in deposit');
+ } else if (chainEvent.builtin.withdrawal) {
+ return t('Built-in withdraw');
+ }
+ return t('Built-in event');
+ } else if (chainEvent.erc20) {
+ if (chainEvent.erc20.assetDelist) {
+ return t('ERC20 delist');
+ } else if (chainEvent.erc20.assetList) {
+ return t('ERC20 list');
+ } else if (chainEvent.erc20.bridgeResumed) {
+ return t('Bridge resume');
+ } else if (chainEvent.erc20.bridgeStopped) {
+ return t('Bridge pause');
+ } else if (chainEvent.erc20.deposit) {
+ return t('ERC20 deposit');
+ } else if (chainEvent.erc20.withdrawal) {
+ return t('ERC20 withdraw');
+ }
+ return t('ERC20 event');
+ } else if (chainEvent.stakingEvent) {
+ if (chainEvent.stakingEvent.stakeDeposited) {
+ return t('Stake add');
+ } else if (chainEvent.stakingEvent.stakeRemoved) {
+ return t('Stake remove');
+ }
+ return t('Staking event');
+ } else if (chainEvent.erc20Multisig) {
+ if (chainEvent.erc20Multisig.signerAdded) {
+ return t('Signer adde');
+ } else if (chainEvent.erc20Multisig.signerRemoved) {
+ return t('Signer remove');
+ } else if (chainEvent.erc20Multisig.thresholdSet) {
+ return t('Signer threshold');
+ }
+ return t('Multisig update');
+ }
+ return t('Chain Event');
+}
+
+export const TxOrderType = ({ orderType, chainEvent }: TxOrderTypeProps) => {
+ let type = displayString[orderType] || orderType;
+
+ let colours = 'text-white dark:text-white bg-zinc-800 dark:bg-zinc-800';
+
+ // This will get unwieldy and should probably produce a different colour of tag
+ if (type === 'Chain Event' && !!chainEvent) {
+ type = getLabelForChainEvent(chainEvent);
+ colours =
+ 'text-white dark-text-white bg-vega-pink-dark dark:bg-vega-pink-dark';
+ }
return (
- {displayString[orderType] || orderType}
+ {type}
);
};
diff --git a/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx b/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx
index 6214b7a8e..f9420b6b3 100644
--- a/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx
+++ b/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx
@@ -13,6 +13,7 @@ export const TxsInfiniteListItem = ({
type,
block,
index,
+ command,
}: Partial
) => {
if (
!hash ||
@@ -54,7 +55,7 @@ export const TxsInfiniteListItem = ({
/>