UNPKG

zonder

Version:

Ergonomic multi-chain indexing framework with dual runtime support for Ponder and Envio.

113 lines (112 loc) • 4.39 kB
import * as fs from 'fs'; import * as path from 'path'; import { safeWriteFileSync } from '../utils/safeWrite.js'; export function takeAbiFromFoundryOutput(foundryJsonPath) { try { const content = fs.readFileSync(foundryJsonPath, 'utf8'); const foundryOutput = JSON.parse(content); return foundryOutput.abi; } catch (error) { console.error(`Error reading ${foundryJsonPath}:`, error.message); return null; } } export function generateTypeScriptAbiFile(abi) { const formattedAbi = JSON.stringify(abi, null, 2); return `export default ${formattedAbi} as const;\n`; } function findContractFile(dirPath, targetContract) { const entries = fs.readdirSync(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); if (entry.isDirectory()) { const found = findContractFile(fullPath, targetContract); if (found) return found; } else if (entry.name === `${targetContract}.json`) { return fullPath; } } return null; } function findAllContractFiles(dirPath) { const contracts = []; if (!fs.existsSync(dirPath)) { return contracts; } const entries = fs.readdirSync(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); if (entry.isDirectory()) { contracts.push(...findAllContractFiles(fullPath)); } else if (entry.name.endsWith('.json')) { const contractName = entry.name.replace('.json', ''); contracts.push(contractName); } } return contracts; } export function extractSpecificContract(foundryOutDir, contractName, outputDir, overwrite = false) { if (!fs.existsSync(foundryOutDir)) { console.error(`Foundry output directory not found: ${foundryOutDir}`); return false; } if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } const contractJsonPath = findContractFile(foundryOutDir, contractName); if (!contractJsonPath) { console.error(`Contract ${contractName}.json not found in ${foundryOutDir}`); // Show available contracts const availableContracts = findAllContractFiles(foundryOutDir); if (availableContracts.length > 0) { const sortedContracts = [...new Set(availableContracts)].sort(); console.log('\nšŸ’” Available contracts:'); sortedContracts.forEach((contract) => { console.log(` - ${contract}`); }); console.log(`\nšŸ’” Usage: pnpm zonder take-abi ${foundryOutDir} ${sortedContracts.slice(0, 3).join(' ')}`); } return false; } const abi = takeAbiFromFoundryOutput(contractJsonPath); if (!abi || abi.length === 0) { console.error(`No ABI found for ${contractName}`); return false; } const tsContent = generateTypeScriptAbiFile(abi); const outputPath = path.join(outputDir, `${contractName}.ts`); safeWriteFileSync(outputPath, tsContent, { overwrite }); return true; } export function extractMultipleContracts(foundryOutDir, contractNames, outputDir = './abis', overwrite = false) { const foundryOutDirResolved = path.resolve(foundryOutDir); const outputDirResolved = path.resolve(outputDir); // Check if foundry out directory exists if (!fs.existsSync(foundryOutDirResolved)) { console.error(`āŒ Foundry output directory not found: ${foundryOutDirResolved}`); console.log('šŸ’” Make sure you have run "forge build" in your Foundry project first.'); process.exit(1); } let successCount = 0; let failCount = 0; for (const contractName of contractNames) { const success = extractSpecificContract(foundryOutDirResolved, contractName, outputDirResolved, overwrite); if (success) { successCount++; } else { failCount++; } } console.log(`\nExtraction completed: ${successCount} succeeded, ${failCount} failed`); if (failCount > 0) { process.exit(1); } } export async function takeAbi(outDir, contracts, overwrite = false) { return extractMultipleContracts(outDir, contracts, './abis', overwrite); }