feat(explorer): show Ethereum mainnet Etherscan links on attested transactions.
Some checks failed
Deploy Explorer Live / deploy (push) Failing after 15s
Validate Explorer / frontend (push) Failing after 21s
Validate Explorer / smoke-e2e (push) Has been skipped

Render checkpoint batch attestation with per-layer mainnet tx links on the transaction detail page.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-06-08 08:13:59 -07:00
parent 4d6c2891cd
commit 0f02e6e54f
4 changed files with 126 additions and 3 deletions

View File

@@ -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",

View File

@@ -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 (
<Card title="Ethereum mainnet attestation">
<p className="text-sm text-gray-600 dark:text-gray-400">
This Chain 138 transaction is included in checkpoint batch #{batchId}
{batchTotalUsd ? ` · USD ref ${batchTotalUsd}` : ''}.
</p>
{links.length === 0 ? (
<p className="mt-3 text-sm text-gray-500 dark:text-gray-400">
Attested on mainnet; Etherscan transaction links are indexing. Refresh in a minute or open the
checkpoint contracts on Etherscan.
</p>
) : (
<ul className="mt-4 space-y-3">
{links.map((link) => (
<li
key={`${link.layer}:${link.mainnetTxHash}`}
className="rounded-2xl border border-primary-200/60 bg-primary-50/40 p-4 dark:border-primary-500/20 dark:bg-primary-950/20"
>
<div className="flex flex-wrap items-center gap-x-3 gap-y-2">
<span className="text-sm font-medium text-gray-900 dark:text-white">
{link.label || link.layer}
</span>
<Link
href={link.mainnetExplorerUrl}
target="_blank"
rel="noopener noreferrer"
className="font-mono text-sm text-primary-600 hover:underline dark:text-primary-400"
>
{shortHash(link.mainnetTxHash)}
</Link>
</div>
{(link.meta?.role || link.meta?.uetr) && (
<div className="mt-2 flex flex-wrap gap-3 text-xs text-gray-500 dark:text-gray-400">
{link.meta.role ? <span>role: {link.meta.role}</span> : null}
{link.meta.uetr ? <span>UETR: {link.meta.uetr}</span> : null}
</div>
)}
</li>
))}
</ul>
)}
</Card>
)
}

View File

@@ -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() {
</div>
</Card>
{checkpointAttestation ? (
<MainnetAttestationPanel
batchId={checkpointAttestation.batchId}
batchTotalUsd={checkpointAttestation.batchTotalUsd}
links={checkpointAttestation.etherscanLinks ?? []}
/>
) : null}
<SectionTabs tabs={tabs} activeTab={activeTab} onChange={setActiveTab} className="mb-6" />
{activeTab === 'evidence' && complianceAssessment ? (

View File

@@ -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<string, string>
}
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
}