Files
smom-dbis-138/services/token-aggregation/src/api/routes/bridge.ts
defiQUG 76aa419320 feat: bridges, PMM, flash workflow, token-aggregation, and deployment docs
- CCIP/trustless bridge contracts, GRU tokens, DEX/PMM tests, reserve vault.
- Token-aggregation service routes, planner, chain config, relay env templates.
- Config snapshots and multi-chain deployment markdown updates.
- gitignore services/btc-intake/dist/ (tsc output); do not track dist.

Run forge build && forge test before deploy (large solc graph).

Made-with: Cursor
2026-04-07 23:40:52 -07:00

231 lines
7.9 KiB
TypeScript

/**
* Bridge API: cross-chain bridge status and metrics.
* GET /api/v1/bridge/routes — CCIP WETH9/WETH10 + Trustless (Snap / dApps).
* GET /api/v1/bridge/status, /api/v1/bridge/metrics, /api/v1/bridge/preflight — GRU Transport readiness + cross-chain guidance.
*/
import { Router, Request, Response } from 'express';
import fs from 'fs';
import path from 'path';
import { fetchRemoteJson } from '../utils/fetch-remote-json';
import { buildDefaultBridgeRoutes } from '../utils/default-bridge-routes';
import { getActivePublicPools, getActiveTransportPairs, getGruTransportMetadata } from '../../config/gru-transport';
import { logger } from '../../utils/logger';
const router: Router = Router();
function buildGruTransportStatus() {
const metadata = getGruTransportMetadata();
const transportPairs = getActiveTransportPairs();
const publicPools = getActivePublicPools();
if (!metadata) return null;
return {
system: metadata.system,
terminology: metadata.terminology,
summary: metadata.counts,
gasAssetFamilies: metadata.gasAssetFamilies ?? [],
gasRedeemGroups: metadata.gasRedeemGroups ?? [],
gasProtocolExposure: metadata.gasProtocolExposure ?? [],
pairs: transportPairs.map((pair) => ({
key: pair.key,
canonicalChainId: pair.canonicalChainId,
destinationChainId: pair.destinationChainId,
canonicalSymbol: pair.canonicalSymbol,
mirroredSymbol: pair.mirroredSymbol,
assetClass: pair.assetClass ?? null,
familyKey: pair.familyKey ?? null,
laneGroup: pair.laneGroup ?? null,
backingMode: pair.backingMode ?? null,
redeemPolicy: pair.redeemPolicy ?? null,
wrappedNativeQuoteSymbol: pair.wrappedNativeQuoteSymbol ?? null,
stableQuoteSymbol: pair.stableQuoteSymbol ?? null,
referenceVenue: pair.referenceVenue ?? null,
eligible: pair.eligible === true,
runtimeReady: pair.runtimeReady === true,
runtimeBridgeReady: pair.runtimeBridgeReady === true,
runtimeReserveVerifierReady: pair.runtimeReserveVerifierReady === true,
runtimeMaxOutstandingReady: pair.runtimeMaxOutstandingReady === true,
runtimeSupplyAccountingReady: pair.runtimeSupplyAccountingReady ?? null,
supplyInvariantSatisfied: pair.supplyInvariantSatisfied ?? null,
runtimeOutstandingValue: pair.runtimeOutstandingValue ?? null,
runtimeEscrowedValue: pair.runtimeEscrowedValue ?? null,
runtimeTreasuryBackedValue: pair.runtimeTreasuryBackedValue ?? null,
runtimeTreasuryCapValue: pair.runtimeTreasuryCapValue ?? null,
bridgeAvailable: pair.bridgeAvailable ?? null,
protocolExposure: pair.protocolExposure ?? null,
eligibilityBlockers: Array.isArray(pair.eligibilityBlockers) ? pair.eligibilityBlockers : [],
runtimeMissingRequirements: Array.isArray(pair.runtimeMissingRequirements) ? pair.runtimeMissingRequirements : [],
activePublicPoolKeys: Array.isArray(pair.publicPoolKeys) ? pair.publicPoolKeys : [],
})),
publicPools,
};
}
function uniquePaths(paths: Array<string | undefined | null>): string[] {
const seen = new Set<string>();
const out: string[] = [];
for (const candidate of paths) {
if (typeof candidate !== 'string') continue;
const trimmed = candidate.trim();
if (!trimmed || seen.has(trimmed)) continue;
seen.add(trimmed);
out.push(trimmed);
}
return out;
}
function resolveBridgeRoutesPath(): string | null {
const candidates = uniquePaths([
process.env.BRIDGE_LIST_JSON_PATH,
process.env.BRIDGE_ROUTES_JSON_PATH,
path.resolve(process.cwd(), 'config/bridge-routes-chain138-default.json'),
path.resolve(process.cwd(), '../config/bridge-routes-chain138-default.json'),
path.resolve(process.cwd(), '../../config/bridge-routes-chain138-default.json'),
path.resolve(__dirname, '../../../../../config/bridge-routes-chain138-default.json'),
]);
for (const candidate of candidates) {
if (fs.existsSync(candidate)) return candidate;
}
return null;
}
function loadRuntimeBridgeRoutes(): { payload: Record<string, unknown>; lastModified?: string } | null {
const filePath = resolveBridgeRoutesPath();
if (!filePath) return null;
try {
const raw = fs.readFileSync(filePath, 'utf8');
const stat = fs.statSync(filePath);
return {
payload: JSON.parse(raw) as Record<string, unknown>,
lastModified: stat.mtime.toISOString(),
};
} catch {
return null;
}
}
/**
* GET /api/v1/bridge/routes
* Optional BRIDGE_LIST_JSON_URL — remote JSON replaces entire payload (5m cache).
*/
router.get('/routes', async (_req: Request, res: Response) => {
const gruTransportMetadata = getGruTransportMetadata();
res.set('Cache-Control', 'public, max-age=0, must-revalidate');
const url = process.env.BRIDGE_LIST_JSON_URL?.trim();
if (url) {
try {
const data = await fetchRemoteJson(url);
const basePayload = data && typeof data === 'object' ? data : { data };
res.json({
source: 'remote-url',
...basePayload,
gruTransport: gruTransportMetadata
? {
system: gruTransportMetadata.system,
summary: gruTransportMetadata.counts,
activeTransportPairs: getActiveTransportPairs(),
activePublicPools: getActivePublicPools(),
}
: undefined,
});
return;
} catch (e) {
logger.error('BRIDGE_LIST_JSON_URL fetch failed, trying runtime file/built-in routes:', e);
}
}
const runtimePayload = loadRuntimeBridgeRoutes();
if (runtimePayload) {
res.json({
source: 'runtime-file',
lastModified: runtimePayload.lastModified,
...runtimePayload.payload,
gruTransport: gruTransportMetadata
? {
system: gruTransportMetadata.system,
summary: gruTransportMetadata.counts,
activeTransportPairs: getActiveTransportPairs(),
activePublicPools: getActivePublicPools(),
}
: undefined,
});
return;
}
res.json({
source: 'built-in',
...buildDefaultBridgeRoutes(),
});
});
router.get('/status', (_req: Request, res: Response) => {
const gruTransport = buildGruTransportStatus();
res.json({
ok: true,
bridges: [],
gruTransport,
message: 'Bridge status includes GRU Transport runtime readiness. Use /api/v1/bridge/preflight for missing refs and /api/v1/report/cross-chain for volume/lanes.',
});
});
router.get('/metrics', (_req: Request, res: Response) => {
const gruTransport = buildGruTransportStatus();
res.json({
ok: true,
lanes: [],
gruTransport: gruTransport
? {
system: gruTransport.system,
summary: gruTransport.summary,
}
: null,
message: 'Bridge metrics include GRU Transport summary counts. Use /api/v1/report/cross-chain for aggregated data.',
});
});
router.get('/preflight', (_req: Request, res: Response) => {
const gruTransport = buildGruTransportStatus();
if (!gruTransport) {
return res.status(503).json({
ok: false,
error: 'GRU transport config not available',
});
}
const blockedPairs = gruTransport.pairs.filter(
(pair) => pair.eligible !== true || pair.runtimeReady !== true
);
const readyPairs = gruTransport.pairs.filter(
(pair) => pair.eligible === true && pair.runtimeReady === true
);
return res.json({
ok: blockedPairs.length === 0,
generatedAt: new Date().toISOString(),
gruTransport: {
system: gruTransport.system,
summary: gruTransport.summary,
blockedPairs,
readyPairs: readyPairs.map((pair) => ({
key: pair.key,
canonicalSymbol: pair.canonicalSymbol,
mirroredSymbol: pair.mirroredSymbol,
destinationChainId: pair.destinationChainId,
assetClass: pair.assetClass ?? null,
familyKey: pair.familyKey ?? null,
backingMode: pair.backingMode ?? null,
redeemPolicy: pair.redeemPolicy ?? null,
supplyInvariantSatisfied: pair.supplyInvariantSatisfied ?? null,
})),
},
});
});
export default router;