feat(explorer): token-list surfaces, homepage trim, and sprint smoke tests
Some checks failed
Deploy Explorer Live / deploy (push) Failing after 14s
Some checks failed
Deploy Explorer Live / deploy (push) Failing after 14s
Unify wallet/catalog/extended token-list policy, add contract verification CTA, trim the homepage dashboard with status strip and recent activity, and add Playwright smoke coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import Link from 'next/link'
|
||||
import { Card } from '@/libs/frontend-ui-primitives'
|
||||
|
||||
export const CONTRACT_VERIFICATION_GUIDE_URL =
|
||||
'https://gitea.d-bis.org/d-bis/proxmox/src/branch/master/docs/08-monitoring/BLOCKSCOUT_VERIFICATION_GUIDE.md'
|
||||
|
||||
export const FORGE_VERIFY_COMMAND =
|
||||
'source scripts/lib/load-project-env.sh && ./scripts/verify/run-contract-verification-with-proxy.sh'
|
||||
|
||||
interface ContractVerificationCalloutProps {
|
||||
address: string
|
||||
verified: boolean
|
||||
}
|
||||
|
||||
export default function ContractVerificationCallout({ address, verified }: ContractVerificationCalloutProps) {
|
||||
if (verified) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Card title="Verify & Publish Contract" className="mb-6">
|
||||
<p className="text-sm leading-6 text-gray-600 dark:text-gray-400">
|
||||
This contract is not verified on the public explorer yet. Verified source improves read/write tooling,
|
||||
ABI decoding, and auditability for{' '}
|
||||
<span className="font-mono text-xs">{address}</span>.
|
||||
</p>
|
||||
<ul className="mt-4 list-disc space-y-2 pl-5 text-sm text-gray-700 dark:text-gray-300">
|
||||
<li>
|
||||
<strong>Forge batch (recommended):</strong>{' '}
|
||||
<code className="rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-900">{FORGE_VERIFY_COMMAND}</code>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Operator guide:</strong>{' '}
|
||||
<Link href={CONTRACT_VERIFICATION_GUIDE_URL} className="text-primary-600 hover:underline" target="_blank" rel="noopener noreferrer">
|
||||
Blockscout verification guide
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Native Blockscout UI (LAN):</strong> use contract verification on the VM Blockscout instance when the custom explorer UI does not expose the form.
|
||||
</li>
|
||||
</ul>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { Card } from '@/libs/frontend-ui-primitives/Card'
|
||||
import { Address } from '@/libs/frontend-ui-primitives'
|
||||
import Link from 'next/link'
|
||||
import { blocksApi, type Block } from '@/services/api/blocks'
|
||||
import {
|
||||
@@ -129,6 +130,7 @@ export default function Home({
|
||||
const [featuredPrices, setFeaturedPrices] = useState<TokenAggregationTokenSnapshot[]>([])
|
||||
const [missionExpanded, setMissionExpanded] = useState(false)
|
||||
const [relayExpanded, setRelayExpanded] = useState(false)
|
||||
const [statsDetailsExpanded, setStatsDetailsExpanded] = useState(false)
|
||||
const [relayPage, setRelayPage] = useState(1)
|
||||
const [relayFeedState, setRelayFeedState] = useState<'connecting' | 'live' | 'fallback'>(
|
||||
initialRelaySummary || initialBridgeStatus ? 'fallback' : 'connecting'
|
||||
@@ -163,13 +165,13 @@ export default function Home({
|
||||
}, [chainId])
|
||||
|
||||
const loadFeaturedPrices = useCallback(async () => {
|
||||
const [curatedResult, reportResult] = await Promise.all([
|
||||
tokensApi.listCuratedSafe(chainId),
|
||||
const [catalogResult, reportResult] = await Promise.all([
|
||||
tokensApi.listForSurface('catalog', chainId),
|
||||
tokensApi.listReportSafe(chainId),
|
||||
])
|
||||
|
||||
const addresses = resolveHomePriceFeedAddresses(
|
||||
curatedResult.ok ? curatedResult.data : [],
|
||||
catalogResult.ok ? catalogResult.data : [],
|
||||
reportResult.ok ? reportResult.data : [],
|
||||
)
|
||||
|
||||
@@ -751,9 +753,20 @@ export default function Home({
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{(relaySummary || bridgeStatus || stats) && (
|
||||
<div className="mb-4 flex flex-wrap items-center gap-2 rounded-xl border border-gray-200 bg-white/80 px-4 py-3 text-sm shadow-sm dark:border-gray-800 dark:bg-gray-950/60">
|
||||
<EntityBadge label={`block ${latestBlock != null ? latestBlock.toLocaleString() : 'unknown'}`} tone="info" />
|
||||
{chainStatus?.status ? <EntityBadge label={`chain ${chainStatus.status}`} tone={chainStatus.status === 'operational' ? 'success' : 'warning'} /> : null}
|
||||
{relaySummary ? <EntityBadge label={`${relayOperationalCount} relays ok`} tone="success" /> : null}
|
||||
<EntityBadge label={relayFeedState === 'live' ? 'live feed' : relayFeedState === 'fallback' ? 'snapshot feed' : 'connecting'} tone={relayFeedState === 'live' ? 'success' : 'info'} />
|
||||
<span className="text-gray-600 dark:text-gray-400">{latestTransactionAgeLabel}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{stats && (
|
||||
<div className="mb-8 space-y-4">
|
||||
<div className="grid grid-cols-1 gap-3 sm:gap-4 md:grid-cols-4">
|
||||
<div className="mb-6 space-y-4">
|
||||
<p className="text-sm font-semibold text-gray-900 dark:text-white">Network overview</p>
|
||||
<div className="grid grid-cols-2 gap-3 md:grid-cols-4">
|
||||
{primaryMetricCards.map((card) => (
|
||||
<Card key={card.label}>
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400">{card.label}</div>
|
||||
@@ -763,48 +776,77 @@ export default function Home({
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-3 sm:gap-4 md:grid-cols-3">
|
||||
{activityMetricCards.map((card) => (
|
||||
<Card key={card.label}>
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400">{card.label}</div>
|
||||
<div className="text-xl font-bold sm:text-2xl">{card.value}</div>
|
||||
<div className="mt-2 text-sm text-gray-700 dark:text-gray-300">{card.note}</div>
|
||||
<div className="mt-2 text-xs text-gray-500 dark:text-gray-400">{card.detail}</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setStatsDetailsExpanded((current) => !current)}
|
||||
className="text-sm font-semibold text-primary-600 hover:underline"
|
||||
>
|
||||
{statsDetailsExpanded ? 'Hide telemetry and freshness' : 'Show telemetry and freshness'}
|
||||
</button>
|
||||
|
||||
{mode === 'guided' ? (
|
||||
<div className="grid grid-cols-1 gap-3 sm:gap-4 md:grid-cols-4">
|
||||
{secondaryMetricCards.map((card) => (
|
||||
<Card key={card.label}>
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400">{card.label}</div>
|
||||
<div className="text-xl font-bold sm:text-2xl">{card.value}</div>
|
||||
<div className="mt-2 text-xs text-gray-500 dark:text-gray-400">{card.note}</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<Card>
|
||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
||||
<div>
|
||||
<div className="text-sm font-semibold text-gray-900 dark:text-white">Telemetry Snapshot</div>
|
||||
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
Secondary public stats in a denser expert layout.
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid flex-1 gap-3 sm:grid-cols-2 xl:grid-cols-4">
|
||||
{statsDetailsExpanded ? (
|
||||
<>
|
||||
<div className="grid grid-cols-1 gap-3 sm:gap-4 md:grid-cols-3">
|
||||
{activityMetricCards.map((card) => (
|
||||
<Card key={card.label}>
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400">{card.label}</div>
|
||||
<div className="text-xl font-bold sm:text-2xl">{card.value}</div>
|
||||
<div className="mt-2 text-sm text-gray-700 dark:text-gray-300">{card.note}</div>
|
||||
<div className="mt-2 text-xs text-gray-500 dark:text-gray-400">{card.detail}</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{mode === 'guided' ? (
|
||||
<div className="grid grid-cols-1 gap-3 sm:gap-4 md:grid-cols-4">
|
||||
{secondaryMetricCards.map((card) => (
|
||||
<div key={card.label} className="rounded-2xl border border-gray-200 bg-gray-50/70 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/40">
|
||||
<div className="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">{card.label}</div>
|
||||
<div className="mt-1 text-lg font-semibold text-gray-900 dark:text-white">{card.value}</div>
|
||||
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">{card.note}</div>
|
||||
</div>
|
||||
<Card key={card.label}>
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400">{card.label}</div>
|
||||
<div className="text-xl font-bold sm:text-2xl">{card.value}</div>
|
||||
<div className="mt-2 text-xs text-gray-500 dark:text-gray-400">{card.note}</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
) : (
|
||||
<Card>
|
||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
||||
<div>
|
||||
<div className="text-sm font-semibold text-gray-900 dark:text-white">Telemetry Snapshot</div>
|
||||
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
Secondary public stats in a denser expert layout.
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid flex-1 gap-3 sm:grid-cols-2 xl:grid-cols-4">
|
||||
{secondaryMetricCards.map((card) => (
|
||||
<div key={card.label} className="rounded-2xl border border-gray-200 bg-gray-50/70 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/40">
|
||||
<div className="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">{card.label}</div>
|
||||
<div className="mt-1 text-lg font-semibold text-gray-900 dark:text-white">{card.value}</div>
|
||||
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">{card.note}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<ActivityContextPanel
|
||||
context={activityContext}
|
||||
title="Freshness Interpretation"
|
||||
compact
|
||||
/>
|
||||
<FreshnessTrustNote
|
||||
className="mt-3"
|
||||
context={activityContext}
|
||||
stats={stats}
|
||||
bridgeStatus={bridgeStatus}
|
||||
scopeLabel={
|
||||
mode === 'guided'
|
||||
? 'Homepage status combines chain freshness, transaction visibility, and mission-control posture.'
|
||||
: 'Homepage freshness view aligns chain, transaction, and mission-control posture.'
|
||||
}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -838,25 +880,6 @@ export default function Home({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="mb-8">
|
||||
<ActivityContextPanel
|
||||
context={activityContext}
|
||||
title="Freshness Interpretation"
|
||||
compact
|
||||
/>
|
||||
<FreshnessTrustNote
|
||||
className="mt-3"
|
||||
context={activityContext}
|
||||
stats={stats}
|
||||
bridgeStatus={bridgeStatus}
|
||||
scopeLabel={
|
||||
mode === 'guided'
|
||||
? 'Homepage status combines chain freshness, transaction visibility, and mission-control posture.'
|
||||
: 'Homepage freshness view aligns chain, transaction, and mission-control posture.'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!stats && (
|
||||
<Card className="mb-8">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
@@ -865,7 +888,46 @@ export default function Home({
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Card title="Recent Blocks">
|
||||
<div className="mb-8 grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||
<Card title="Recent Transactions">
|
||||
{recentTransactions.length === 0 ? (
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
Recent transactions are unavailable right now.
|
||||
</p>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{recentTransactions.map((transaction) => (
|
||||
<div key={transaction.hash} className="flex flex-col gap-1.5 border-b border-gray-200 py-2 last:border-0 dark:border-gray-700 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<Link href={`/transactions/${transaction.hash}`} className="text-primary-600 hover:underline">
|
||||
{transaction.hash.slice(0, 10)}...{transaction.hash.slice(-8)}
|
||||
</Link>
|
||||
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
Block #{transaction.block_number} · from{' '}
|
||||
<Address address={transaction.from_address} truncate showCopy={false} />
|
||||
{transaction.to_address ? (
|
||||
<>
|
||||
{' '}→ <Address address={transaction.to_address} truncate showCopy={false} />
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400 sm:text-right">
|
||||
<div>{formatWeiAsEth(transaction.value, 4)}</div>
|
||||
<div className="text-xs">{formatTimestamp(transaction.created_at)}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-4">
|
||||
<Link href="/transactions" className="text-primary-600 hover:underline">
|
||||
View all transactions →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card title="Recent Blocks">
|
||||
{recentBlocks.length === 0 ? (
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
Recent blocks are unavailable right now.
|
||||
@@ -903,120 +965,35 @@ export default function Home({
|
||||
View all blocks →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<div className="mt-8 grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||
<Card title="Activity Pulse">
|
||||
<p className="text-sm leading-6 text-gray-600 dark:text-gray-400">
|
||||
{mode === 'guided'
|
||||
? 'A concise public view of chain activity, index coverage, and recent execution patterns.'
|
||||
: 'Public chain activity and index posture.'}
|
||||
</p>
|
||||
<div className="mt-4 grid gap-3 sm:grid-cols-2">
|
||||
<div className="rounded-2xl border border-gray-200 bg-gray-50 p-4 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">Latest Daily Volume</div>
|
||||
<div className="mt-2 text-xl font-semibold text-gray-900 dark:text-white">
|
||||
{latestTrendPoint ? latestTrendPoint.transaction_count.toLocaleString() : 'Unknown'}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-gray-600 dark:text-gray-400">{latestTrendPoint?.date || 'Trend feed unavailable'}</div>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-gray-200 bg-gray-50 p-4 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">Recent Success Rate</div>
|
||||
<div className="mt-2 text-xl font-semibold text-gray-900 dark:text-white">
|
||||
{activitySnapshot ? `${Math.round(activitySnapshot.success_rate * 100)}%` : 'Unknown'}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
{activitySnapshot ? `${activitySnapshot.sample_size} sampled transactions` : 'Recent activity snapshot unavailable'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-gray-200 bg-gray-50 p-4 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">Avg Recent Fee</div>
|
||||
<div className="mt-2 text-xl font-semibold text-gray-900 dark:text-white">
|
||||
{activitySnapshot ? formatWeiAsEth(Math.round(activitySnapshot.average_fee_wei).toString(), 6) : 'Unknown'}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-gray-600 dark:text-gray-400">Average fee from the recent public sample.</div>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-gray-200 bg-gray-50 p-4 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">Peak Charted Day</div>
|
||||
<div className="mt-2 text-xl font-semibold text-gray-900 dark:text-white">
|
||||
{peakTrendPoint ? peakTrendPoint.transaction_count.toLocaleString() : 'Unknown'}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-gray-600 dark:text-gray-400">{peakTrendPoint?.date || 'No trend data yet'}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<Link href="/analytics" className="text-primary-600 hover:underline">
|
||||
Open full analytics →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
<Card title="Explorer Shortcuts">
|
||||
<p className="text-sm leading-6 text-gray-600 dark:text-gray-400">
|
||||
Go directly to the explorer surfaces that provide the strongest operational and discovery context.
|
||||
</p>
|
||||
<div className="mt-4 flex flex-wrap gap-3 text-sm">
|
||||
<Link href="/search" className="text-primary-600 hover:underline">
|
||||
Search →
|
||||
</Link>
|
||||
<Link href="/transactions" className="text-primary-600 hover:underline">
|
||||
Transactions →
|
||||
</Link>
|
||||
<Link href="/tokens" className="text-primary-600 hover:underline">
|
||||
Tokens →
|
||||
</Link>
|
||||
<Link href="/addresses" className="text-primary-600 hover:underline">
|
||||
Addresses →
|
||||
</Link>
|
||||
<Link href="/analytics" className="text-primary-600 hover:underline">
|
||||
Analytics →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
<Card title="Liquidity & Routes">
|
||||
<p className="text-sm leading-6 text-gray-600 dark:text-gray-400">
|
||||
Explore the public Chain 138 DODO PMM liquidity mesh, the canonical route matrix, and the
|
||||
partner payload endpoints exposed through the explorer.
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<Link href="/routes" className="text-primary-600 hover:underline">
|
||||
Open routes and liquidity →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
<Card title="Wallet & Token Discovery">
|
||||
<p className="text-sm leading-6 text-gray-600 dark:text-gray-400">
|
||||
Add Chain 138, Ethereum Mainnet, and ALL Mainnet to MetaMask, then use the explorer token
|
||||
list URL so supported tokens appear automatically.
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<Link href="/wallet" className="text-primary-600 hover:underline">
|
||||
Open wallet tools →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
<Card title="Bridge & Relay Monitoring">
|
||||
<p className="text-sm leading-6 text-gray-600 dark:text-gray-400">
|
||||
Open the public bridge monitoring surface for relay status, mission-control links, bridge trace tooling,
|
||||
and the visual command center entry points.
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<Link href="/bridge" className="text-primary-600 hover:underline">
|
||||
Open bridge monitoring →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
<Card title="Operations Hub">
|
||||
<p className="text-sm leading-6 text-gray-600 dark:text-gray-400">
|
||||
Open the public operations surface for wrapped-asset references, analytics shortcuts, operator links,
|
||||
system topology views, and other Chain 138 support tools.
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<Link href="/operations" className="text-primary-600 hover:underline">
|
||||
Open operations hub →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card title="Quick links" className="mt-8">
|
||||
<p className="text-sm leading-6 text-gray-600 dark:text-gray-400">
|
||||
Jump to the explorer surfaces used most often for discovery, liquidity, wallet setup, and bridge monitoring.
|
||||
</p>
|
||||
<div className="mt-4 grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<Link href="/search" className="rounded-xl border border-gray-200 px-4 py-3 text-sm font-semibold text-primary-600 hover:border-primary-400 dark:border-gray-800">
|
||||
Search
|
||||
</Link>
|
||||
<Link href="/tokens" className="rounded-xl border border-gray-200 px-4 py-3 text-sm font-semibold text-primary-600 hover:border-primary-400 dark:border-gray-800">
|
||||
Tokens
|
||||
</Link>
|
||||
<Link href="/wallet" className="rounded-xl border border-gray-200 px-4 py-3 text-sm font-semibold text-primary-600 hover:border-primary-400 dark:border-gray-800">
|
||||
Wallet & MetaMask
|
||||
</Link>
|
||||
<Link href="/routes" className="rounded-xl border border-gray-200 px-4 py-3 text-sm font-semibold text-primary-600 hover:border-primary-400 dark:border-gray-800">
|
||||
Liquidity & routes
|
||||
</Link>
|
||||
<Link href="/bridge" className="rounded-xl border border-gray-200 px-4 py-3 text-sm font-semibold text-primary-600 hover:border-primary-400 dark:border-gray-800">
|
||||
Bridge monitoring
|
||||
</Link>
|
||||
<Link href="/analytics" className="rounded-xl border border-gray-200 px-4 py-3 text-sm font-semibold text-primary-600 hover:border-primary-400 dark:border-gray-800">
|
||||
Analytics
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ export function AddToMetaMask({
|
||||
useEffect(() => {
|
||||
let active = true
|
||||
|
||||
tokensApi.listCuratedSafe(138).then(({ ok, data }) => {
|
||||
tokensApi.listForSurface('wallet', 138).then(({ ok, data }) => {
|
||||
if (active) {
|
||||
setCuratedTokens(ok ? (data as TokenListToken[]) : [])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user