#!/usr/bin/env node import fs from 'fs'; import path from 'path'; const repoRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..'); const smartContractsPath = path.join(repoRoot, 'config', 'smart-contracts-master.json'); const deploymentStatusPath = path.join(repoRoot, 'cross-chain-pmm-lps', 'config', 'deployment-status.json'); const outputJsonPath = path.join(repoRoot, 'reports', 'status', 'contract_verification_publish_matrix.json'); const outputMdPath = path.join(repoRoot, 'docs', '11-references', 'CONTRACT_VERIFICATION_AND_PUBLICATION_MATRIX_ALL_NETWORKS.md'); const CHAIN_META = { '1': { name: 'Ethereum Mainnet', explorer: 'https://etherscan.io', verifierKind: 'etherscan', publishSurface: 'Etherscan + repo inventory/token maps', }, '10': { name: 'Optimism', explorer: 'https://optimistic.etherscan.io', verifierKind: 'etherscan-family', publishSurface: 'Optimism explorer + repo inventory/token maps', }, '25': { name: 'Cronos', explorer: 'https://cronoscan.com', verifierKind: 'etherscan-family', publishSurface: 'Cronoscan + repo inventory/token maps', }, '56': { name: 'BSC', explorer: 'https://bscscan.com', verifierKind: 'etherscan-family', publishSurface: 'BscScan + repo inventory/token maps', }, '100': { name: 'Gnosis', explorer: 'https://gnosisscan.io', verifierKind: 'etherscan-family', publishSurface: 'Gnosis explorer + repo inventory/token maps', }, '1111': { name: 'Wemix', explorer: 'https://explorer.wemix.com', verifierKind: 'manual', publishSurface: 'Wemix explorer + repo inventory/token maps', }, '137': { name: 'Polygon', explorer: 'https://polygonscan.com', verifierKind: 'etherscan-family', publishSurface: 'PolygonScan + repo inventory/token maps', }, '138': { name: 'Chain 138', explorer: 'https://blockscout.defi-oracle.io', explorerAlt: 'https://explorer.d-bis.org', verifierKind: 'blockscout', publishSurface: 'Blockscout + repo inventory + explorer token/config surfaces', verificationScript: 'bash scripts/verify/run-contract-verification-with-proxy.sh', }, '42161': { name: 'Arbitrum', explorer: 'https://arbiscan.io', verifierKind: 'etherscan-family', publishSurface: 'Arbiscan + repo inventory/token maps', }, '42220': { name: 'Celo', explorer: 'https://celoscan.io', verifierKind: 'etherscan-family', publishSurface: 'Celo explorer + repo inventory/token maps', }, '43114': { name: 'Avalanche', explorer: 'https://snowtrace.io', verifierKind: 'etherscan-family', publishSurface: 'Snowtrace + repo inventory/token maps', }, '8453': { name: 'Base', explorer: 'https://basescan.org', verifierKind: 'etherscan-family', publishSurface: 'Basescan + repo inventory/token maps', }, '651940': { name: 'ALL Mainnet', explorer: 'https://alltra.global', verifierKind: 'manual', publishSurface: 'Alltra explorer/docs + repo inventory/token maps', }, }; function loadJson(filePath) { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } function ensureDir(filePath) { fs.mkdirSync(path.dirname(filePath), { recursive: true }); } function chainMeta(chainId, fallbackName = '') { const meta = CHAIN_META[String(chainId)] || {}; return { chainId: String(chainId), chainName: meta.name || fallbackName || `Chain ${chainId}`, explorer: meta.explorer || '', explorerAlt: meta.explorerAlt || '', verifierKind: meta.verifierKind || 'manual', publishSurface: meta.publishSurface || 'Explorer + repo inventory', verificationScript: meta.verificationScript || '', }; } function pushEntry(target, entry) { target.push({ verificationStatus: 'pending', publicationStatus: 'pending', publishRequirement: 'Verify source on chain explorer and keep repo inventories/token maps aligned', ...entry, }); } const smartContracts = loadJson(smartContractsPath); const deploymentStatus = loadJson(deploymentStatusPath); const entries = []; for (const [chainId, chainData] of Object.entries(smartContracts.chains || {})) { const meta = chainMeta(chainId); for (const [label, address] of Object.entries(chainData.contracts || {})) { pushEntry(entries, { sourceRegistry: 'config/smart-contracts-master.json', contractType: 'canonical_contract', label, address, ...meta, automation: chainId === '138' ? 'repo-supported' : 'manual-or-external', publishNotes: chainId === '138' ? 'Canonical Chain 138 contract; verify in Blockscout and keep reference docs current' : 'Mainnet relay or non-138 canonical contract; verify on chain explorer and mirror in repo docs', }); } } for (const [chainId, chainData] of Object.entries(deploymentStatus.chains || {})) { const meta = chainMeta(chainId, chainData.name); for (const [label, address] of Object.entries(chainData.cwTokens || {})) { pushEntry(entries, { sourceRegistry: 'cross-chain-pmm-lps/config/deployment-status.json', contractType: 'cw_token', label, address, ...meta, automation: 'inventory-only', publishNotes: 'Cross-chain wrapped/canonical token; verify on explorer and keep PMM/token-mapping inventories aligned', }); } for (const [label, address] of Object.entries(chainData.gasMirrors || {})) { pushEntry(entries, { sourceRegistry: 'cross-chain-pmm-lps/config/deployment-status.json', contractType: 'gas_mirror', label, address, ...meta, automation: 'inventory-only', publishNotes: 'Gas-family mirror token; verify on explorer and keep gas rollout inventory aligned', }); } for (const [label, address] of Object.entries(chainData.anchorAddresses || {})) { pushEntry(entries, { sourceRegistry: 'cross-chain-pmm-lps/config/deployment-status.json', contractType: 'anchor_token', label, address, ...meta, automation: 'reference-only', publishNotes: 'Anchor/reference asset; confirm explorer address and keep mapping docs current', }); } for (const pool of chainData.pmmPools || []) { pushEntry(entries, { sourceRegistry: 'cross-chain-pmm-lps/config/deployment-status.json', contractType: 'pmm_pool', label: `${pool.base}/${pool.quote}`, address: pool.poolAddress, ...meta, automation: chainId === '138' ? 'partial' : 'inventory-only', publishNotes: `PMM pool (${pool.role || 'unclassified'}); verify source if custom deployment and keep routing inventory aligned`, }); } for (const pool of chainData.pmmPoolsVolatile || []) { pushEntry(entries, { sourceRegistry: 'cross-chain-pmm-lps/config/deployment-status.json', contractType: 'pmm_pool_volatile', label: `${pool.base}/${pool.quote}`, address: pool.poolAddress, ...meta, automation: 'inventory-only', publishNotes: `Volatile PMM pool (${pool.role || 'unclassified'}); verify source where repo owns deployment and keep routing inventory aligned`, }); } for (const venue of chainData.gasReferenceVenues || []) { if (!venue.venueAddress) continue; pushEntry(entries, { sourceRegistry: 'cross-chain-pmm-lps/config/deployment-status.json', contractType: 'reference_venue', label: `${venue.protocol}:${venue.base}/${venue.quote}`, address: venue.venueAddress, ...meta, automation: 'inventory-only', publishNotes: 'Reference venue entry; verify only if repo owns deployment, otherwise treat as external dependency', }); } } entries.sort((a, b) => { if (a.chainId !== b.chainId) return Number(a.chainId) - Number(b.chainId); if (a.contractType !== b.contractType) return a.contractType.localeCompare(b.contractType); return a.label.localeCompare(b.label); }); const summaryByChain = new Map(); for (const entry of entries) { const key = `${entry.chainId}:${entry.chainName}`; const current = summaryByChain.get(key) || { total: 0, canonical: 0, cw: 0, pools: 0 }; current.total += 1; if (entry.contractType === 'canonical_contract') current.canonical += 1; if (entry.contractType === 'cw_token' || entry.contractType === 'gas_mirror') current.cw += 1; if (entry.contractType.includes('pmm_pool')) current.pools += 1; summaryByChain.set(key, current); } const generatedAt = new Date().toISOString(); const jsonPayload = { generatedAt, sources: [ 'config/smart-contracts-master.json', 'cross-chain-pmm-lps/config/deployment-status.json', ], entryCount: entries.length, entries, }; const summaryRows = [...summaryByChain.entries()] .map(([key, value]) => { const [chainId, chainName] = key.split(':'); const meta = chainMeta(chainId, chainName); return `| ${chainId} | ${chainName} | ${value.total} | ${value.canonical} | ${value.cw} | ${value.pools} | ${meta.explorer || 'manual'} |`; }) .join('\n'); const sampleRows = entries.slice(0, 80).map((entry) => { const explorer = entry.explorer || 'manual'; return `| ${entry.chainId} | ${entry.chainName} | ${entry.contractType} | ${entry.label} | \`${entry.address}\` | ${entry.verifierKind} | ${entry.automation} | ${explorer} | ${entry.verificationStatus} | ${entry.publicationStatus} |`; }).join('\n'); const md = `# Contract Verification And Publication Matrix (All Networks) **Generated:** ${generatedAt} **Authoritative sources:** \`config/smart-contracts-master.json\`, \`cross-chain-pmm-lps/config/deployment-status.json\` This matrix is the canonical repo-level inventory for **what still needs explorer verification and publication coverage across every network currently tracked in the workspace**. ## Meaning - **Verification** = source or deployment metadata is verified on the network explorer used for that chain. - **Publication** = the deployment is also reflected in the repo’s public inventories, token mappings, PMM status, and explorer-facing docs/config where applicable. - **Pending** means the repo knows the address, but does not yet have a machine-confirmed proof here that explorer verification/publication is complete. ## Chain Summary | Chain ID | Chain | Total Entries | Canonical Contracts | cW / Gas Mirrors | PMM Pools | Explorer | | --- | --- | ---: | ---: | ---: | ---: | --- | ${summaryRows} ## Required operator path 1. **Chain 138 canonical contracts** - Run: \`bash scripts/verify/run-contract-verification-with-proxy.sh\` - Recheck: \`bash scripts/verify/check-contracts-on-chain-138.sh\` 2. **Chain 138 DODO v3 pilot** - Run: \`bash scripts/verify/verify-dodo-v3-chain138-blockscout.sh\` 3. **Other EVM chains** - Verify on the chain explorer shown below. - If the repo owns the deployment, keep token/pool/mapping docs updated after explorer verification. 4. **Publication closure** - Update \`config/smart-contracts-master.json\`, \`cross-chain-pmm-lps/config/deployment-status.json\`, token lists, and any chain-specific runbooks after verification is confirmed. ## Inventory sample The JSON report in \`reports/status/contract_verification_publish_matrix.json\` contains the full set. The first 80 rows are shown here for readability. | Chain ID | Chain | Type | Label | Address | Verifier | Automation | Explorer | Verify | Publish | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ${sampleRows} ## Notes - Entries from \`smart-contracts-master.json\` are treated as the canonical deploy inventory. - Entries from \`deployment-status.json\` are treated as required publication inventory, even when explorer verification may be external or manual. - This matrix does **not** claim every address is already verified; it marks the repo-wide backlog explicitly so the status can be closed chain by chain instead of being lost in prose. `; ensureDir(outputJsonPath); ensureDir(outputMdPath); fs.writeFileSync(outputJsonPath, JSON.stringify(jsonPayload, null, 2) + '\n'); fs.writeFileSync(outputMdPath, md + '\n'); console.log(`Wrote ${entries.length} entries to:`); console.log(`- ${outputJsonPath}`); console.log(`- ${outputMdPath}`);