- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138 - Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices - Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts Made-with: Cursor
318 lines
12 KiB
JavaScript
318 lines
12 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
const repoRoot = path.resolve(__dirname, "..", "..");
|
|
|
|
const deploymentStatusPath = path.join(repoRoot, "cross-chain-pmm-lps/config/deployment-status.json");
|
|
const manifestPath = path.join(repoRoot, "atomic-swap-dapp/config/ecosystem-manifest.json");
|
|
const liveRouteRegistryPath = path.join(repoRoot, "atomic-swap-dapp/config/live-route-registry.json");
|
|
const routingRegistryPath = path.join(repoRoot, "config/routing-registry.json");
|
|
const allMainnetProtocolSurfacePath = path.join(repoRoot, "config/allmainnet-non-dodo-protocol-surface.json");
|
|
const allMainnetTokenDocPath = path.join(repoRoot, "docs/11-references/ALL_MAINNET_TOKEN_ADDRESSES.md");
|
|
const markdownOutputPath = path.join(repoRoot, "reports/status/network-deployment-inventory-latest.md");
|
|
const jsonOutputPath = path.join(repoRoot, "reports/status/network-deployment-inventory-latest.json");
|
|
|
|
function readJson(filePath) {
|
|
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
}
|
|
|
|
function writeText(filePath, content) {
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
fs.writeFileSync(filePath, content);
|
|
}
|
|
|
|
function normalizeBool(value) {
|
|
if (value === true) return "✓";
|
|
if (value === false) return "—";
|
|
return "?";
|
|
}
|
|
|
|
function parseMarkdownTable(markdown, sectionTitle) {
|
|
const lines = markdown.split("\n");
|
|
const heading = `### ${sectionTitle}`;
|
|
const startIndex = lines.findIndex((line) => line.trim() === heading);
|
|
if (startIndex === -1) {
|
|
return [];
|
|
}
|
|
const tableLines = [];
|
|
for (const rawLine of lines.slice(startIndex + 1)) {
|
|
const line = rawLine.trim();
|
|
if (line.startsWith("### ") || line.startsWith("## ")) {
|
|
break;
|
|
}
|
|
tableLines.push(line);
|
|
}
|
|
|
|
const relevant = tableLines.filter((line) => line.startsWith("|"));
|
|
|
|
if (relevant.length < 3) {
|
|
return [];
|
|
}
|
|
|
|
const headers = relevant[0]
|
|
.split("|")
|
|
.slice(1, -1)
|
|
.map((cell) => cell.trim());
|
|
|
|
return relevant.slice(2).map((line) => {
|
|
const values = line
|
|
.split("|")
|
|
.slice(1, -1)
|
|
.map((cell) => cell.trim());
|
|
return Object.fromEntries(headers.map((header, index) => [header, values[index] ?? ""]));
|
|
}).filter(
|
|
(row) =>
|
|
row.Symbol &&
|
|
row.Symbol !== "Symbol" &&
|
|
row.Symbol !== "--------" &&
|
|
row.Address &&
|
|
row.Address !== "Address" &&
|
|
row.Address !== "---------"
|
|
);
|
|
}
|
|
|
|
function parseAllMainnetTokens(markdown) {
|
|
const sections = ["Stablecoins", "Wrapped Tokens", "DeFi Tokens"];
|
|
return sections.flatMap((section) =>
|
|
parseMarkdownTable(markdown, section).map((row) => ({
|
|
category: section,
|
|
token: row.Token,
|
|
symbol: row.Symbol,
|
|
address: row.Address?.replace(/`/g, "") ?? "",
|
|
decimals: Number(row.Decimals || 0),
|
|
status: row.Status,
|
|
notes: row.Notes
|
|
}))
|
|
);
|
|
}
|
|
|
|
function buildSpecialCaseBridgeList(liveRouteRegistry, routingRegistry, chainId) {
|
|
const liveRoutes = (liveRouteRegistry.liveBridgeRoutes ?? [])
|
|
.filter((route) => Number(route.fromChainId) === Number(chainId) || Number(route.toChainId) === Number(chainId))
|
|
.map((route) => ({
|
|
routeId: route.routeId,
|
|
fromChainId: route.fromChainId,
|
|
toChainId: route.toChainId,
|
|
bridgeType: route.bridgeType,
|
|
asset: route.assetSymbol,
|
|
bridgeAddress: route.bridgeAddress,
|
|
status: "live"
|
|
}));
|
|
|
|
if (liveRoutes.length > 0) {
|
|
return liveRoutes;
|
|
}
|
|
|
|
return (routingRegistry.routes ?? [])
|
|
.filter((route) => Number(route.fromChain) === Number(chainId) || Number(route.toChain) === Number(chainId))
|
|
.map((route) => ({
|
|
routeId: `${route.fromChain}-${route.toChain}-${route.asset}-${route.pathType}`.toLowerCase(),
|
|
fromChainId: route.fromChain,
|
|
toChainId: route.toChain,
|
|
bridgeType: route.pathType,
|
|
asset: route.asset,
|
|
bridgeAddress: route.bridgeAddress,
|
|
status: "configured"
|
|
}));
|
|
}
|
|
|
|
function countTokens(chainStatus) {
|
|
return Object.keys(chainStatus.cwTokens ?? {}).length;
|
|
}
|
|
|
|
function countAnchors(chainStatus) {
|
|
return Object.keys(chainStatus.anchorAddresses ?? {}).length;
|
|
}
|
|
|
|
function countPools(chainStatus, key) {
|
|
return Array.isArray(chainStatus[key]) ? chainStatus[key].length : 0;
|
|
}
|
|
|
|
function buildNextTasks(chainId) {
|
|
switch (Number(chainId)) {
|
|
case 138:
|
|
return [
|
|
"Keep Chain 138 PMM inventory, live swap routes, and public manifest synchronized after every token or pool deployment.",
|
|
"Replace remaining placeholder bridge metadata with canonical deployed addresses and keep bridge notes current.",
|
|
"Re-run route, inventory, and explorer verification audits after any bridge or pool change.",
|
|
"Maintain source-chain bridge support for CCIP, GRU, and Alltra routes as the canonical launch surface."
|
|
];
|
|
case 1111:
|
|
return [
|
|
"Keep Wemix marked `planned_gas_scaffold` and `bridgeAvailable: false` until a successful bridge proof transfer is recorded.",
|
|
"Replace placeholder gas PMM pools and gas reference venues with real deployed venues or remove them from the launch inventory.",
|
|
"Complete canonical Wemix bridge readiness: funding, proof transfer verification, and any required inbound/outbound confirmation.",
|
|
"Add real same-chain settlement inventory only after WEMIX-side execution is actually deployed and routable."
|
|
];
|
|
case 651940:
|
|
return [
|
|
"Add real same-chain Alltra swap inventory if users should settle into assets other than direct bridge receive.",
|
|
"Publish deployed PMM or public DEX pool addresses into canonical inventory instead of anchor-only metadata.",
|
|
"Expand the canonical Alltra token/routing surface only when those assets are actually part of supported settlement flows.",
|
|
"Keep AlltraAdapter bridge metadata, supported assets, and fee assumptions synchronized with deployed bridge behavior."
|
|
];
|
|
default:
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
const deploymentStatus = readJson(deploymentStatusPath);
|
|
const manifest = readJson(manifestPath);
|
|
const liveRouteRegistry = readJson(liveRouteRegistryPath);
|
|
const routingRegistry = readJson(routingRegistryPath);
|
|
const allMainnetProtocolSurface = readJson(allMainnetProtocolSurfacePath);
|
|
const allMainnetTokenDoc = fs.readFileSync(allMainnetTokenDocPath, "utf8");
|
|
|
|
const supportedNetworks = manifest.supportedNetworks ?? [];
|
|
const manifestByChain = new Map(supportedNetworks.map((network) => [String(network.chainId), network]));
|
|
const allMainnetTokens = parseAllMainnetTokens(allMainnetTokenDoc);
|
|
|
|
const chains = Object.entries(deploymentStatus.chains ?? {})
|
|
.map(([chainId, status]) => {
|
|
const manifestRow = manifestByChain.get(chainId) ?? {};
|
|
return {
|
|
chainId: Number(chainId),
|
|
chainKey: chainId,
|
|
network: status.name ?? manifestRow.name ?? `Chain ${chainId}`,
|
|
activationState: status.activationState ?? manifestRow.activationState ?? "live",
|
|
bridgeAvailable:
|
|
typeof status.bridgeAvailable === "boolean"
|
|
? status.bridgeAvailable
|
|
: Boolean(manifestRow.bridgeAvailable),
|
|
tokenCount: countTokens(status),
|
|
anchorCount: countAnchors(status),
|
|
pmmPoolCount: countPools(status, "pmmPools"),
|
|
volatilePoolCount: countPools(status, "pmmPoolsVolatile"),
|
|
gasPmmPoolCount: countPools(status, "gasPmmPools"),
|
|
referenceVenueCount: countPools(status, "gasReferenceVenues"),
|
|
uniswapV2PoolCount: countPools(status, "uniswapV2Pools"),
|
|
bridgeRouteCount: (manifestRow.routeCoverage?.inboundBridgeRoutes ?? 0) + (manifestRow.routeCoverage?.outboundBridgeRoutes ?? 0),
|
|
cwTokens: status.cwTokens ?? {},
|
|
anchorAddresses: status.anchorAddresses ?? {},
|
|
gasMirrors: status.gasMirrors ?? {},
|
|
gasQuoteAddresses: status.gasQuoteAddresses ?? {},
|
|
specialCaseBridges: buildSpecialCaseBridgeList(liveRouteRegistry, routingRegistry, chainId)
|
|
};
|
|
})
|
|
.sort((left, right) => left.chainId - right.chainId);
|
|
|
|
const specialCases = chains
|
|
.filter((chain) => [138, 1111, 651940].includes(chain.chainId))
|
|
.map((chain) => ({
|
|
...chain,
|
|
documentedTokens:
|
|
chain.chainId === 651940
|
|
? (allMainnetProtocolSurface.documentedTokens ?? allMainnetTokens)
|
|
: [],
|
|
nextTasks: buildNextTasks(chain.chainId)
|
|
}));
|
|
|
|
const markdown = [
|
|
"# Network Deployment Inventory",
|
|
"",
|
|
"| Chain | Network | Activation | Bridge Available | Tokens | Anchors | PMM | Volatile | Gas PMM | Ref Venues | UniV2 | Bridge Routes |",
|
|
"|---:|---|---|:---:|---:|---:|---:|---:|---:|---:|---:|---:|",
|
|
...chains.map(
|
|
(chain) =>
|
|
`| \`${chain.chainId}\` | ${chain.network} | \`${chain.activationState}\` | ${normalizeBool(chain.bridgeAvailable)} | ${chain.tokenCount} | ${chain.anchorCount} | ${chain.pmmPoolCount} | ${chain.volatilePoolCount} | ${chain.gasPmmPoolCount} | ${chain.referenceVenueCount} | ${chain.uniswapV2PoolCount} | ${chain.bridgeRouteCount} |`
|
|
),
|
|
"",
|
|
"## Special-Case Networks",
|
|
"",
|
|
...specialCases.flatMap((chain) => {
|
|
const bridgeLines =
|
|
chain.specialCaseBridges.length > 0
|
|
? chain.specialCaseBridges.map(
|
|
(bridge) =>
|
|
` - \`${bridge.fromChainId} -> ${bridge.toChainId}\` \`${bridge.bridgeType}\` \`${bridge.asset}\` at \`${bridge.bridgeAddress}\``
|
|
)
|
|
: [" - none recorded"];
|
|
|
|
const documentedTokenLines =
|
|
chain.documentedTokens.length > 0
|
|
? [
|
|
"",
|
|
"- Documented ecosystem tokens:",
|
|
...chain.documentedTokens.map(
|
|
(token) =>
|
|
` - \`${token.symbol}\` ${token.address} (${token.decimals} decimals; ${token.category}; ${token.status})`
|
|
)
|
|
]
|
|
: [];
|
|
|
|
return [
|
|
`### \`${chain.chainId}\` ${chain.network}`,
|
|
"",
|
|
`- Activation state: \`${chain.activationState}\``,
|
|
`- Bridge available: \`${chain.bridgeAvailable}\``,
|
|
`- cW tokens: ${Object.keys(chain.cwTokens).length ? Object.keys(chain.cwTokens).join(", ") : "none"}`,
|
|
`- Anchors: ${Object.keys(chain.anchorAddresses).length ? Object.entries(chain.anchorAddresses).map(([symbol, address]) => `${symbol}=${address}`).join(", ") : "none"}`,
|
|
`- PMM pools: \`${chain.pmmPoolCount}\``,
|
|
`- Gas PMM pools: \`${chain.gasPmmPoolCount}\``,
|
|
`- Gas/reference venues: \`${chain.referenceVenueCount}\``,
|
|
`- UniV2 pools: \`${chain.uniswapV2PoolCount}\``,
|
|
"- Bridge routes:",
|
|
...bridgeLines,
|
|
...documentedTokenLines,
|
|
"",
|
|
"- Next tasks:",
|
|
...chain.nextTasks.map((task) => ` - ${task}`),
|
|
""
|
|
];
|
|
})
|
|
].join("\n");
|
|
|
|
const json = {
|
|
name: "Network Deployment Inventory",
|
|
generatedAt: new Date().toISOString(),
|
|
sourceFiles: [
|
|
path.relative(repoRoot, deploymentStatusPath),
|
|
path.relative(repoRoot, manifestPath),
|
|
path.relative(repoRoot, liveRouteRegistryPath),
|
|
path.relative(repoRoot, routingRegistryPath),
|
|
path.relative(repoRoot, allMainnetProtocolSurfacePath),
|
|
path.relative(repoRoot, allMainnetTokenDocPath)
|
|
],
|
|
networks: chains.map((chain) => ({
|
|
chainId: chain.chainId,
|
|
network: chain.network,
|
|
activationState: chain.activationState,
|
|
bridgeAvailable: chain.bridgeAvailable,
|
|
tokenCount: chain.tokenCount,
|
|
anchorCount: chain.anchorCount,
|
|
pmmPoolCount: chain.pmmPoolCount,
|
|
volatilePoolCount: chain.volatilePoolCount,
|
|
gasPmmPoolCount: chain.gasPmmPoolCount,
|
|
referenceVenueCount: chain.referenceVenueCount,
|
|
uniswapV2PoolCount: chain.uniswapV2PoolCount,
|
|
bridgeRouteCount: chain.bridgeRouteCount
|
|
})),
|
|
specialCases: specialCases.map((chain) => ({
|
|
chainId: chain.chainId,
|
|
network: chain.network,
|
|
activationState: chain.activationState,
|
|
bridgeAvailable: chain.bridgeAvailable,
|
|
cwTokens: chain.cwTokens,
|
|
anchors: chain.anchorAddresses,
|
|
gasMirrors: chain.gasMirrors,
|
|
gasQuoteAddresses: chain.gasQuoteAddresses,
|
|
bridgeRoutes: chain.specialCaseBridges,
|
|
documentedTokens: chain.documentedTokens,
|
|
nextTasks: chain.nextTasks
|
|
}))
|
|
};
|
|
|
|
writeText(markdownOutputPath, `${markdown}\n`);
|
|
writeText(jsonOutputPath, `${JSON.stringify(json, null, 2)}\n`);
|
|
console.log(`Wrote ${path.relative(repoRoot, markdownOutputPath)}`);
|
|
console.log(`Wrote ${path.relative(repoRoot, jsonOutputPath)}`);
|
|
}
|
|
|
|
main();
|