feat: explorer API, wallet, CCIP scripts, and config refresh

- Backend REST/gateway/track routes, analytics, Blockscout proxy paths.
- Frontend wallet and liquidity surfaces; MetaMask token list alignment.
- Deployment docs, verification scripts, address inventory updates.

Check: go build ./... under backend/ (pass).
Made-with: Cursor
This commit is contained in:
defiQUG
2026-04-07 23:22:12 -07:00
parent d931be8e19
commit 6eef6b07f6
224 changed files with 19671 additions and 3291 deletions

View File

@@ -0,0 +1,419 @@
'use client'
import { useEffect, useMemo, useState } from 'react'
import Link from 'next/link'
import { Card } from '@/libs/frontend-ui-primitives'
import { configApi, type TokenListResponse } from '@/services/api/config'
import {
aggregateLiquidityPools,
featuredLiquiditySymbols,
getLivePlannerProviders,
getRouteBackedPoolAddresses,
getTopLiquidityRoutes,
selectFeaturedLiquidityTokens,
type AggregatedLiquidityPool,
} from '@/services/api/liquidity'
import { plannerApi, type InternalExecutionPlanResponse, type PlannerCapabilitiesResponse } from '@/services/api/planner'
import { routesApi, type MissionControlLiquidityPool, type RouteMatrixResponse } from '@/services/api/routes'
import {
formatCurrency,
formatNumber,
relativeAge,
truncateMiddle,
} from './OperationsPageShell'
const tokenAggregationV1Base = '/token-aggregation/api/v1'
const tokenAggregationV2Base = '/token-aggregation/api/v2'
interface TokenPoolRecord {
symbol: string
pools: MissionControlLiquidityPool[]
}
function routePairLabel(routeId: string, routeLabel: string, tokenIn?: string, tokenOut?: string): string {
return [tokenIn, tokenOut].filter(Boolean).join(' / ') || routeLabel || routeId
}
export default function LiquidityOperationsPage() {
const [tokenList, setTokenList] = useState<TokenListResponse | null>(null)
const [routeMatrix, setRouteMatrix] = useState<RouteMatrixResponse | null>(null)
const [plannerCapabilities, setPlannerCapabilities] = useState<PlannerCapabilitiesResponse | null>(null)
const [internalPlan, setInternalPlan] = useState<InternalExecutionPlanResponse | null>(null)
const [tokenPoolRecords, setTokenPoolRecords] = useState<TokenPoolRecord[]>([])
const [loadingError, setLoadingError] = useState<string | null>(null)
useEffect(() => {
let cancelled = false
const load = async () => {
const [tokenListResult, routeMatrixResult, plannerCapabilitiesResult, planResult] =
await Promise.allSettled([
configApi.getTokenList(),
routesApi.getRouteMatrix(),
plannerApi.getCapabilities(),
plannerApi.getInternalExecutionPlan(),
])
if (cancelled) return
if (tokenListResult.status === 'fulfilled') setTokenList(tokenListResult.value)
if (routeMatrixResult.status === 'fulfilled') setRouteMatrix(routeMatrixResult.value)
if (plannerCapabilitiesResult.status === 'fulfilled') setPlannerCapabilities(plannerCapabilitiesResult.value)
if (planResult.status === 'fulfilled') setInternalPlan(planResult.value)
if (tokenListResult.status === 'fulfilled') {
const featuredTokens = selectFeaturedLiquidityTokens(tokenListResult.value.tokens || [])
const poolResults = await Promise.allSettled(
featuredTokens.map(async (token) => ({
symbol: token.symbol,
pools: (await routesApi.getTokenPools(token.address)).pools || [],
}))
)
if (!cancelled) {
setTokenPoolRecords(
poolResults
.filter((result): result is PromiseFulfilledResult<TokenPoolRecord> => result.status === 'fulfilled')
.map((result) => result.value)
)
}
}
const failedCount = [
tokenListResult,
routeMatrixResult,
plannerCapabilitiesResult,
planResult,
].filter((result) => result.status === 'rejected').length
if (failedCount === 4) {
setLoadingError('Live liquidity data is temporarily unavailable from the public explorer APIs.')
}
}
load().catch((error) => {
if (!cancelled) {
setLoadingError(
error instanceof Error ? error.message : 'Live liquidity data is temporarily unavailable from the public explorer APIs.'
)
}
})
return () => {
cancelled = true
}
}, [])
const featuredTokens = useMemo(
() => selectFeaturedLiquidityTokens(tokenList?.tokens || []),
[tokenList?.tokens]
)
const aggregatedPools = useMemo(
() => aggregateLiquidityPools(tokenPoolRecords),
[tokenPoolRecords]
)
const livePlannerProviders = useMemo(
() => getLivePlannerProviders(plannerCapabilities),
[plannerCapabilities]
)
const routeBackedPoolAddresses = useMemo(
() => getRouteBackedPoolAddresses(routeMatrix),
[routeMatrix]
)
const highlightedRoutes = useMemo(
() => getTopLiquidityRoutes(routeMatrix, 6),
[routeMatrix]
)
const dexCount = useMemo(
() => new Set(aggregatedPools.map((pool) => pool.dex).filter(Boolean)).size,
[aggregatedPools]
)
const insightLines = useMemo(
() => [
`${formatNumber(routeMatrix?.counts?.liveSwapRoutes)} live swap routes and ${formatNumber(routeMatrix?.counts?.liveBridgeRoutes)} bridge routes are currently published in the public route matrix.`,
`${formatNumber(aggregatedPools.length)} unique pools were discovered across ${formatNumber(featuredTokens.length)} featured Chain 138 liquidity tokens.`,
`${formatNumber(livePlannerProviders.length)} planner providers are live, and the current internal fallback decision is ${internalPlan?.plannerResponse?.decision || 'unknown'}.`,
`${formatNumber(routeBackedPoolAddresses.length)} unique pool addresses are referenced directly by the current live route legs.`,
],
[routeMatrix, aggregatedPools.length, featuredTokens.length, livePlannerProviders.length, internalPlan?.plannerResponse?.decision, routeBackedPoolAddresses.length]
)
const endpointCards = [
{
name: 'Canonical route matrix',
method: 'GET',
href: `${tokenAggregationV1Base}/routes/matrix?includeNonLive=true`,
notes: 'All live and non-live route inventory with counts and pool-backed legs.',
},
{
name: 'Planner capabilities',
method: 'GET',
href: `${tokenAggregationV2Base}/providers/capabilities?chainId=138`,
notes: 'Live provider inventory, published pair coverage, and execution modes.',
},
{
name: 'Internal execution plan',
method: 'POST',
href: `${tokenAggregationV2Base}/routes/internal-execution-plan`,
notes: 'Returns the direct-pool fallback posture that the operator surfaces already verify.',
},
{
name: 'Mission-control token pools',
method: 'GET',
href: `/explorer-api/v1/mission-control/liquidity/token/${featuredTokens[0]?.address || '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22'}/pools`,
notes: 'Cached public pool inventory for a specific Chain 138 token.',
},
]
return (
<main className="container mx-auto px-4 py-6 sm:py-8">
<div className="mb-8 max-w-4xl">
<div className="mb-3 inline-flex rounded-full border border-amber-200 bg-amber-50 px-3 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-amber-700">
Chain 138 Liquidity Access
</div>
<h1 className="mb-3 text-3xl font-bold text-gray-900 dark:text-white sm:text-4xl">
Public liquidity, route discovery, and execution access points
</h1>
<p className="text-base leading-7 text-gray-600 dark:text-gray-400 sm:text-lg sm:leading-8">
This page now reads the live explorer APIs instead of hardcoded pool snapshots. It pulls the
public route matrix, planner capabilities, and mission-control token pool inventory together
so integrators can inspect what Chain 138 is actually serving right now.
</p>
</div>
{loadingError ? (
<Card className="mb-6 border border-red-200 bg-red-50/70 dark:border-red-900/50 dark:bg-red-950/20">
<p className="text-sm leading-6 text-red-900 dark:text-red-100">{loadingError}</p>
</Card>
) : null}
<div className="mb-8 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
<Card className="border border-emerald-200 bg-emerald-50/70 dark:border-emerald-900/50 dark:bg-emerald-950/20">
<div className="text-sm font-semibold uppercase tracking-wide text-emerald-800 dark:text-emerald-100">
Live Pools
</div>
<div className="mt-2 text-3xl font-bold text-gray-900 dark:text-white">
{formatNumber(aggregatedPools.length)}
</div>
<div className="mt-2 text-sm text-gray-700 dark:text-gray-300">
Dedupe of mission-control pool inventory across featured Chain 138 tokens.
</div>
</Card>
<Card className="border border-sky-200 bg-sky-50/70 dark:border-sky-900/50 dark:bg-sky-950/20">
<div className="text-sm font-semibold uppercase tracking-wide text-sky-800 dark:text-sky-100">
Route Coverage
</div>
<div className="mt-2 text-3xl font-bold text-gray-900 dark:text-white">
{formatNumber(routeMatrix?.counts?.filteredLiveRoutes)}
</div>
<div className="mt-2 text-sm text-gray-700 dark:text-gray-300">
{formatNumber(routeMatrix?.counts?.liveSwapRoutes)} swaps and {formatNumber(routeMatrix?.counts?.liveBridgeRoutes)} bridges.
</div>
</Card>
<Card>
<div className="text-sm text-gray-500 dark:text-gray-400">Planner providers</div>
<div className="mt-2 text-3xl font-bold text-gray-900 dark:text-white">
{formatNumber(livePlannerProviders.length)}
</div>
<div className="mt-2 text-sm text-gray-600 dark:text-gray-400">
{formatNumber(dexCount)} DEX families in the current discovered pools.
</div>
</Card>
<Card>
<div className="text-sm text-gray-500 dark:text-gray-400">Fallback posture</div>
<div className="mt-2 text-3xl font-bold text-gray-900 dark:text-white">
{internalPlan?.plannerResponse?.decision || 'unknown'}
</div>
<div className="mt-2 text-sm text-gray-600 dark:text-gray-400">
Execution contract {truncateMiddle(internalPlan?.execution?.contractAddress)}
</div>
</Card>
</div>
<div className="mb-8 grid gap-6 lg:grid-cols-[1.2fr_0.8fr]">
<Card title="Live Pool Snapshot">
<div className="space-y-4">
{aggregatedPools.slice(0, 8).map((pool) => (
<div
key={pool.address}
className="rounded-2xl border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/40"
>
<div className="flex flex-col gap-2 md:flex-row md:items-center md:justify-between">
<div>
<div className="text-base font-semibold text-gray-900 dark:text-white">
{(pool.token0?.symbol || '?') + ' / ' + (pool.token1?.symbol || '?')}
</div>
<div className="mt-1 break-all text-xs text-gray-500 dark:text-gray-400">
Pool: {pool.address}
</div>
</div>
<div className="text-sm font-medium text-gray-700 dark:text-gray-300">
{pool.dex || 'Unknown DEX'} · TVL {formatCurrency(pool.tvl)}
</div>
</div>
<div className="mt-2 text-sm text-gray-600 dark:text-gray-400">
Seen from {pool.sourceSymbols.join(', ')}
</div>
</div>
))}
{aggregatedPools.length === 0 ? (
<p className="text-sm text-gray-600 dark:text-gray-400">
No live pool inventory is available right now.
</p>
) : null}
</div>
</Card>
<Card title="What Integrators Need To Know">
<div className="space-y-3 text-sm leading-6 text-gray-600 dark:text-gray-400">
{insightLines.map((item) => (
<p key={item}>{item}</p>
))}
<p>
Featured symbols in this view: {featuredLiquiditySymbols.join(', ')}.
</p>
</div>
</Card>
</div>
<div className="mb-8 grid gap-6 lg:grid-cols-[1fr_1fr]">
<Card title="Top Route-Backed Liquidity Paths">
<div className="space-y-4">
{highlightedRoutes.map((route) => (
<div
key={route.routeId}
className="rounded-2xl border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/40"
>
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<div>
<div className="text-base font-semibold text-gray-900 dark:text-white">
{routePairLabel(route.routeId, route.label || '', route.tokenInSymbol, route.tokenOutSymbol)}
</div>
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
{formatNumber((route.legs || []).length)} legs · {formatNumber((route.legs || []).filter((leg) => leg.poolAddress).length)} pool-backed
</div>
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">
{route.aggregatorFamilies?.join(', ') || 'No provider families listed'}
</div>
</div>
<div className="mt-2 text-sm text-gray-600 dark:text-gray-400">
{(route.legs || [])
.map((leg) => leg.poolAddress)
.filter(Boolean)
.map((address) => truncateMiddle(address))
.join(' · ') || 'No pool addresses published'}
</div>
</div>
))}
</div>
</Card>
<Card title="Featured Token Coverage">
<div className="space-y-4">
{featuredTokens.map((token) => {
const matchingRecord = tokenPoolRecords.find((record) => record.symbol === token.symbol)
return (
<div
key={token.address}
className="rounded-2xl border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/40"
>
<div className="text-base font-semibold text-gray-900 dark:text-white">
{token.symbol}
</div>
<div className="mt-1 text-sm text-gray-600 dark:text-gray-400">
{token.name || 'Unnamed token'} · {formatNumber(matchingRecord?.pools.length || 0)} mission-control pools
</div>
<div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
{truncateMiddle(token.address, 10, 8)}
</div>
</div>
)
})}
</div>
</Card>
</div>
<div className="mb-8">
<Card title="Explorer Access Points">
<div className="grid gap-4 md:grid-cols-2">
{endpointCards.map((endpoint) => (
<a
key={endpoint.href}
href={endpoint.href}
target="_blank"
rel="noopener noreferrer"
className="rounded-2xl border border-gray-200 bg-white p-5 transition hover:border-primary-400 hover:shadow-md dark:border-gray-700 dark:bg-gray-800"
>
<div className="flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="text-base font-semibold text-gray-900 dark:text-white">{endpoint.name}</div>
<span className="rounded-full bg-primary-50 px-2.5 py-1 text-xs font-semibold uppercase tracking-wide text-primary-700 dark:bg-primary-900/30 dark:text-primary-300">
{endpoint.method}
</span>
</div>
<div className="mt-3 break-all rounded-xl bg-gray-50 p-3 text-xs text-gray-700 dark:bg-gray-900 dark:text-gray-300">
{endpoint.href}
</div>
<div className="mt-3 text-sm leading-6 text-gray-600 dark:text-gray-400">{endpoint.notes}</div>
</a>
))}
</div>
</Card>
</div>
<div className="mb-8 grid gap-6 lg:grid-cols-[1fr_1fr]">
<Card title="Quick Request Examples">
<div className="space-y-4">
{[
`GET ${tokenAggregationV1Base}/routes/matrix?includeNonLive=true`,
`GET ${tokenAggregationV2Base}/providers/capabilities?chainId=138`,
`POST ${tokenAggregationV2Base}/routes/internal-execution-plan`,
`GET /explorer-api/v1/mission-control/liquidity/token/${featuredTokens[0]?.address || '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22'}/pools`,
].map((example) => (
<div key={example} className="rounded-2xl border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/40">
<code className="block break-all text-xs leading-6 text-gray-700 dark:text-gray-300">
{example}
</code>
</div>
))}
</div>
</Card>
<Card title="Related Explorer Tools">
<div className="space-y-4 text-sm leading-6 text-gray-600 dark:text-gray-400">
<p>
Use the wallet page for network onboarding, the pools page for a tighter live inventory
view, and this page for the broader route and execution surfaces.
</p>
<p>
The live route matrix was updated {relativeAge(routeMatrix?.updated)}, and the current
route-backed pool set references {formatNumber(routeBackedPoolAddresses.length)} unique
pool addresses.
</p>
<div className="flex flex-wrap gap-3">
<Link
href="/pools"
className="rounded-full bg-primary-600 px-4 py-2 text-sm font-medium text-white transition hover:bg-primary-700"
>
Open pools page
</Link>
<Link
href="/wallet"
className="rounded-full border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 transition hover:border-primary-400 hover:text-primary-700 dark:border-gray-600 dark:text-gray-300 dark:hover:text-primary-300"
>
Open wallet tools
</Link>
<a
href="/docs.html"
className="rounded-full border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 transition hover:border-primary-400 hover:text-primary-700 dark:border-gray-600 dark:text-gray-300 dark:hover:text-primary-300"
>
Explorer docs
</a>
</div>
</div>
</Card>
</div>
</main>
)
}