#!/usr/bin/env -S tsx // Read JSON blobs line-by-line, containing keys `code` and `abi`, compare results import { ethers } from "ethers"; import { whatsabi } from "../src/index.js"; import readline from "readline"; main().then().catch(err => { console.error("Failed:", err) process.exit(2); }) async function main() { const pipe = readline.createInterface({ input: process.stdin, terminal: false }); const result = { elapsed: 0, // in ms count: 0, falsePositive: 0, falseNegative: 0, }; pipe.on('line', (line) => { let data: any; try { data = JSON.parse(line); } catch (error) { console.error("Failed to parse line:", error); return; } // Measure time spent in whatsabi const start = new Date(); const selectors = whatsabi.selectorsFromBytecode(data.code); const end = new Date(); // Compare results const want = new Set(); const sigs: Record = {}; ethers.Interface.from(data.abi).forEachFunction((fragment) => { want.add(fragment.selector); sigs[fragment.selector] = fragment.format(); }); const got = new Set(selectors); const falsePositive = [...got].filter(x => !want.has(x)); const falseNegative = [...want].filter(x => !got.has(x)); result.elapsed += end.getTime() - start.getTime(); result.count += 1; result.falsePositive += falsePositive.length; result.falseNegative += falseNegative.length; if (falsePositive.length > 0 || falseNegative.length > 0) { console.error({ address: data.address, id: result.count, falsePositive: falsePositive.map(s => { return {selector: s, signature: sigs[s] }}), falseNegative: falseNegative.map(s => { return {selector: s, signature: sigs[s] }}), }); } }); pipe.once('close', () => { console.log(result); }); };