diff --git a/shared/lib/transactions.utils.test.ts b/shared/lib/transactions.utils.test.ts index c4f4e048a40f..bbe36d7f9b3d 100644 --- a/shared/lib/transactions.utils.test.ts +++ b/shared/lib/transactions.utils.test.ts @@ -9,9 +9,30 @@ import { getPostQuoteWithdrawTransactionType, isPostQuoteWithdrawTransaction, isPerpsWithdrawTransaction, + isValidTransactionHash, } from './transactions.utils'; describe('Transactions utils', () => { + describe('isValidTransactionHash', () => { + it('returns true for a valid EVM transaction hash', () => { + expect( + isValidTransactionHash( + '0x8586e162e456a23c1969573a4b79e77912705b474bc5aa0c2a63d56556623ab2', + ), + ).toBe(true); + }); + + it('returns false for invalid EVM transaction hashes', () => { + expect( + isValidTransactionHash('48a75190-45ca-11ef-9001-f3886ec2397c'), + ).toBe(false); + }); + + it('returns false for truncated EVM hashes', () => { + expect(isValidTransactionHash('0x1234')).toBe(false); + }); + }); + describe('isBatchTransaction', () => { it('returns true when nestedTransactions has items', () => { const nested: NestedTransactionMetadata[] = [{ to: '0x1', data: '0x' }]; diff --git a/shared/lib/transactions.utils.ts b/shared/lib/transactions.utils.ts index 093664808d58..0b5a381d416f 100644 --- a/shared/lib/transactions.utils.ts +++ b/shared/lib/transactions.utils.ts @@ -3,6 +3,11 @@ import { TransactionMeta, TransactionType, } from '@metamask/transaction-controller'; +import { isStrictHexString } from '@metamask/utils'; + +export function isValidTransactionHash(hash: string) { + return hash.length === 66 && isStrictHexString(hash); +} /** * Determines if a transaction is a batch transaction. diff --git a/ui/pages/details/components/sections.tsx b/ui/pages/details/components/sections.tsx index ffa48d4e4e0b..f54daa4caac9 100644 --- a/ui/pages/details/components/sections.tsx +++ b/ui/pages/details/components/sections.tsx @@ -9,6 +9,7 @@ import { NetworkName } from '../../../components/app/transaction/network-name'; import { TransactionStatus } from '../../../components/app/transaction/transaction-status'; import { AccountName } from '../../../components/app/transaction/account-name'; import { TransactionId } from '../../../components/app/transaction/transaction-id'; +import { isValidTransactionHash } from '../../../../shared/lib/transactions.utils'; import { Row, Section } from './shared'; import { TokenRow } from './token-row'; @@ -50,6 +51,11 @@ export function MetadataSection({ const { formatDateTime } = useFormatters(); const accountAddress = item.data.from; const showAddressRows = Boolean(addressRows?.from && addressRows?.to); + const txId = + item.hash && + (!item.chainId.startsWith('eip155:') || isValidTransactionHash(item.hash)) + ? item.hash + : undefined; return (
@@ -85,7 +91,7 @@ export function MetadataSection({ } + value={txId ? : null} />
); diff --git a/ui/pages/details/components/shared.tsx b/ui/pages/details/components/shared.tsx index 662f2c7d734a..fd53fd784f20 100644 --- a/ui/pages/details/components/shared.tsx +++ b/ui/pages/details/components/shared.tsx @@ -9,6 +9,7 @@ import { } from '../../../../shared/constants/multichain/networks'; import { CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP } from '../../../../shared/constants/common'; import { formatBlockExplorerTransactionUrl } from '../../../../shared/lib/multichain/networks'; +import { isValidTransactionHash } from '../../../../shared/lib/transactions.utils'; export function getExplorerTxUrl({ chainId, @@ -19,7 +20,12 @@ export function getExplorerTxUrl({ txHash: string | undefined; blockExplorerUrl: string | undefined; }): string | undefined { - if (!txHash) { + const txId = + txHash && (!chainId.startsWith('eip155:') || isValidTransactionHash(txHash)) + ? txHash + : undefined; + + if (!txId) { return undefined; } @@ -29,7 +35,7 @@ export function getExplorerTxUrl({ ]; if (nonEvmExplorerUrls) { - return formatBlockExplorerTransactionUrl(nonEvmExplorerUrls, txHash); + return formatBlockExplorerTransactionUrl(nonEvmExplorerUrls, txId); } const hexChainId = getMaybeHexChainId(chainId); @@ -41,7 +47,7 @@ export function getExplorerTxUrl({ return undefined; } - return `${explorerRoot.replace(/\/$/u, '')}/tx/${txHash}`; + return `${explorerRoot.replace(/\/$/u, '')}/tx/${txId}`; } export function useBlockExplorerUrl( diff --git a/ui/pages/details/templates/bridge-details.tsx b/ui/pages/details/templates/bridge-details.tsx index a9f942a8db9d..c39a82dcbcb7 100644 --- a/ui/pages/details/templates/bridge-details.tsx +++ b/ui/pages/details/templates/bridge-details.tsx @@ -23,6 +23,7 @@ import { NetworkName } from '../../../components/app/transaction/network-name'; import { TransactionStatus } from '../../../components/app/transaction/transaction-status'; import { AccountName } from '../../../components/app/transaction/account-name'; import { TransactionId } from '../../../components/app/transaction/transaction-id'; +import { isValidTransactionHash } from '../../../../shared/lib/transactions.utils'; import { Footer, Row, Section } from '../components/shared'; import { TokenRow } from '../components/token-row'; import { FeesRows, TotalAmountRow } from '../components/amounts-section'; @@ -90,6 +91,13 @@ export function BridgeDetails({ ); const sourceTxHash = item.hash; + const txId = + sourceTxHash && + (!sourceChainId.startsWith('eip155:') || + isValidTransactionHash(sourceTxHash)) + ? sourceTxHash + : undefined; + const { destTxHash, destinationAccountAddress, fromAddress } = useSelector( (state) => { const bridgeHistoryItem = sourceTxHash @@ -191,7 +199,7 @@ export function BridgeDetails({ /> } + value={txId ? : null} />