Files
proxmox/token-lists/scripts/validate-chainlists.js
defiQUG cb47cce074 Complete markdown files cleanup and organization
- 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.
2026-01-06 01:46:25 -08:00

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);