- Organized 252 files across project - Root directory: 187 → 2 files (98.9% reduction) - Moved configuration guides to docs/04-configuration/ - Moved troubleshooting guides to docs/09-troubleshooting/ - Moved quick start guides to docs/01-getting-started/ - Moved reports to reports/ directory - Archived temporary files - Generated comprehensive reports and documentation - Created maintenance scripts and guides All files organized according to established standards.
177 lines
5.4 KiB
JavaScript
Executable File
177 lines
5.4 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
/**
|
|
* Validates chain configuration for Chainlists submission
|
|
*/
|
|
|
|
import { readFileSync } from 'fs';
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname, resolve } from 'path';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
const REQUIRED_FIELDS = [
|
|
'name',
|
|
'chain',
|
|
'chainId',
|
|
'networkId',
|
|
'rpc',
|
|
'nativeCurrency'
|
|
];
|
|
|
|
function validateChainConfig(filePath) {
|
|
console.log(`\n🔍 Validating chain configuration: ${filePath}\n`);
|
|
|
|
let config;
|
|
try {
|
|
const fileContent = readFileSync(filePath, 'utf-8');
|
|
config = JSON.parse(fileContent);
|
|
} catch (error) {
|
|
console.error('❌ Error reading or parsing chain config file:');
|
|
console.error(` ${error.message}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const errors = [];
|
|
const warnings = [];
|
|
|
|
// Validate required fields
|
|
REQUIRED_FIELDS.forEach(field => {
|
|
if (!(field in config)) {
|
|
errors.push(`Missing required field: ${field}`);
|
|
}
|
|
});
|
|
|
|
// Validate chainId
|
|
if (config.chainId !== 138) {
|
|
errors.push(`chainId must be 138, got ${config.chainId}`);
|
|
}
|
|
|
|
// Validate networkId
|
|
if (config.networkId && config.networkId !== 138) {
|
|
warnings.push(`networkId should match chainId (138), got ${config.networkId}`);
|
|
}
|
|
|
|
// Validate RPC URLs
|
|
if (!Array.isArray(config.rpc) || config.rpc.length === 0) {
|
|
errors.push('rpc must be a non-empty array');
|
|
} else {
|
|
config.rpc.forEach((url, index) => {
|
|
if (typeof url !== 'string' || (!url.startsWith('http://') && !url.startsWith('https://'))) {
|
|
errors.push(`rpc[${index}] must be a valid HTTP/HTTPS URL`);
|
|
}
|
|
if (url.startsWith('http://')) {
|
|
warnings.push(`rpc[${index}] should use HTTPS, not HTTP: ${url}`);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Validate nativeCurrency
|
|
if (config.nativeCurrency) {
|
|
if (!config.nativeCurrency.symbol) {
|
|
errors.push('nativeCurrency.symbol is required');
|
|
}
|
|
if (typeof config.nativeCurrency.decimals !== 'number') {
|
|
errors.push('nativeCurrency.decimals must be a number');
|
|
}
|
|
if (config.nativeCurrency.symbol !== 'ETH') {
|
|
warnings.push(`Expected nativeCurrency.symbol to be "ETH", got "${config.nativeCurrency.symbol}"`);
|
|
}
|
|
if (config.nativeCurrency.decimals !== 18) {
|
|
warnings.push(`Expected nativeCurrency.decimals to be 18, got ${config.nativeCurrency.decimals}`);
|
|
}
|
|
}
|
|
|
|
// Validate explorers (optional but recommended)
|
|
if (config.explorers && Array.isArray(config.explorers)) {
|
|
config.explorers.forEach((explorer, index) => {
|
|
if (!explorer.url) {
|
|
errors.push(`explorers[${index}].url is required`);
|
|
}
|
|
if (explorer.url && !explorer.url.startsWith('https://')) {
|
|
warnings.push(`explorers[${index}].url should use HTTPS: ${explorer.url}`);
|
|
}
|
|
if (!explorer.name) {
|
|
warnings.push(`explorers[${index}].name is recommended`);
|
|
}
|
|
if (!explorer.standard) {
|
|
warnings.push(`explorers[${index}].standard is recommended (e.g., "EIP3091")`);
|
|
}
|
|
});
|
|
} else {
|
|
warnings.push('No explorers configured (recommended for better UX)');
|
|
}
|
|
|
|
// Validate shortName
|
|
if (config.shortName && typeof config.shortName !== 'string') {
|
|
errors.push('shortName must be a string');
|
|
} else if (!config.shortName) {
|
|
warnings.push('shortName is recommended');
|
|
}
|
|
|
|
// Validate icon (optional)
|
|
if (config.icon && !config.icon.startsWith('https://') && !config.icon.startsWith('ipfs://')) {
|
|
warnings.push(`icon should use HTTPS or IPFS URL: ${config.icon}`);
|
|
}
|
|
|
|
// Report results
|
|
if (errors.length > 0) {
|
|
console.error('❌ Validation failed!\n');
|
|
console.error('Errors:');
|
|
errors.forEach(error => console.error(` ❌ ${error}`));
|
|
console.log('');
|
|
if (warnings.length > 0) {
|
|
console.log('⚠️ Warnings:');
|
|
warnings.forEach(warning => console.log(` ⚠️ ${warning}`));
|
|
console.log('');
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log('✅ Chain configuration is valid!\n');
|
|
|
|
if (warnings.length > 0) {
|
|
console.log('⚠️ Warnings:');
|
|
warnings.forEach(warning => console.log(` ⚠️ ${warning}`));
|
|
console.log('');
|
|
}
|
|
|
|
console.log('📋 Configuration Summary:');
|
|
console.log(` Name: ${config.name}`);
|
|
console.log(` Chain: ${config.chain}`);
|
|
console.log(` Short Name: ${config.shortName || '(not set)'}`);
|
|
console.log(` Chain ID: ${config.chainId}`);
|
|
console.log(` Network ID: ${config.networkId || '(not set)'}`);
|
|
console.log(` RPC URLs: ${config.rpc.length}`);
|
|
config.rpc.forEach((url, i) => console.log(` ${i + 1}. ${url}`));
|
|
if (config.explorers && config.explorers.length > 0) {
|
|
console.log(` Explorers: ${config.explorers.length}`);
|
|
config.explorers.forEach((exp, i) => {
|
|
console.log(` ${i + 1}. ${exp.name || '(unnamed)'}: ${exp.url}`);
|
|
if (exp.standard) {
|
|
console.log(` Standard: ${exp.standard}`);
|
|
}
|
|
});
|
|
}
|
|
if (config.nativeCurrency) {
|
|
console.log(` Native Currency: ${config.nativeCurrency.symbol} (${config.nativeCurrency.decimals} decimals)`);
|
|
}
|
|
if (config.infoURL) {
|
|
console.log(` Info URL: ${config.infoURL}`);
|
|
}
|
|
console.log('');
|
|
|
|
process.exit(0);
|
|
}
|
|
|
|
// Main
|
|
const filePath = process.argv[2] || resolve(__dirname, '../chainlists/chain-138.json');
|
|
|
|
if (!filePath) {
|
|
console.error('Usage: node validate-chainlists.js [path/to/chain.json]');
|
|
process.exit(1);
|
|
}
|
|
|
|
validateChainConfig(filePath);
|
|
|