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
All checks were successful
phoenix-deploy Deployed to explorer-live
Deploy Explorer Live / deploy (push) Successful in 3m6s
This commit is contained in:
37
frontend/src/components/common/MarketEvidenceNote.tsx
Normal file
37
frontend/src/components/common/MarketEvidenceNote.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
@@ -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 ? (
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
Reference in New Issue
Block a user