Skip to content

74Thirsty/getBytecode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

15 Commits
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ§ͺ Foundry ABI & Bytecode Extractor

Copilot-20250601-124946.png

πŸ”§ Technologies & Tools

Cyfrin FlashBots Python Solidity pYcHARM Issues Lead Dev

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.


πŸš€ Features

  • βœ… Checks if Foundry is installed
  • πŸ“ Prompts for contract directory and filename
  • πŸ› οΈ Runs forge build automatically
  • πŸ“¦ Extracts ABI and bytecode from Foundry's output
  • πŸ“€ Saves to a user-defined location as structured JSON

πŸ“¦ Installation

Clone the repo and install dependencies (if needed):

git clone https://github.com/your-username/foundry-abi-extractor.git
cd foundry-abi-extractor

Make the script executable:

chmod +x extractAbiBytecode.js

πŸ§‘β€πŸ’» Usage

Run the script interactively:

node getBytecode.js

You'll be prompted to:

  1. Enter the contract directory (e.g., src)
  2. Enter the Solidity filename (e.g., MyContract.sol)
  3. 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

πŸ“‚ Output Format

The script generates a JSON file like:

{
  "contract": "MyContract",
  "abi": [ ... ],
  "bytecode": "0x60806040..."
}

πŸ›  Requirements

  • Foundry installed (forge must be available in your PATH)
  • Node.js v14+ recommended

🧠 Future Enhancements

  • CLI flags for non-interactive mode
  • Etherscan verification integration
  • ABI-only or bytecode-only export options
  • Auto-discovery of contracts in a directory

πŸš€ Script: extractAbiBytecode.js

#!/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();
  }
})();

πŸ” 1. ZOE Is Still Interfering

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.


🧨 Step-by-Step ZOE Exorcism

βœ… 1. Check for aliases

alias forge

If you see anything, remove it:

unalias forge

βœ… 2. Check for symlinks

ls -l $(which forge)

If it’s a symlink to /usr/bin/forge, delete it:

sudo rm /usr/bin/forge

βœ… 3. Check your $PATH order

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 ~/.bashrc

βœ… 4. Clear shell cache

hash -r

βœ… 5. Reinstall Foundry (optional but clean)

foundryup --reinstall

🧠 Bonus: Detect ZOE in Your Script

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

About

Extracts abi bytecode from smart contracts.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published