All checks were successful
phoenix-deploy Deployed to explorer-live
Deploy Explorer Live / deploy (push) Successful in 2m18s
230 lines
13 KiB
TypeScript
230 lines
13 KiB
TypeScript
import { Card } from '@/libs/frontend-ui-primitives'
|
|
import { DetailRow } from '@/components/common/DetailRow'
|
|
import EntityBadge from '@/components/common/EntityBadge'
|
|
import type { GruStandardsProfile } from '@/services/api/gru'
|
|
import Link from 'next/link'
|
|
|
|
const STANDARD_EXPLANATIONS: Record<string, string> = {
|
|
'ERC-20': 'Base fungible-token surface for wallets, DEXs, explorers, and accounting systems.',
|
|
AccessControl: 'Role-governed administration for mint, burn, pause, and supervised operations.',
|
|
Pausable: 'Emergency intervention surface for freezing activity during incidents or policy actions.',
|
|
'EIP-712': 'Typed signing domain for structured off-chain approvals and payment flows.',
|
|
'ERC-2612': 'Permit support for signature-based approvals without a separate on-chain approve transaction.',
|
|
'ERC-3009': 'Authorization-based transfer model for signed payment flows without prior allowances.',
|
|
'ERC-5267': 'Discoverable EIP-712 domain introspection so wallets and relayers can inspect the signing domain cleanly.',
|
|
CashElectronicMoneyInterface: 'Repo-native GRU instrument methodology for issuance and redemption semantics.',
|
|
DeterministicStorageNamespace: 'Stable namespace for upgrade-aware policy, registry, and audit resolution.',
|
|
JurisdictionAndSupervisionMetadata: 'Governance, supervisory, disclosure, and reporting metadata required by the GRU operating model.',
|
|
}
|
|
|
|
const STANDARD_DISPLAY_LABELS: Record<string, string> = {
|
|
CashElectronicMoneyInterface: 'Cash electronic-money interface',
|
|
DeterministicStorageNamespace: 'Deterministic storage namespace',
|
|
JurisdictionAndSupervisionMetadata: 'Jurisdiction and supervision metadata',
|
|
}
|
|
|
|
function formatStandardLabel(id: string): string {
|
|
return STANDARD_DISPLAY_LABELS[id] || id
|
|
}
|
|
|
|
function formatProfileLabel(id: string): string {
|
|
if (id === 'gru-c-star-v2-public-network-and-payment') return 'GRU C* v2 payment profile'
|
|
return id
|
|
}
|
|
|
|
function formatDuration(seconds: number | null): string | null {
|
|
if (seconds == null || !Number.isFinite(seconds) || seconds <= 0) return null
|
|
const units = [
|
|
{ label: 'day', value: 86400 },
|
|
{ label: 'hour', value: 3600 },
|
|
{ label: 'minute', value: 60 },
|
|
]
|
|
const parts: string[] = []
|
|
let remaining = Math.floor(seconds)
|
|
for (const unit of units) {
|
|
if (remaining >= unit.value) {
|
|
const count = Math.floor(remaining / unit.value)
|
|
remaining -= count * unit.value
|
|
parts.push(`${count} ${unit.label}${count === 1 ? '' : 's'}`)
|
|
}
|
|
if (parts.length === 2) break
|
|
}
|
|
if (parts.length === 0) {
|
|
return `${remaining} second${remaining === 1 ? '' : 's'}`
|
|
}
|
|
return parts.join(' ')
|
|
}
|
|
|
|
export default function GruStandardsCard({
|
|
profile,
|
|
title = 'GRU v2 Standards',
|
|
}: {
|
|
profile: GruStandardsProfile
|
|
title?: string
|
|
}) {
|
|
const detectedCount = profile.standards.filter((standard) => standard.detected).length
|
|
const requiredCount = profile.standards.filter((standard) => standard.required).length
|
|
const missingRequired = profile.standards.filter((standard) => standard.required && !standard.detected)
|
|
const noticePeriod = formatDuration(profile.minimumUpgradeNoticePeriodSeconds)
|
|
const recommendations = [
|
|
missingRequired.length > 0
|
|
? `Review the live contract ABI and deployment against the GRU v2 base-token matrix before treating this asset as fully canonical.`
|
|
: `The live contract exposes the full required GRU v2 base-token surface currently checked by the explorer.`,
|
|
profile.wrappedTransport
|
|
? 'This looks like a cW public-network representation, so confirm the corresponding bridge lane and reserve-verifier posture in addition to the token ABI.'
|
|
: 'This looks like a canonical GRU asset, so the next meaningful checks are reserve, governance, and bridge activation beyond the token interface itself.',
|
|
profile.x402Ready
|
|
? 'This contract appears ready for x402-style payment flows because the explorer can see the required signature and domain surfaces.'
|
|
: 'This contract does not currently look x402-ready from the live explorer surface; verify EIP-712, ERC-5267, and permit or authorization flow exposure before using it as a payment rail.',
|
|
profile.forwardCanonical === true
|
|
? 'This version is marked forward-canonical, so it should be treated as the preferred successor surface even if older liquidity or bridge versions still coexist.'
|
|
: profile.forwardCanonical === false
|
|
? 'This version is not forward-canonical, which usually means it is legacy, staged, or bridge-only relative to the intended primary canonical surface.'
|
|
: 'Forward-canonical posture is not directly detectable on this contract, so rely on the bridge overlay and deployment records before making promotion assumptions.',
|
|
profile.legacyAliasSupport
|
|
? 'Legacy alias support is exposed, which is useful during version cutovers and explorer/search reconciliation.'
|
|
: 'Legacy alias support is not visible from the current explorer contract surface, so name/version migration may need registry or deployment-record cross-checks.',
|
|
'Use the repo standards references to reconcile any missing surface with the intended GRU profile and rollout phase.',
|
|
]
|
|
|
|
return (
|
|
<Card title={title}>
|
|
<dl className="space-y-4">
|
|
<DetailRow label="Profile">
|
|
<div className="space-y-2">
|
|
<div className="flex flex-wrap gap-2">
|
|
<EntityBadge label={formatProfileLabel(profile.profileId)} tone="info" className="normal-case tracking-normal" />
|
|
<EntityBadge
|
|
label={profile.wrappedTransport ? 'cW public-network' : 'canonical GRU'}
|
|
tone={profile.wrappedTransport ? 'warning' : 'success'}
|
|
/>
|
|
</div>
|
|
<div className="text-sm text-gray-600 dark:text-gray-400">
|
|
{detectedCount} of {requiredCount} required base-token standards are currently detectable from the live contract surface.
|
|
</div>
|
|
</div>
|
|
</DetailRow>
|
|
|
|
<DetailRow label="Standards" valueClassName="flex flex-wrap gap-2">
|
|
{profile.standards.map((standard) => (
|
|
<EntityBadge
|
|
key={standard.id}
|
|
label={standard.detected ? `${formatStandardLabel(standard.id)} detected` : `${formatStandardLabel(standard.id)} missing`}
|
|
tone={standard.detected ? 'success' : 'warning'}
|
|
className="normal-case tracking-normal"
|
|
/>
|
|
))}
|
|
</DetailRow>
|
|
|
|
<DetailRow label="Bridge Posture">
|
|
<div className="space-y-3">
|
|
<div className="flex flex-wrap gap-2">
|
|
<EntityBadge
|
|
label={profile.x402Ready ? 'x402 ready' : 'x402 not ready'}
|
|
tone={profile.x402Ready ? 'success' : 'warning'}
|
|
/>
|
|
<EntityBadge
|
|
label={
|
|
profile.forwardCanonical === true
|
|
? 'forward canonical'
|
|
: profile.forwardCanonical === false
|
|
? 'not forward canonical'
|
|
: 'forward canonical unknown'
|
|
}
|
|
tone={
|
|
profile.forwardCanonical === true
|
|
? 'success'
|
|
: profile.forwardCanonical === false
|
|
? 'warning'
|
|
: 'info'
|
|
}
|
|
/>
|
|
<EntityBadge
|
|
label={profile.legacyAliasSupport ? 'legacy aliases exposed' : 'no alias surface'}
|
|
tone={profile.legacyAliasSupport ? 'info' : 'warning'}
|
|
/>
|
|
</div>
|
|
<div className="grid gap-3 md:grid-cols-2">
|
|
<div className="rounded-xl border border-gray-200 bg-gray-50 p-3 text-sm dark:border-gray-700 dark:bg-gray-900/40">
|
|
<div className="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Settlement posture</div>
|
|
<div className="mt-2 text-gray-900 dark:text-white">
|
|
{profile.wrappedTransport
|
|
? 'This contract presents itself like a cW public-network representation instead of the canonical Chain 138 GRU surface.'
|
|
: 'This contract presents itself like the canonical Chain 138 GRU surface instead of a cW public-network representation.'}
|
|
</div>
|
|
</div>
|
|
<div className="rounded-xl border border-gray-200 bg-gray-50 p-3 text-sm dark:border-gray-700 dark:bg-gray-900/40">
|
|
<div className="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Upgrade notice</div>
|
|
<div className="mt-2 text-gray-900 dark:text-white">
|
|
{noticePeriod
|
|
? `${noticePeriod} (${profile.minimumUpgradeNoticePeriodSeconds} seconds)`
|
|
: 'No readable minimum upgrade notice period was detected from the current explorer surface.'}
|
|
</div>
|
|
</div>
|
|
<div className="rounded-xl border border-gray-200 bg-gray-50 p-3 text-sm dark:border-gray-700 dark:bg-gray-900/40">
|
|
<div className="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Version posture</div>
|
|
<div className="mt-2 text-gray-900 dark:text-white">
|
|
{profile.activeVersion || profile.forwardVersion
|
|
? `Active liquidity/bridge version: ${profile.activeVersion || 'unknown'}; preferred forward version: ${profile.forwardVersion || 'unknown'}.`
|
|
: 'No explicit active-versus-forward version posture is available from the local GRU catalog yet.'}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</DetailRow>
|
|
|
|
<DetailRow label="Interpretation">
|
|
<div className="space-y-3">
|
|
{profile.standards.map((standard) => (
|
|
<div key={`${standard.id}-explanation`} className="rounded-xl border border-gray-200 bg-gray-50 p-3 text-sm dark:border-gray-700 dark:bg-gray-900/40">
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<div className="font-medium text-gray-900 dark:text-white">{formatStandardLabel(standard.id)}</div>
|
|
<EntityBadge label={standard.detected ? 'detected' : 'missing'} tone={standard.detected ? 'success' : 'warning'} />
|
|
</div>
|
|
<div className="mt-2 text-gray-600 dark:text-gray-400">
|
|
{STANDARD_EXPLANATIONS[standard.id] || 'GRU-specific standard surfaced by the repo standards profile.'}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</DetailRow>
|
|
|
|
{profile.metadata.length > 0 ? (
|
|
<DetailRow label="Metadata">
|
|
<div className="space-y-3">
|
|
{profile.metadata.map((field) => (
|
|
<div key={field.label} className="rounded-xl border border-gray-200 bg-gray-50 p-3 text-sm dark:border-gray-700 dark:bg-gray-900/40">
|
|
<div className="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">{field.label}</div>
|
|
<div className="mt-2 break-all text-gray-900 dark:text-white">{field.value}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</DetailRow>
|
|
) : null}
|
|
|
|
<DetailRow label="References">
|
|
<div className="space-y-2 text-sm text-gray-600 dark:text-gray-400">
|
|
<div><Link href="/docs/gru" className="text-primary-600 hover:underline">Explorer GRU guide</Link></div>
|
|
<div>Canonical profile: <code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800">{formatProfileLabel(profile.profileId)}</code></div>
|
|
<div>Standards matrix: <code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800">GRU C* v2 implementation plan</code></div>
|
|
<div>Machine-readable profile: <code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800">GRU standards profile</code></div>
|
|
<div>Public-network overlay: <code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800">GRU cW representation registry</code></div>
|
|
<div>x402 support note: <code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800">Chain 138 x402 token support</code></div>
|
|
<div>Chain 138 readiness guide: <code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800">GRU v2 Chain 138 readiness</code></div>
|
|
</div>
|
|
</DetailRow>
|
|
|
|
<DetailRow label="Recommendations">
|
|
<div className="space-y-2 text-sm text-gray-600 dark:text-gray-400">
|
|
{recommendations.map((item) => (
|
|
<div key={item} className="rounded-xl border border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-gray-900/40">
|
|
{item}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</DetailRow>
|
|
</dl>
|
|
</Card>
|
|
)
|
|
}
|