Add market evidence notes to explorer surfaces
All checks were successful
phoenix-deploy Deployed to explorer-live
Deploy Explorer Live / deploy (push) Successful in 3m6s

This commit is contained in:
defiQUG
2026-04-30 03:53:13 -07:00
parent 8cd8bfa195
commit e397245ec9
6 changed files with 67 additions and 3 deletions

View File

@@ -0,0 +1,37 @@
import { formatRelativeAge, formatTimestamp } from '@/utils/format'
function formatSource(source?: string | null): string {
switch (source) {
case 'token-aggregation':
return 'token aggregation API'
case 'blockscout':
return 'Blockscout index'
case 'derived':
return 'derived from indexed supply and price inputs'
case 'mission-control':
return 'mission-control liquidity inventory'
default:
return source || 'source unavailable'
}
}
export default function MarketEvidenceNote({
source = 'token-aggregation',
lastUpdated,
method = 'DEX route and pool aggregation; visible liquidity only where indexed.',
compact = false,
}: {
source?: string | null
lastUpdated?: string | null
method?: string
compact?: boolean
}) {
const freshness = lastUpdated ? `${formatRelativeAge(lastUpdated)} (${formatTimestamp(lastUpdated)})` : 'timestamp unavailable'
const text = `Source: ${formatSource(source)}. Updated: ${freshness}. Method: ${method}`
return (
<p className={`${compact ? 'mt-1' : 'mt-3'} text-xs leading-5 text-gray-500 dark:text-gray-400`}>
{text}
</p>
)
}

View File

@@ -20,6 +20,7 @@ import { statsApi, type ExplorerStats } from '@/services/api/stats'
import { summarizeChainActivity } from '@/utils/activityContext'
import ActivityContextPanel from '@/components/common/ActivityContextPanel'
import FreshnessTrustNote from '@/components/common/FreshnessTrustNote'
import MarketEvidenceNote from '@/components/common/MarketEvidenceNote'
import SubsystemPosturePanel from '@/components/common/SubsystemPosturePanel'
import { resolveEffectiveFreshness } from '@/utils/explorerFreshness'
import {
@@ -318,6 +319,12 @@ export default function LiquidityOperationsPage({
<div className="mt-2 text-sm text-gray-600 dark:text-gray-400">
{formatNumber(dexCount)} DEX families in the current discovered pools.
</div>
<MarketEvidenceNote
source="mission-control"
lastUpdated={routeMatrix?.updated}
method="Route matrix, provider capabilities, and mission-control pool inventory are reconciled for visible public liquidity only."
compact
/>
</Card>
<Card>
<div className="text-sm text-gray-500 dark:text-gray-400">Fallback posture</div>
@@ -354,6 +361,12 @@ export default function LiquidityOperationsPage({
<div className="mt-2 text-sm text-gray-600 dark:text-gray-400">
Seen from {pool.sourceSymbols.join(', ')}
</div>
<MarketEvidenceNote
source="mission-control"
lastUpdated={routeMatrix?.updated}
method="Pool TVL is the visible mission-control value for discovered route-backed liquidity."
compact
/>
</div>
))}
{aggregatedPools.length === 0 ? (

View File

@@ -21,6 +21,7 @@ import { transactionsApi, type Transaction } from '@/services/api/transactions'
import { summarizeChainActivity } from '@/utils/activityContext'
import ActivityContextPanel from '@/components/common/ActivityContextPanel'
import FreshnessTrustNote from '@/components/common/FreshnessTrustNote'
import MarketEvidenceNote from '@/components/common/MarketEvidenceNote'
import { Explain, useUiMode } from '@/components/common/UiModeContext'
import { resolveEffectiveFreshness, shouldExplainEmptyHeadBlocks } from '@/utils/explorerFreshness'
import { tokenAggregationApi, type TokenAggregationTokenSnapshot } from '@/services/api/tokenAggregation'
@@ -794,6 +795,7 @@ export default function Home({
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
{token.market?.lastUpdated ? `Updated ${formatRelativeAge(token.market.lastUpdated)}` : 'Update time unavailable'}
</div>
<MarketEvidenceNote lastUpdated={token.market?.lastUpdated} compact />
</Link>
))}
</div>

View File

@@ -16,6 +16,7 @@ import {
import PageIntro from '@/components/common/PageIntro'
import { fetchPublicJson } from '@/utils/publicExplorer'
import { useUiMode } from '@/components/common/UiModeContext'
import MarketEvidenceNote from '@/components/common/MarketEvidenceNote'
type SearchFilterMode = 'all' | 'gru' | 'x402' | 'wrapped'
@@ -402,9 +403,12 @@ export default function SearchPage({
</span>
<Address address={result.data.address} truncate showCopy={false} />
{market ? (
<div className="flex flex-wrap gap-x-3 gap-y-1 text-sm text-gray-500 dark:text-gray-400">
<span>Live price: {formatUsd(market.priceUsd)}</span>
<span>Visible liquidity: {formatUsd(market.liquidityUsd)}</span>
<div className="text-sm text-gray-500 dark:text-gray-400">
<div className="flex flex-wrap gap-x-3 gap-y-1">
<span>Live price: {formatUsd(market.priceUsd)}</span>
<span>Visible liquidity: {formatUsd(market.liquidityUsd)}</span>
</div>
<MarketEvidenceNote lastUpdated={market.lastUpdated} compact />
</div>
) : null}
</Link>

View File

@@ -11,6 +11,7 @@ import PageIntro from '@/components/common/PageIntro'
import { DetailRow } from '@/components/common/DetailRow'
import EntityBadge from '@/components/common/EntityBadge'
import GruStandardsCard from '@/components/common/GruStandardsCard'
import MarketEvidenceNote from '@/components/common/MarketEvidenceNote'
import { formatTokenAmount, formatTimestamp } from '@/utils/format'
import { getGruStandardsProfileSafe, type GruStandardsProfile } from '@/services/api/gru'
import { getGruExplorerMetadata } from '@/services/api/gruExplorerData'
@@ -352,6 +353,11 @@ export default function TokenDetailPage() {
<div>Visible liquidity: {formatUsd(token.liquidity_usd)}</div>
<div>Valuation source: {token.price_source === 'token-aggregation' ? 'live token aggregation' : token.price_source || 'unavailable'}</div>
<div>Market snapshot: {token.market_updated_at ? formatTimestamp(token.market_updated_at) : 'Unavailable'}</div>
<MarketEvidenceNote
source={token.price_source}
lastUpdated={token.market_updated_at}
method="Merged Blockscout token profile with token aggregation price, volume, and visible-liquidity fields where available."
/>
</div>
</div>
<div className="rounded-2xl border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/40">

View File

@@ -5,6 +5,7 @@ import { useEffect, useMemo, useState } from 'react'
import { Card } from '@/libs/frontend-ui-primitives'
import PageIntro from '@/components/common/PageIntro'
import EntityBadge from '@/components/common/EntityBadge'
import MarketEvidenceNote from '@/components/common/MarketEvidenceNote'
import { tokensApi } from '@/services/api/tokens'
import type { TokenListToken } from '@/services/api/config'
import { tokenAggregationApi, type TokenAggregationTokenSnapshot } from '@/services/api/tokenAggregation'
@@ -203,6 +204,7 @@ export default function TokensPage({ initialCuratedTokens }: TokensPageProps) {
<div className="mt-3 space-y-1 text-sm text-gray-700 dark:text-gray-300">
<div>Live price: {formatUsd(market.priceUsd)}</div>
<div>Visible liquidity: {formatUsd(market.liquidityUsd)}</div>
<MarketEvidenceNote lastUpdated={market.lastUpdated} compact />
</div>
) : null}
{token.tags && token.tags.length > 0 && (