EVMole is a powerful library that extracts information from Ethereum Virtual Machine (EVM) bytecode, including function selectors, arguments, state mutability, persistent and transient storage layouts, and CBOR metadata, even for unverified contracts.
- Multi-language support: Available as JavaScript, Rust, Python, and Go libraries.
- High accuracy and performance: Outperforms existing tools.
- Broad compatibility: Tested with both Solidity and Vyper compiled contracts.
- Lightweight: Clean codebase with minimal external dependencies.
- Unverified contract analysis: Extracts information even from unverified bytecode.
- Selector dispatch classification: Distinguishes normal ABI dispatch from selectors handled by fallback logic.
- CBOR metadata: Extracts string-keyed values from a terminal, length-suffixed CBOR map without assuming a particular compiler.
API documentation and usage examples (Node.js, Vite, webpack, Parcel, esbuild)
npm i evmoleimport{contractInfo}from'evmole'constcode='0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256'console.log(contractInfo(code,{selectors:true,arguments:true,stateMutability:true}))// {// functions: [// {// selector: '2125b65b',// bytecodeOffset: 52,// dispatch: 'abi',// arguments: 'uint32,address,uint224',// stateMutability: 'pure'// },// ...Documentation is available on docs.rs
let code = hex::decode("6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256").unwrap();println!("{:?}", evmole::contract_info(
evmole::ContractInfoArgs::new(&code).with_selectors().with_arguments().with_state_mutability()));// Contract {// functions: Some([// Function {// selector: [33, 37, 182, 91],// bytecode_offset: 52,// dispatch: Abi,// arguments: Some([Uint(32), Address, Uint(224)]),// state_mutability: Some(Pure)// },// ...pip install evmole --upgradefromevmoleimportcontract_infocode='0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256'print( contract_info(code, selectors=True, arguments=True, state_mutability=True) )
# Contract(# functions=[# Function(# selector=2125b65b,# bytecode_offset=52,# dispatch="abi",# arguments=uint32,address,uint224,# state_mutability=pure),# ...go get github.com/cdump/evmole/gopackage main
import (
"context""encoding/hex""fmt""github.com/cdump/evmole/go"
)
funcmain() {
code, _:=hex.DecodeString("6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256")
info, _:=evmole.ContractInfo(context.Background(), code, evmole.Options{
Selectors: true,
Arguments: true,
StateMutability: true,
})
for_, fn:=rangeinfo.Functions {
fmt.Printf("%s: %s @ %d\n", fn.Selector, *fn.Arguments, fn.BytecodeOffset)
}
// 2125b65b: uint32,address,uint224 @ 52// b69ef8a8: @ 68
}Foundry's cast uses the Rust implementation of EVMole
$ cast selectors $(cast code 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)
0x06fdde03 view
0x095ea7b3 address,uint256 nonpayable
0x18160ddd view
0x23b872dd address,address,uint256 nonpayable
...
$ cast selectors --resolve $(cast code 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)
0x06fdde03 view name()
0x095ea7b3 address,uint256 nonpayable approve(address,uint256)
0x18160ddd view totalSupply()
0x23b872dd address,address,uint256 nonpayable transferFrom(address,address,uint256)
...For application code, use one of the language bindings above. For agent-driven bytecode analysis, choose one integration.
Use for one-off analysis and scripts:
npx -y evmole analyze --bytecode 0x...Install routing and interpretation guidance for supported agents:
npx skills add cdump/evmole --skill evm-bytecode-analysis -gExpose EVMole as a typed local tool:
npx -y evmole-mcpAll integrations expect deployed/runtime bytecode and run locally without sending bytecode to an EVMole-operated service. See the agent integration guide for setup, schemas, limitations, and privacy details.
FP/FN - False Positive/False Negative errors; smaller is better
| Dataset | evmolers · js · py · go | whatsabi | sevm | evmhound | heimdall | |
| coverage2k solidity 2000 addresses 45650 functions | FP addrs | 0 🥇 | 4 | 1 | 56 | 3 |
| FN addrs | 0 🥇 | 11 | 0 🥇 | 224 | 166 | |
| FP funcs | 0 🥇 | 10 | 10 | 616 | 27 | |
| FN funcs | 0 🥇 | 145 | 0 🥇 | 821 | 342 | |
| Time | 24ms · 0.3s · 31ms · 0.1s | 2.0s | 28s(*) | 86ms | 111s(*) | |
| random10k solidity 10000 addresses 223316 functions | FP addrs | 0 🥇 | 19 | 16 | 224 | 7 |
| FN addrs | 0 🥇 | 44 | 1 | 838 | 819 | |
| FP funcs | 0 🥇 | 65 | 112 | 3157 | 260 | |
| FN funcs | 0 🥇 | 173 | 7 | 4112 | 1021 | |
| Time | 0.1s · 0.8s · 0.2s · 0.8s | 7.1s | 80s(*) | 0.4s | 533s(*) | |
| coverage1k vyper 1000 addresses 38759 functions | FP addrs | 0 🥇 | 560 | 0 🥇 | 2 | 0 🥇 |
| FN addrs | 0 🥇 | 998 | 788 | 525 | 998 | |
| FP funcs | 0 🥇 | 560 | 0 🥇 | 5 | 0 🥇 | |
| FN funcs | 0 🥇 | 38759 | 34077 | 16218 | 38759 | |
| Time | 91ms · 0.4s · 0.1s · 0.3s | 1.9s | 5.4s(*) | 67ms | 12s(*) | |
Errors - when at least 1 inferred argument is incorrect: (uint256,string) ≠ (uint256,bytes)
| Dataset | evmolers · js · py · go | heimdall | |
| coverage2k solidity 45650 functions | Errors | 8.5% 🥇 3883 | 23.3% 10643 |
| Time | 0.8s · 1.7s · 1.1s · 2.1s | 111s(*) | |
| random10k solidity 223316 functions | Errors | 6.8% 🥇 15296 | 21.4% 47878 |
| Time | 3.5s · 6.9s · 4.2s · 9.7s | 511s(*) | |
| coverage1k vyper 38759 functions | Errors | 45.4% 🥇 17590 | 100.0% 38759 |
| Time | 0.5s · 1.1s · 0.6s · 1.4s | 12s(*) | |
Errors - Results are not equal (treating view and pure as equivalent to nonpayable)
Errors strict - Results are strictly unequal (nonpayable ≠ view). Some ABIs mark pure/view functions as nonpayable, so not all strict errors indicate real issues.
| Dataset | evmolers · js · py · go | whatsabi | sevm | heimdall | |
| coverage2k solidity 45647 functions | Errors | 0.0% 🥇 18 | 52.2% 23810 | 11.2% 5133 | 19.6% 8951 |
| Errors strict | 9.0% 🥇 4107 | 70.9% 32346 | 62.3% 28429 | 41.3% 18835 | |
| Time | 10s · 11s · 9.7s · 20s | 3.1s | 29s(*) | 112s(*) | |
| random10k solidity 223273 functions | Errors | 0.0% 🥇 39 | 48.8% 108928 | 9.3% 20713 | 18.6% 41507 |
| Errors strict | 8.9% 🥇 19940 | 69.9% 156081 | 60.9% 136069 | 40.1% 89519 | |
| Time | 48s · 50s · 46s · 88s | 12s | 81s(*) | 512s(*) | |
| coverage1k vyper 38278 functions | Errors | 0.1% 🥇 34 | 100.0% 38278 | 96.2% 36814 | 100.0% 38278 |
| Errors strict | 1.2% 🥇 441 | 100.0% 38278 | 98.4% 37650 | 100.0% 38278 | |
| Time | 45s · 39s · 44s · 89s | 2.0s | 5.5s(*) | 12s(*) | |
False Negatives - Valid blocks possibly incorrectly marked unreachable by CFG analysis. Lower count usually indicates better precision.
| evmolers · js · py · go | ethersolve | evm-cfg | sevm | heimdall-rs | evm-cfg-builder | |
| Basic Blocks | 92.8% 🥇 483212 | 52.5% 273518 | 58.6% 305248 | 37.3% 194368 | 32.6% 169980 | 14.5% 75383 |
| False Negatives | 7.2% 🥇 37496 | 47.5% 247190 | 41.4% 215460 | 62.7% 326340 | 67.4% 350728 | 85.5% 445325 |
| Time | 14s · 26s · 12s · 55s | 888s | 36s | 9.8s | 20s | 359s |
dataset flow-challenge500, 500 contracts, 520,708 blocks
See benchmark/README.md for the methodology and commands to reproduce these results
versions: evmole v0.9.3; whatsabi v0.25.0; sevm v0.7.4; evm-hound-rs v0.1.4; heimdall-rs v0.9.3
(*): sevm and heimdall-rs are full decompilers, not limited to extracting function selectors
EVMole uses symbolic execution with a custom EVM implementation to trace how CALLDATA flows through the bytecode:
This approach is more accurate than static pattern matching because it follows the actual execution paths the EVM would take, correctly handling complex dispatchers, proxy patterns, and compiler-specific optimizations from both Solidity and Vyper.
- EVMole: function selectors and arguments from bytecode - BlockSplit 2024
- EVMole: function selectors and arguments from bytecode - EthCC 2024
- Reconstructing Control Flow Graphs from EVM Bytecode - ETHTaipei 2025
- Reconstructing Control Flow Graphs from EVM Bytecode: Faster, Better, Stronger - EthCC 2025
MIT