Files
cross-chain-pmm-lps/scripts/validate-deployment-status.cjs
2026-03-02 12:14:07 -08:00

76 lines
2.6 KiB
JavaScript

#!/usr/bin/env node
/**
* Validates config/deployment-status.json for "minimum viable deployed graph".
* Use in CI so deployment-realistic sim cannot run with half-filled state.
*
* Rules:
* - If bridgeAvailable === true on a chain, cwTokens must include at least cWUSDT and cWUSDC (phase 1).
* - For each pmmPool: role in {defense, public_routing}, feeBps and k present,
* base/quote (or tokenIn/tokenOut) exist in cwTokens or anchorAddresses.
*
* Exit code: 0 if valid, 1 if invalid (and prints errors to stderr).
*/
const fs = require('fs');
const path = require('path');
const CONFIG_DIR = path.join(__dirname, '..', 'config');
const DEPLOYMENT_STATUS_PATH = path.join(CONFIG_DIR, 'deployment-status.json');
const PHASE1_CW = ['cWUSDT', 'cWUSDC'];
const VALID_ROLES = ['defense', 'public_routing'];
function loadJson(p) {
return JSON.parse(fs.readFileSync(p, 'utf8'));
}
function main() {
const status = loadJson(DEPLOYMENT_STATUS_PATH);
const chains = status.chains || {};
const errors = [];
for (const [chainId, chain] of Object.entries(chains)) {
const cwTokens = chain.cwTokens || {};
const anchorAddresses = chain.anchorAddresses || {};
const pmmPools = chain.pmmPools || [];
const bridgeAvailable = chain.bridgeAvailable;
if (bridgeAvailable === true) {
for (const sym of PHASE1_CW) {
if (!cwTokens[sym] || typeof cwTokens[sym] !== 'string' || !cwTokens[sym].trim()) {
errors.push(`Chain ${chainId} (${chain.name}): bridgeAvailable=true but cwTokens.${sym} missing or empty`);
}
}
}
const knownTokens = new Set([...Object.keys(cwTokens), ...Object.keys(anchorAddresses)]);
for (let i = 0; i < pmmPools.length; i++) {
const pool = pmmPools[i];
const base = pool.base ?? pool.tokenIn;
const quote = pool.quote ?? pool.tokenOut;
if (!VALID_ROLES.includes(pool.role)) {
errors.push(`Chain ${chainId} pmmPools[${i}]: role must be one of ${VALID_ROLES.join(', ')}`);
}
if (pool.feeBps == null || pool.k == null) {
errors.push(`Chain ${chainId} pmmPools[${i}]: feeBps and k required`);
}
if (base && !knownTokens.has(base)) {
errors.push(`Chain ${chainId} pmmPools[${i}]: base/tokenIn "${base}" not in cwTokens or anchorAddresses`);
}
if (quote && !knownTokens.has(quote)) {
errors.push(`Chain ${chainId} pmmPools[${i}]: quote/tokenOut "${quote}" not in cwTokens or anchorAddresses`);
}
}
}
if (errors.length > 0) {
errors.forEach((e) => process.stderr.write(e + '\n'));
process.exit(1);
}
process.exit(0);
}
main();