# EVMole [![try it online](https://img.shields.io/badge/Try_It_Online-github.io-brightgreen)](https://cdump.github.io/evmole/) [![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) 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, and [state mutability](https://docs.soliditylang.org/en/latest/contracts.html#state-mutability), even for unverified contracts. ## Key Features - Multi-language support: Available as [JavaScript](#javascript), [Rust](#rust), and [Python](#python) libraries. - High accurancy 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. ## Usage ### JavaScript [API documentation](./javascript/#api) and [usage examples](./javascript#usage) (node, vite, webpack, parcel, esbuild) ```sh $ npm i evmole ``` ```javascript import { functionSelectors, functionArguments, functionStateMutability } from 'evmole' const code = '0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256' console.log(functionSelectors(code)); // [ '2125b65b', 'b69ef8a8' ] console.log(functionArguments(code, '2125b65b')); // 'uint32,address,uint224' console.log(functionStateMutability(code, '2125b65b')); // 'pure' ``` ### Rust Documentation is available on [docs.rs](https://docs.rs/evmole/latest/evmole/) ```rust let code = hex::decode("6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256").unwrap(); println!("{:x?} | {} | {:?}", evmole::function_selectors(&code, 0), evmole::function_arguments(&code, &[0x21, 0x25, 0xb6, 0x5b], 0), evmole::function_state_mutability(&code, &[0x21, 0x25, 0xb6, 0x5b], 0), ); // [[21, 25, b6, 5b], [b6, 9e, f8, a8]] | uint32,address,uint224 | Pure ``` ### Python [API documentation](./python/#api) ```sh $ pip install evmole --upgrade ``` ```python from evmole import function_selectors, function_arguments, function_state_mutability code = '0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256' print(function_selectors(code)) # ['2125b65b', 'b69ef8a8'] print(function_arguments(code, '2125b65b')) # uint32,address,uint224 print(function_state_mutability(code, '2125b65b')) # pure ``` ### Foundry Foundy's cast uses the Rust implementation of EVMole ```sh $ cast selectors $(cast code 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) 0x06fdde03 0x095ea7b3 address,uint256 0x18160ddd 0x23b872dd address,address,uint256 ... $ cast selectors --resolve $(cast code 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) 0x06fdde03 name() 0x095ea7b3 address,uint256 approve(address,uint256) 0x18160ddd totalSupply() 0x23b872dd address,address,uint256 transferFrom(address,address,uint256) ... ``` ## 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 whatsabi sevm evmhound heimdall smpl
largest1k
1000
addresses

24427
functions
FP addrs 1 🥈 0 🥇 0 🥇 75 18 95
FN addrs 0 🥇 0 🥇 0 🥇 40 111 9
FP funcs 192 🥈 0 🥇 0 🥇 720 600 749
FN funcs 0 🥇 0 🥇 0 🥇 191 147 12
Time 0.5s · 0.7s · 0.6s 3.2s 44s(*) 0.5s 341s(*) 1.8s
random50k
50000
addresses

1171102
functions
FP addrs 1 🥇 43 1 693 3 4136
FN addrs 9 🥇 11 10 2903 4708 77
FP funcs 3 🥇 51 3 10798 29 14652
FN funcs 10 🥇 12 11 3538 6098 96
Time 4.5s · 8.5s · 7.8s 54s 2458s(*) 6.1s 8576s(*) 46s
vyper
780
addresses

21244
functions
FP addrs 0 🥇 30 0 19 0 185
FN addrs 0 🥇 780 21 300 780 480
FP funcs 0 🥇 30 0 19 0 197
FN funcs 0 🥇 21244 336 8273 21244 12971
Time 0.4s · 0.6s · 0.4s 2.4s 43s(*) 0.4s 27s(*) 1.1s
### function arguments Errors - when at least 1 argument is incorrect: `(uint256,string)` ≠ `(uint256,bytes)`
Dataset evmole rs · js · py heimdall smpl
largest1k
24427
functions
Errors 14.0% 🥇
3410
31.1%
7593
58.3%
14242
Time 1.1s · 4.8s · 1.4s 342s(*) 0.7s
random50k
1171102
functions
Errors 4.5% 🥇
52662
19.4%
227612
54.9%
643213
Time 25s · 127 · 32 8544s(*) 9.5s
vyper
21244
functions
Errors 48.5% 🥇
10300
100.0%
21244
56.8%
12077
Time 0.8s · 3.0s · 1.0s 28s(*) 0.6s
### 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 whatsabi sevm heimdall smpl
largest1k
24427
functions
Errors 0.0% 🥇
0
68.1%
16623
2.1%
501
25.4%
6201
2.6%
643
Errors strict 18.7% 🥇
4558
79.3%
19370
59.0%
14417
54.9%
13403
60.9%
14864
Time 9.5s · 19s · 9.4s 3.8s 46s(*) 339s(*) 0.7s
random50k
1160861
functions
Errors 0.0% 🥇
35
30.2%
351060
0.3%
3370
11.6%
134195
2.2%
24961
Errors strict 6.7% 🥇
77945
58.1%
674922
55.7%
646831
27.7%
321494
57.7%
670318
Time 214s · 471s · 240s 85s 2331s(*) 8151s(*) 9.4s
vyper
21166
functions
Errors 0.5% 🥇
110
100.0%
21166
77.8%
16462
100.0%
21166
1.8%
390
Errors strict 4.2% 🥇
888
100.0%
21166
91.0%
19253
100.0%
21166
59.6%
12610
Time 10s · 15s · 10s 2.4s 41s(*) 28s(*) 0.6s
See [benchmark/README.md](./benchmark/) for the methodology and commands to reproduce these results versions: evmole v0.5.1; whatsabi v0.14.1; sevm v0.7.2; evm-hound-rs v0.1.4; heimdall-rs v0.8.4 (*): sevm and heimdall-rs are full decompilers, not limited to extracting function selectors ## How it works Short: Executes code with a custom EVM and traces CALLDATA usage. Long: TODO ## License MIT