Add bridge lane health API and config-ready lane UI for Tier A Week 3.
Some checks failed
Deploy Explorer Live / deploy (push) Failing after 13s
Validate Explorer / frontend (push) Failing after 21s
Validate Explorer / smoke-e2e (push) Has been skipped

Probe LINK balances on CCIP bridge contracts, expose proof-transfer metadata on bridge status, and render funded/unfunded lane health on /bridge with extended smoke coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-05-23 04:21:44 -07:00
parent 763ca75c21
commit 228fa0eef6
14 changed files with 605 additions and 3 deletions

View File

@@ -0,0 +1,107 @@
'use client'
import Link from 'next/link'
import { Card } from '@/libs/frontend-ui-primitives'
import EntityBadge from '@/components/common/EntityBadge'
import type { MissionControlBridgeLane, MissionControlBridgeLaneHealth } from '@/services/api/missionControl'
function laneTone(status?: string | null): 'success' | 'warning' | 'info' | 'neutral' {
switch (String(status || '').toLowerCase()) {
case 'funded':
case 'proof-recorded':
return 'success'
case 'degraded':
case 'proof-pending':
return 'warning'
case 'unfunded':
return 'warning'
default:
return 'neutral'
}
}
function formatLinkBalance(wei?: string | null): string {
if (!wei) return 'Unknown'
try {
const value = BigInt(wei)
const whole = value / 10n ** 18n
const fractional = (value % 10n ** 18n).toString().padStart(18, '0').slice(0, 4).replace(/0+$/, '')
return fractional ? `${whole}.${fractional} LINK` : `${whole} LINK`
} catch {
return wei
}
}
export default function BridgeLaneHealthPanel({
laneHealth,
className = '',
}: {
laneHealth?: MissionControlBridgeLaneHealth | null
className?: string
}) {
const lanes = laneHealth?.lanes || []
if (lanes.length === 0) return null
const normalizedClassName = className ? ` ${className}` : ''
return (
<Card title="Config-ready lane health" className={`mb-8${normalizedClassName}`}>
<p className="mb-4 text-sm text-gray-600 dark:text-gray-400">
LINK balances are read from each remote CCIP bridge contract. Proof-transfer status comes from operator-recorded CCIP message hashes when available.
</p>
<p className="mb-4 text-sm text-gray-600 dark:text-gray-400">
Operator runbook: fund LINK with{' '}
<code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-900">fund-ccip-bridges-with-link.sh</code>
{' '}· lane probe{' '}
<code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-900">probe-bridge-lane-link-balances.sh</code>
{' '}· routing reference{' '}
<Link href="/docs/public-api-access" className="text-primary-600 hover:underline">
public API access
</Link>
</p>
<div className="overflow-x-auto">
<table className="min-w-full text-sm">
<thead>
<tr className="border-b border-gray-200 text-left text-xs uppercase tracking-wide text-gray-500 dark:border-gray-700 dark:text-gray-400">
<th className="py-2 pr-4">Lane</th>
<th className="py-2 pr-4">Overall</th>
<th className="py-2 pr-4">Proof</th>
<th className="py-2 pr-4">WETH9 bridge</th>
<th className="py-2 pr-4">WETH10 bridge</th>
</tr>
</thead>
<tbody>
{lanes.map((lane: MissionControlBridgeLane) => (
<tr key={lane.key} className="border-b border-gray-100 align-top last:border-0 dark:border-gray-800">
<td className="py-3 pr-4">
<div className="font-medium text-gray-900 dark:text-white">{lane.chain_name || lane.key}</div>
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">chain {lane.chain_id ?? '?'}</div>
</td>
<td className="py-3 pr-4">
<EntityBadge label={lane.status || 'unknown'} tone={laneTone(lane.status)} />
</td>
<td className="py-3 pr-4">
<EntityBadge label={lane.proof_status || 'proof-pending'} tone={laneTone(lane.proof_status)} />
</td>
<td className="py-3 pr-4">
<div className="font-mono text-xs text-gray-700 dark:text-gray-300">{lane.weth9?.bridge || '—'}</div>
<div className="mt-1 flex flex-wrap items-center gap-2">
<EntityBadge label={lane.weth9?.status || 'unknown'} tone={laneTone(lane.weth9?.status)} className="px-2 py-0.5 text-[11px]" />
<span className="text-xs text-gray-600 dark:text-gray-400">{formatLinkBalance(lane.weth9?.link_balance_wei)}</span>
</div>
</td>
<td className="py-3 pr-4">
<div className="font-mono text-xs text-gray-700 dark:text-gray-300">{lane.weth10?.bridge || '—'}</div>
<div className="mt-1 flex flex-wrap items-center gap-2">
<EntityBadge label={lane.weth10?.status || 'unknown'} tone={laneTone(lane.weth10?.status)} className="px-2 py-0.5 text-[11px]" />
<span className="text-xs text-gray-600 dark:text-gray-400">{formatLinkBalance(lane.weth10?.link_balance_wei)}</span>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</Card>
)
}

View File

@@ -20,6 +20,7 @@ import { resolveEffectiveFreshness } from '@/utils/explorerFreshness'
import { bridgeRoutesApi, normalizeBridgeRouteEntries, type BridgeRoutesResponse } from '@/services/api/bridgeRoutes'
import { createVisibilityAwarePoller } from '@/utils/visibilityRefresh'
import { HOME_DASHBOARD_REFRESH_MS } from '@/utils/featuredTokens'
import BridgeLaneHealthPanel from '@/components/explorer/BridgeLaneHealthPanel'
import OperationsSurfaceNav from './OperationsSurfaceNav'
import OperationsActionGrid from './OperationsActionGrid'
@@ -460,6 +461,8 @@ export default function BridgeMonitoringPage({
))}
</div>
<BridgeLaneHealthPanel laneHealth={bridgeStatus?.data?.bridge_lanes} />
{routeEntries.length > 0 ? (
<Card title="CCIP route catalog" className="mb-8">
<p className="mb-4 text-sm text-gray-600 dark:text-gray-400">