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.
🚧 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 using your package manager or Browser's script
tag
yarn add sevm
npm install sevm
or to install globally in your system
npm install --global sevm
<script src="https://cdn.jsdelivr.net/gh/acuarica/evm@f88b20a/lib/EVM.js"></script>
bytecode
- Get raw bytecode (not really useful; same as input)metadata
- Get IPFS or Swarm hash (if present) for contract metadataevm.opcodes
- Returns opcodes including pc and pushData (if included)evm.jumpdests
- Get map of program counters from JUMPDEST opcodesgetFunctions()
- Parse functions from their signatures in bytecodegetEvents()
- Parse events from their signatures in bytecodecontainsOpcode(opcode)
- Check whether an opcode exists and is reachable within bytecodedecompile()
- Decompile bytecode into readable Solidity-like pseudocodeisERC165()
- Detect whether contract is ERC165-compliant
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 */
});
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 */
});
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 */
});
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 */
});
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 */
});
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 */
}
);
$ 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
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.
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.