From 0f02e6e54f91e003b1f7ac4ddc92d088bdb620a8 Mon Sep 17 00:00:00 2001 From: defiQUG Date: Mon, 8 Jun 2026 08:13:59 -0700 Subject: [PATCH] feat(explorer): show Ethereum mainnet Etherscan links on attested transactions. Render checkpoint batch attestation with per-layer mainnet tx links on the transaction detail page. Co-authored-by: Cursor --- frontend/package-lock.json | 40 +++++++++++- .../checkpoint/MainnetAttestationPanel.tsx | 65 +++++++++++++++++++ frontend/src/pages/transactions/[hash].tsx | 9 +++ frontend/src/services/api/tokenAggregation.ts | 15 +++++ 4 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 frontend/src/components/checkpoint/MainnetAttestationPanel.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index bfe263b..9805da2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -56,9 +56,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, @@ -2142,6 +2142,40 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@rolldown/binding-win32-arm64-msvc": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", diff --git a/frontend/src/components/checkpoint/MainnetAttestationPanel.tsx b/frontend/src/components/checkpoint/MainnetAttestationPanel.tsx new file mode 100644 index 0000000..8d4f6da --- /dev/null +++ b/frontend/src/components/checkpoint/MainnetAttestationPanel.tsx @@ -0,0 +1,65 @@ +import Link from 'next/link' +import { Card } from '@/libs/frontend-ui-primitives' +import type { CheckpointMainnetAttestationLink } from '@/services/api/tokenAggregation' + +function shortHash(hash: string): string { + if (hash.length < 20) return hash + return `${hash.slice(0, 10)}…${hash.slice(-8)}` +} + +export interface MainnetAttestationPanelProps { + batchId: string + batchTotalUsd?: string + links: CheckpointMainnetAttestationLink[] +} + +export default function MainnetAttestationPanel({ + batchId, + batchTotalUsd, + links, +}: MainnetAttestationPanelProps) { + return ( + +

+ This Chain 138 transaction is included in checkpoint batch #{batchId} + {batchTotalUsd ? ` · USD ref ${batchTotalUsd}` : ''}. +

+ + {links.length === 0 ? ( +

+ Attested on mainnet; Etherscan transaction links are indexing. Refresh in a minute or open the + checkpoint contracts on Etherscan. +

+ ) : ( +
    + {links.map((link) => ( +
  • +
    + + {link.label || link.layer} + + + {shortHash(link.mainnetTxHash)} ↗ + +
    + {(link.meta?.role || link.meta?.uetr) && ( +
    + {link.meta.role ? role: {link.meta.role} : null} + {link.meta.uetr ? UETR: {link.meta.uetr} : null} +
    + )} +
  • + ))} +
+ )} +
+ ) +} diff --git a/frontend/src/pages/transactions/[hash].tsx b/frontend/src/pages/transactions/[hash].tsx index 13fd8ca..4f60ae7 100644 --- a/frontend/src/pages/transactions/[hash].tsx +++ b/frontend/src/pages/transactions/[hash].tsx @@ -20,6 +20,7 @@ import PaginationControls from '@/components/common/PaginationControls' import SectionTabs, { type SectionTab } from '@/components/common/SectionTabs' import { getGruCatalogPosture } from '@/services/api/gruCatalog' import { assessTransactionCompliance } from '@/utils/transactionCompliance' +import MainnetAttestationPanel from '@/components/checkpoint/MainnetAttestationPanel' import { tokenAggregationApi, type CheckpointTxAttestationSnapshot, @@ -504,6 +505,14 @@ export default function TransactionDetailPage() { + {checkpointAttestation ? ( + + ) : null} + {activeTab === 'evidence' && complianceAssessment ? ( diff --git a/frontend/src/services/api/tokenAggregation.ts b/frontend/src/services/api/tokenAggregation.ts index 91c8649..88fe0af 100644 --- a/frontend/src/services/api/tokenAggregation.ts +++ b/frontend/src/services/api/tokenAggregation.ts @@ -37,6 +37,16 @@ export interface CheckpointTransferUsdLine { priceSource?: string } +export interface CheckpointMainnetAttestationLink { + layer: string + label: string + mainnetTxHash: string + mainnetExplorerUrl: string + contractAddress?: string + logIndex?: number + meta?: Record +} + export interface CheckpointTxAttestationSnapshot { txHash: string included: boolean @@ -50,6 +60,11 @@ export interface CheckpointTxAttestationSnapshot { priceSource?: string transfers?: CheckpointTransferUsdLine[] } | null + etherscanLinks?: CheckpointMainnetAttestationLink[] + etherscan?: { + base?: string + txUrlTemplate?: string + } source?: string }