Evm
A Symbolic Ethereum Virtual Machine (EVM) bytecode interpreter, parser and decompiler, along with several other utils for programmatically extracting information from EVM bytecode.
Install / Use
/learn @acuarica/EvmREADME
Symbolic EVM Bytecode Decompiler

A Symbolic Ethereum Virtual Machine (EVM) interpreter and decompiler, along with several other utils for programmatically extracting information from bytecode.
[!NOTE] Forked from MrLuit/evm. For more info, see Detached Fork.
Features
:construction: Under heavy development. Feel free to open an issue if something is not right. :construction:
- Lightweight with no dependencies, ~65 kB minified ~17 kB minified & brotlied
- Embedded functions and events signature database <small style="background: #f000b8; padding: 0.2em; border-radius: 3px">optional</small>
- Convert bytecode to opcodes
- Extract events or functions information from bytecode
- Extract the IPFS or swarm hash (when present) from bytecode using
cbor-js - 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
Browser
<script src="https://cdn.jsdelivr.net/npm/sevm@0.6/dist/sevm.js"></script>
<!-- tabs:end -->
or if you're interested only in the CLI Tool, install globally in your system
npm install --global sevm
sevm supports both ESM import and Node's CommonJS require.
Also it can be used in browsers, where all classes and functions can be found under the sevm global object.
ESM
import { Contract } from 'sevm';
// 00 opcode is STOP https://www.evm.codes/#00?fork=shanghai
const contract = new Contract('0x00');
console.log(contract.solidify());
CJS
const { Contract } = require('sevm');
// 00 opcode is STOP https://www.evm.codes/#00?fork=shanghai
const contract = new Contract('0x00');
console.log(contract.solidify());
script tag
<script src="https://cdn.jsdelivr.net/npm/sevm@0.6/dist/sevm.js"></script>
<script>
console.log('sevm exported symbols', sevm);
// 00 opcode is STOP https://www.evm.codes/#00?fork=shanghai
const contract = new sevm.Contract('0x00');
document.getElementById('code').innerHTML = contract.solidify();
</script>
<!-- tabs:end -->
API 
Main Methods and Properties
bytecode- Get raw bytecode (not really useful; same as input)metadata- Get IPFS or Swarm hash (if present) for contract metadataopcodes- Returns opcodes reachable within bytecodegetFunctions()- Parse functions from their signatures in bytecodegetEvents()- Parse events from their signatures in bytecodesolidify()- Decompile bytecode into readable Solidity-like pseudocodeisERC(ercid)- Detect whether contract is ERC id compliant
Usage
These examples use the import syntax and ethers.js is used to fetch bytecode from public EVM-based networks.
Decode Bytecode into Opcodes
import { JsonRpcProvider } from 'ethers';
import { Contract } from 'sevm';
const provider = new JsonRpcProvider('https://cloudflare-eth.com/');
// CryptoKitties Contract
// https://etherscan.io/address/0x06012c8cf97BEaD5deAe237070F9587f8E7A266d#code
const bytecode = await provider.getCode('0x06012c8cf97BEaD5deAe237070F9587f8E7A266d');
const contract = new Contract(bytecode);
const opcodes = contract.opcodes();
console.log(opcodes.map(opcode => opcode.format()));
Decompile a Contract
import { JsonRpcProvider } from 'ethers';
import { Contract } from 'sevm';
import 'sevm/4bytedb';
const provider = new JsonRpcProvider('https://cloudflare-eth.com/');
// WETH Contract
// https://etherscan.io/address/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
const bytecode = await provider.getCode('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2');
const contract = new Contract(bytecode).patchdb(); // Lookup for 4byte matches
console.log(contract.solidify()); // Decompile bytecode to Solidity
You can use the contract.yul() method to decompile the bytecode into Yul-like format.
Detect Functions, Events and ERC compliance
import { JsonRpcProvider } from 'ethers';
import { Contract } from 'sevm';
import 'sevm/4bytedb';
const provider = new JsonRpcProvider('https://cloudflare-eth.com/');
// CryptoKitties Contract
// https://etherscan.io/address/0x06012c8cf97BEaD5deAe237070F9587f8E7A266d#code
const bytecode = await provider.getCode('0x06012c8cf97BEaD5deAe237070F9587f8E7A266d');
const contract = new Contract(bytecode).patchdb();
console.log('functions', contract.getFunctions());
console.log('events', contract.getEvents());
console.log('isERC 165', contract.isERC('ERC165')); // Detect whether contract is ERC165-compliant
Extract Contract Metadata
import { JsonRpcProvider } from 'ethers';
import { Contract } from 'sevm';
// USDC Token Proxy on Avalanche Testnet
// https://testnet.snowtrace.io/address/0x5425890298aed601595a70AB815c96711a31Bc65#code
const provider = new JsonRpcProvider('https://api.avax-test.network/ext/bc/C/rpc');
const bytecode = await provider.getCode('0x5425890298aed601595a70AB815c96711a31Bc65');
const contract = new Contract(bytecode);
console.log(contract.metadata);
Advanced Usage
Hooks
import { EVM, London } from 'sevm';
// contract Test {
// event Deposit(uint256);
// fallback () external payable {
// emit Deposit(tx.gasprice);
// }
// }
const bytecode = '608060408190524581527f4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e3842690602090a16040805145815290517f4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e384269181900360200190a1604080513a815290517f4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e384269181900360200190a100';
const evm = new EVM(bytecode, new class extends London {
/** @override */
GASPRICE = (/** @type {import('sevm').Operand} */ state) => {
super.GASPRICE(state);
console.log('top', state.stack.top);
};
}());
evm.start();
Advanced Hooks
A contract might embed another contract it creates and deploys. Using hooks you can extract the embedded contract.
import { Contract, type Opcode, Shanghai, type State } from 'sevm';
import type { DataCopy, Create } from 'sevm/ast';
import 'sevm/4bytedb';
// contract Token {
// event Deposit(uint256 value);
// fallback() external payable {
// emit Deposit(3);
// }
// }
// contract Test {
// fallback() external payable {
// new Token();
// }
// }
const bytecode = '6080604052604051600e90602d565b604051809103906000f0801580156029573d6000803e3d6000fd5b5050005b60918061003a8339019056fe6080604052348015600f57600080fd5b50607480601d6000396000f3fe60806040527f4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e3842660036040518082815260200191505060405180910390a100fea2646970667358221220f03e9c56a5b70c1ba8fadf7d234cbca48d388951bfc7d402f0c92e4cb2afcd9f64736f6c63430007060033a264697066735822122053e5ffa19b83ac364f3adf6836d3758c98ae850b0fc9f5059124bf85d12c8d7264736f6c63430007060033';
let constructorContract: Contract, tokenContract: Contract;
const testContract = new Contract(bytecode, new class extends Shanghai {
override CREATE = (state: State) => {
super.CREATE(state);
const bytecode = (state.stack.top as Create).bytecode!;
constructorContract = new Contract(bytecode, new class
