Christopher Hirschauer
Builder @ the bleeding edge of MEV, automation, and high-speed arbitrage.
June 13, 2025
A lightweight Node.js script that compiles Solidity contracts using Foundry and extracts the ABI and bytecode into a clean JSON file. Perfect for deploying, testing, or integrating with frontends.
- β Checks if Foundry is installed
- π Prompts for contract directory and filename
- π οΈ Runs
forge buildautomatically - π¦ Extracts ABI and bytecode from Foundry's output
- π€ Saves to a user-defined location as structured JSON
Clone the repo and install dependencies (if needed):
git clone https://github.com/your-username/foundry-abi-extractor.git
cd foundry-abi-extractorMake the script executable:
chmod +x extractAbiBytecode.jsRun the script interactively:
node getBytecode.jsYou'll be prompted to:
- Enter the contract directory (e.g.,
src) - Enter the Solidity filename (e.g.,
MyContract.sol) - Specify the output path (e.g.,
build/MyContract.json)
node getBytecode.js
β‘ CLI Mode
node getBytecode.js --dir src --file MyContract.sol --out build/MyContract.json
The script generates a JSON file like:
{
"contract": "MyContract",
"abi": [ ... ],
"bytecode": "0x60806040..."
}- Foundry installed (
forgemust be available in your PATH) - Node.js v14+ recommended
- CLI flags for non-interactive mode
- Etherscan verification integration
- ABI-only or bytecode-only export options
- Auto-discovery of contracts in a directory
#!/usr/bin/env node
const path = require('path');
const fs = require('fs');
const readline = require('readline');
const { execSync } = require('child_process');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
function ask(question) {
return new Promise(resolve => rl.question(question, answer => resolve(answer.trim())));
}
function expandHome(p) {
return p.startsWith('~') ? path.join(process.env.HOME, p.slice(1)) : p;
}
function getFoundryForgePath() {
const forgePath = path.join(process.env.HOME, '.foundry/bin/forge');
if (!fs.existsSync(forgePath)) {
console.warn('β οΈ Foundry forge binary not found at ~/.foundry/bin/forge');
console.warn(' Make sure Foundry is installed via foundryup and your PATH is set correctly.');
return 'forge'; // fallback to system forge
}
// Sanity check: make sure it's Foundry's forge
try {
const versionOutput = execSync(`${forgePath} --version`).toString();
if (!versionOutput.toLowerCase().includes('foundry')) {
console.warn('β οΈ Detected forge binary is not Foundry. You may be using a conflicting tool like ZOE.');
}
} catch {
console.warn('β οΈ Unable to verify forge binary. Proceeding anyway.');
}
return forgePath;
}
(async () => {
try {
console.log('π§ Foundry Contract Compiler');
const contractDirInput = await ask('π Enter the Foundry project directory: ');
const contractFileInput = await ask('π Enter the contract file path (relative to project root): ');
const projectRoot = path.resolve(expandHome(contractDirInput));
const contractFileRelative = path.normalize(contractFileInput);
const fullContractPath = path.resolve(projectRoot, contractFileRelative);
const normalizedContractPath = path.relative(projectRoot, fullContractPath);
if (!fs.existsSync(fullContractPath)) {
console.error(`β Contract file not found at: ${fullContractPath}`);
rl.close();
process.exit(1);
}
console.log(`π Foundry project root: ${projectRoot}`);
console.log(`π Normalized contract path: ${normalizedContractPath}`);
const forgeBinary = getFoundryForgePath();
execSync(`${forgeBinary} build --contracts ${normalizedContractPath}`, {
cwd: projectRoot,
stdio: 'inherit',
});
console.log('β
Contract compiled successfully');
} catch (err) {
console.error('β Foundry build failed');
} finally {
rl.close();
}
})();Even though which forge points to Foundry, your compiler output says:
β Detected forge binary is not Foundry. You may be using a conflicting tool like ZOE.
That means something in your environment is still executing ZOEβs version, possibly via:
- A rogue alias
- A symlink
- A wrapper script
- A cached binary path
Letβs hunt it down.
alias forge
If you see anything, remove it:
unalias forge
ls -l $(which forge)
If itβs a symlink to /usr/bin/forge, delete it:
sudo rm /usr/bin/forge
Run:
echo $PATH
Make sure ~/.foundry/bin comes before /usr/bin. If not, fix it in .bashrc or .zshrc:
export PATH="$HOME/.foundry/bin:$PATH"
Then reload:
source ~/.bashrchash -r
foundryup --reinstall
Want a script that auto-detects ZOE and warns the user? Here's a snippet:
if forge --version 2>&1 | grep -q "ZOE"; then
echo "β ZOE detected. Please run: sudo rm /usr/bin/forge"
exit 1
fi
