76 lines
2.6 KiB
JavaScript
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();
|