/evm

A Symbolic Ethereum Virtual Machine (EVM) bytecode interpreter, parser and decompiler, along with several other utils for programmatically extracting information from EVM bytecode.

Primary LanguageTypeScriptMIT LicenseMIT

EVM Bytecode Decompiler

GitHub Workflow Status nycrc config on GitHub npm npm GitHub install size Demo

A Symbolic Ethereum Virtual Machine (EVM) interpreter and decompiler, along with several other utils for programmatically extracting information from bytecode.

Forked from MrLuit/evm. For more info, see Detached Fork.

Features

🚧 Under heavy development. Feel free to open an issue if something is not right. 🚧

  • Lightweight with no dependencies
  • Embedded signature database WIP
  • Convert bytecode to opcodes
  • Read information like events or functions from either bytecode or TX data
  • Extract the IPFS or swarm hash (when present) from bytecode
  • Check whether an opcode exists and is reachable within bytecode execution
  • Detect whether contracts are compliant to certain ERCs

Install

Install using your package manager or Browser's script tag

yarn

yarn add sevm

npm

npm install sevm

or to install globally in your system

npm install --global sevm

Browser WIP

<script src="https://cdn.jsdelivr.net/gh/acuarica/evm@f88b20a/lib/EVM.js"></script>

API    TypeDoc

Main Methods and Properties

Usage

Converting Bytecode to Opcodes

Node.js

const { EVM } = require('evm');
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('https://api.mycryptoapi.com/eth'));

web3.eth.getCode('0x06012c8cf97BEaD5deAe237070F9587f8E7A266d').then(code => {
  /* CryptoKitties contract */
  const evm = new EVM(code);
  console.log(evm.getOpcodes()); /* Get opcodes */
});

Browser

const { EVM } = window.EVM_Utils;
const web3 = new Web3(window.web3.currentProvider);
web3.eth.getCode('0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359', function (err, code) {
  /* DAI contract */ if (err) throw err;
  const evm = new EVM(code);
  console.log(evm.getOpcodes()); /* Get opcodes */
});

Decompiling a Contract

Node.js

const { EVM } = require('evm');
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('https://api.mycryptoapi.com/eth'));

web3.eth.getCode('0x06012c8cf97BEaD5deAe237070F9587f8E7A266d').then(code => {
  /* CryptoKitties contract */
  const evm = new EVM(code);
  console.log(evm.getFunctions()); /* Get functions */
  console.log(evm.getEvents()); /* Get events */
  console.log(evm.decompile()); /* Decompile bytecode */
  console.log(
    evm.containsOpcode('SELFDESTRUCT')
  ); /* Check whether contract contains a SELFDESTRUCT */
  console.log(evm.isERC165()); /* Detect whether contract is ERC165-compliant */
});

Browser

const { EVM } = window.EVM;
const web3 = new Web3(window.web3.currentProvider);
web3.eth.getCode('0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359', function (err, code) {
  /* DAI contract */ if (err) throw err;
  const evm = new EVM(code);
  console.log(evm.getFunctions()); /* Get functions */
  console.log(evm.getEvents()); /* Get events */
  console.log(evm.decompile()); /* Decompile bytecode */
  console.log(
    evm.containsOpcode('SELFDESTRUCT')
  ); /* Check whether contract contains a SELFDESTRUCT */
  console.log(evm.isERC165()); /* Detect whether contract is ERC165-compliant */
});

Extracting data from transaction WIP

Node.js

const { Transaction } = require('evm');
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('https://api.mycryptoapi.com/eth'));

web3.eth
  .getTransaction('0xd20a8d888a3f29471ea41ea77cc2d95ccd79ade1eaad059e83524e72b9adf962')
  .then(transactionData => {
    const transaction = new Transaction();
    transaction.setInput(transactionData.input);
    console.log(transaction.getFunction()); /* Get function */
  });

Browser

const { Transaction } = window.EVM;
const web3 = new Web3(window.web3.currentProvider);
web3.eth.getTransaction(
  '0xd20a8d888a3f29471ea41ea77cc2d95ccd79ade1eaad059e83524e72b9adf962',
  function (err, transactionData) {
    if (err) throw err;
    const transaction = new Transaction();
    transaction.setInput(transactionData.input);
    console.log(transaction.getFunction()); /* Get function */
  }
);

--help

$ sevm --help
sevm <cmd> <contract>

Commands:
  sevm metadata <contract>  Shows the Metadata of the contract[1]
  sevm abi <contract>       Shows the ABI of the contract[2]
  sevm dis <contract>       Disassemble the bytecode into Opcodes
  sevm cfg <contract>       Writes the cfg of the selected function in `dot` for
                            mat into standard output
  sevm sol <contract>       Decompile the contract's bytecode into Solidity-like
                             source code
  sevm yul <contract>       Decompile the contract's bytecode into Yul-like sour
                            ce code[3]
  sevm config               Shows cache path used to store downloaded bytecode

Options:
      --version   Show version number                                  [boolean]
      --color     Display with colors, use `--no-color` to deactivate colors
                                                       [boolean] [default: true]
  -s, --selector  Function signature, e.g., `balanceOf(address)` or selector has
                  h to choose a specific function                       [string]
      --help      Show help                                            [boolean]

Examples:
  sevm abi 0x00000000000C2E074eC69A0dFb299  shows the ABI of the ENS registry co
  7BA6C7d2e1e                               ntract
  sevm decompile 0x00000000000C2E074eC69A0  decompiles the ENS registry contract
  dFb2997BA6C7d2e1e

[1] See https://docs.soliditylang.org/en/latest/metadata.html for more informati
on regarding Metadata generated by the Solidity compiler.
[2] See https://docs.soliditylang.org/en/latest/abi-spec.html#abi-json for more
information regarding the ABI specification.
[3] See https://docs.soliditylang.org/en/latest/yul.html for more information re
garding Yul.

At least one command must be specified

EVM Bytecode Decompiler Signature & Topics Hashes 4byte

Collection of Ethereum function and event signatures. It looks up in the signature and events database for matching hashes.

When a matching function or event is found in a Contract, it patches the function or event with the corresponding signature.

Detached Fork

This GitHub repo was originally a fork of https://github.com/MrLuit/evm. It served as a great starting point for this project. The fact that it is lightweight and written in TypeScript, make it ideal for embedding in other applications.

However, as we started to support and decompile newer contracts, we realize it was quite outdated. Besides not being able to process newer smart contracts, for some, the bytecode analysis algorithm did not terminate. That's the reason we forked that repo.

We did a major overhaul of the codebase, adding new features, refactoring the whole project and adding both testing and documentation. As we added changes, we realized it did not make sense to keep it a forked repo. Moreover, when sending new PRs, the default base repo is the upstream repo, which is not what we want in our case. This behavior is both error prone and annoying. That's why, as of Apr 17, 2023, this project is no longer a fork of MrLuit/evm.