Solc批量编译Solidity合约遇JSON解析错误,求技术支援
Hey there, let's fix that solc compilation issue you've been stuck on! The JSON parsing error you're seeing is almost certainly because you're not passing the correct standard JSON input format that solc@0.4.25 expects, especially when compiling multiple files. Let's break this down step by step, with code fixes and explanations of the key logic.
Why the Error Happens
solc (from v0.4 onwards) requires a structured JSON object for compilation, not just raw source code strings. Your error message says the input isn't a valid JSON object/array—this means your solc.compile call is receiving malformed input. Remix works because it automatically handles this standard JSON structure under the hood.
Step-by-Step Fix & Key Logic Explanation
Let's rewrite your compile.js with the correct approach, and explain each critical part:
1. Basic Setup & File Reading
First, we'll read all .sol files from the contracts directory, then build the standard JSON input structure.
const fs = require('fs-extra'); const solc = require('solc'); const path = require('path'); // Define paths const contractsDir = path.resolve(__dirname, 'contracts'); const buildDir = path.resolve(__dirname, 'build'); // Clear and rebuild build directory fs.removeSync(buildDir); fs.ensureDirSync(buildDir); // Read all .sol files const contractFiles = fs.readdirSync(contractsDir).filter(file => file.endsWith('.sol'));
2. Build the Standard JSON Input for solc
This is the most important part. The input must be a JSON object with language, sources, and settings keys:
sources: Maps each contract filename to its source codesettings: Tells solc what outputs to generate (ABI, bytecode, etc.)
const input = { language: 'Solidity', sources: {}, settings: { outputSelection: { '*': { '*': ['abi', 'evm.bytecode'] // We need these for Ethereum transactions } } } }; // Populate sources with contract code contractFiles.forEach(file => { const filePath = path.resolve(contractsDir, file); const sourceCode = fs.readFileSync(filePath, 'utf8'); input.sources[file] = { content: sourceCode }; });
3. Run Compilation Correctly
For solc@0.4.25, you need to pass the JSON string to solc.compile, or use solc.compileStandardWrapper (which handles the JSON parsing/stringifying for you). We'll use the standard wrapper for simplicity:
// Compile the contracts const output = JSON.parse(solc.compileStandardWrapper(JSON.stringify(input)));
4. Process Compilation Output & Write to Build Directory
Now we'll check for errors, then extract the ABI and bytecode for each valid contract, writing them to individual JSON files in build:
// Handle errors first if (output.errors) { // Write errors to errors.json (for debugging) fs.writeFileSync(path.resolve(buildDir, 'errors.json'), JSON.stringify(output.errors, null, 2)); // Check if errors are fatal const fatalErrors = output.errors.filter(err => err.severity === 'error'); if (fatalErrors.length > 0) { console.error('Fatal compilation errors:', fatalErrors); process.exit(1); } } // Extract and write valid contract artifacts for (const fileName in output.contracts) { for (const contractName in output.contracts[fileName]) { const contract = output.contracts[fileName][contractName]; const artifactPath = path.resolve(buildDir, `${contractName}.json`); // Write ABI and bytecode to the artifact file fs.writeFileSync(artifactPath, JSON.stringify({ abi: contract.abi, bytecode: contract.evm.bytecode.object }, null, 2)); console.log(`Successfully compiled ${contractName} from ${fileName}`); } }
Key Logic Breakdown
- Standard JSON Input: solc requires this structure to handle dependencies, imports, and output selection consistently—this is why your previous call failed (you were likely passing raw source instead of this structured JSON).
solc.compileStandardWrapper: This helper function takes the JSON string input, compiles it, and returns the parsed JSON output—saving you from manual stringify/parse steps and reducing errors.- Output Processing: We iterate over the compiled contracts (each file can have multiple contracts), extract the ABI (for interacting with the contract) and bytecode (for deploying), then write them to individual files in
build—exactly what you need for your React app's Ethereum transactions.
Verify the Fix
- Run your compile script again—you should see success messages for each valid contract.
- Check the
builddirectory: you'll have a.jsonfile for each contract with the ABI and bytecode. - In your React app, import these JSON files to access the ABI and bytecode when setting up contract instances (e.g., with web3.js or ethers.js).
Remember, since your contracts work in Remix, this fix should resolve the compilation issue without needing to switch to Truffle.
内容的提问来源于stack exchange,提问作者Ash

