Files
zeekay 353850b5a7 feat: dashboard pages + security hardening for intents, settlements, tx lifecycle
Backend:
- Reorg detection in tx tracker (re-verify block hash, detect receipt disappearance)
- Post-finalization safety margin (6 extra blocks before stopping tracking)
- Server-side HSM co-signing (HSMProvider interface, server calls HSM directly)
- Background intent expiry reaper (5-min sweep for stuck intents)
- Domain-separated intent hashing (lux-mpc-intent:v1 prefix)
- Backup rate limiting (max 3 active per wallet)
- Default backup changed to 2-of-3 (iCloud + HSM + offline) for fault tolerance
- All status transitions now use RecordTransition with proper actors

Frontend:
- Intents list page with status filter
- Intent detail page with lifecycle progress bar, sign/co-sign actions
- Settlements list page with status filter
- Settlement detail page with lifecycle, HSM signatures, transfer agency
- Enhanced transaction detail with on-chain confirmation, revert reason, status history
- Wallet backup UI with Shamir shard visualization
- Updated StatusBadge with all new status colors
- Nav updated with Intents + Settlements links
- Co-sign UI updated for server-side HSM flow (key_id only, no client signature)
2025-12-27 18:16:15 -08:00

57 lines
2.1 KiB
TypeScript

'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { useEffect, useState } from 'react'
import { getBranding } from '@/lib/branding'
import { UserMenu } from './user-menu'
const navLinks = [
{ href: '/dashboard' as const, label: 'Dashboard' },
{ href: '/vaults' as const, label: 'Vaults' },
{ href: '/transactions' as const, label: 'Transactions' },
{ href: '/intents' as const, label: 'Intents' },
{ href: '/settlements' as const, label: 'Settlements' },
{ href: '/policies' as const, label: 'Policies' },
{ href: '/bridge' as const, label: 'Bridge' },
{ href: '/team' as const, label: 'Team' },
{ href: '/settings' as const, label: 'Settings' },
]
export function Nav() {
const pathname = usePathname()
const [logoText, setLogoText] = useState('MPC')
useEffect(() => { setLogoText(getBranding(window.location.hostname).logoText) }, [])
return (
<header className="sticky top-0 z-50 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="mx-auto flex h-14 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
<div className="flex items-center gap-8">
<Link href="/dashboard" className="flex items-center gap-2">
<span className="text-lg font-semibold tracking-tight">{logoText}</span>
</Link>
<nav className="hidden items-center gap-1 md:flex">
{navLinks.map((link) => {
const isActive = pathname.startsWith(link.href)
return (
<Link
key={link.href}
href={link.href}
className={`rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${
isActive
? 'bg-accent text-accent-foreground'
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
}`}
>
{link.label}
</Link>
)
})}
</nav>
</div>
<UserMenu />
</div>
</header>
)
}