![EVMole](./.github/logo.svg) [![try it online](https://img.shields.io/badge/Try_It_Online-evmole.xyz-brightgreen)](https://evmole.xyz/) [![npm](https://img.shields.io/npm/v/evmole)](https://www.npmjs.com/package/evmole) [![Crates.io](https://img.shields.io/crates/v/evmole?color=e9b44f)](https://crates.io/crates/evmole) [![PyPI](https://img.shields.io/pypi/v/evmole?color=006dad)](https://pypi.org/project/evmole) [![Go](https://img.shields.io/badge/go-pkg-00ADD8)](https://pkg.go.dev/github.com/cdump/evmole/go) EVMole is a powerful library that extracts information from Ethereum Virtual Machine (EVM) bytecode, including [function selectors](https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector), arguments, [state mutability](https://docs.soliditylang.org/en/latest/contracts.html#state-mutability), persistent and transient storage layouts, and CBOR metadata, even for unverified contracts. ## Key Features - Multi-language support: Available as [JavaScript](#javascript), [Rust](#rust), [Python](#python), and [Go](#go) libraries. - High accuracy and performance: [Outperforms](#benchmark) 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. ## Usage ### JavaScript [API documentation](./javascript/#api) and [usage examples](./javascript/#usage) (Node.js, Vite, webpack, Parcel, esbuild) ```sh npm i evmole ``` ```javascript import { contractInfo } from 'evmole' const code = '0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256' console.log( contractInfo(code, {selectors:true, arguments:true, stateMutability:true}) ) // { // functions: [ // { // selector: '2125b65b', // bytecodeOffset: 52, // dispatch: 'abi', // arguments: 'uint32,address,uint224', // stateMutability: 'pure' // }, // ... ``` ### Rust Documentation is available on [docs.rs](https://docs.rs/evmole/latest/evmole/) ```rust 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) // }, // ... ``` ### Python [API documentation](./python/#api) ```sh pip install evmole --upgrade ``` ```python from evmole import contract_info code = '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 [API documentation](./go/#api-reference) ```sh go get github.com/cdump/evmole/go ``` ```go package main import ( "context" "encoding/hex" "fmt" "github.com/cdump/evmole/go" ) func main() { code, _ := hex.DecodeString("6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256") info, _ := evmole.ContractInfo(context.Background(), code, evmole.Options{ Selectors: true, Arguments: true, StateMutability: true, }) for _, fn := range info.Functions { fmt.Printf("%s: %s @ %d\n", fn.Selector, *fn.Arguments, fn.BytecodeOffset) } // 2125b65b: uint32,address,uint224 @ 52 // b69ef8a8: @ 68 } ``` ### Foundry Foundry's cast uses the Rust implementation of EVMole ```sh $ 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) ... ``` ### AI agents For application code, use one of the language bindings above. For agent-driven bytecode analysis, choose one integration. #### JSON CLI Use for one-off analysis and scripts: ```bash npx -y evmole analyze --bytecode 0x... ``` #### Portable skill Install routing and interpretation guidance for supported agents: ```bash npx skills add cdump/evmole --skill evm-bytecode-analysis -g ``` #### Local MCP server Expose EVMole as a typed local tool: ```bash npx -y evmole-mcp ``` All integrations expect deployed/runtime bytecode and run locally without sending bytecode to an EVMole-operated service. See the [agent integration guide](./agent/README.md) for setup, schemas, limitations, and privacy details. ## Benchmark ### function selectors FP/FN - [False Positive/False Negative](https://en.wikipedia.org/wiki/False_positives_and_false_negatives) errors; smaller is better
Dataset evmole rs · 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(*)
### function arguments Errors - when at least 1 inferred argument is incorrect: `(uint256,string)` ≠ `(uint256,bytes)`
Dataset evmole rs · 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(*)
### function state mutability 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 evmole rs · 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(*)
### Control Flow Graph False Negatives - Valid blocks possibly incorrectly marked unreachable by CFG analysis. Lower count usually indicates better precision.
evmole rs · 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 ### notes See [benchmark/README.md](./benchmark/) 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 ## How it works 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. ## Talks - [EVMole: function selectors and arguments from bytecode](https://www.youtube.com/watch?v=l0udabGej54) - BlockSplit 2024 - [EVMole: function selectors and arguments from bytecode](https://ethcc.io/archives/evmole-function-selectors-and-arguments-from-bytecode) - EthCC 2024 - [Reconstructing Control Flow Graphs from EVM Bytecode](https://www.youtube.com/watch?v=1Xd6PhEHMHM) - ETHTaipei 2025 - [Reconstructing Control Flow Graphs from EVM Bytecode: Faster, Better, Stronger](https://www.youtube.com/watch?v=UL6-3EZbv3E) - EthCC 2025 ## License MIT