#!/usr/bin/env node /** * Blitzkrieg Step 2–3: Validate token list(s) and emit deterministic hash (hash lock). * Usage: node token-lists/scripts/validate-and-hash.js [dbis-138.tokenlist.json] [all-mainnet.tokenlist.json] * Default: token-lists/lists/dbis-138.tokenlist.json, then token-lists/lists/all-mainnet.tokenlist.json * Exits 0 if validation passes and hashes are printed; non-zero if validation fails. */ import { readFileSync, existsSync } from 'fs'; import { createHash } from 'crypto'; import { fileURLToPath } from 'url'; import { dirname, resolve } from 'path'; import { execSync } from 'child_process'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = resolve(__dirname, '../..'); const LISTS_DIR = resolve(ROOT, 'token-lists/lists'); const defaults = [ resolve(LISTS_DIR, 'dbis-138.tokenlist.json'), resolve(LISTS_DIR, 'all-mainnet.tokenlist.json') ]; const files = process.argv.slice(2).length ? process.argv.slice(2) : defaults.filter(f => existsSync(f)); if (files.length === 0) { console.error('No list files found. Usage: node validate-and-hash.js [file1 ...]'); process.exit(1); } let failed = false; for (const f of files) { const path = f.startsWith('/') ? f : resolve(process.cwd(), f); try { const raw = readFileSync(path, 'utf8'); JSON.parse(raw); // ensure valid JSON const hash = createHash('sha256').update(raw).digest('hex'); console.log(`${path}\tSHA256:${hash}`); // Run schema validation if validate-token-list.js exists try { execSync(`node "${resolve(__dirname, 'validate-token-list.js')}" "${path}"`, { stdio: 'pipe', cwd: ROOT }); } catch (_) { console.warn(`Schema validation skipped or failed for ${path}`); } } catch (e) { console.error(`${path}: ${e.message}`); failed = true; } } process.exit(failed ? 1 : 0);