Skip to content
/ evmole Public

Extracts function selectors, arguments and state mutability from EVM bytecode, even for unverified contracts

License

Notifications You must be signed in to change notification settings

cdump/evmole

Repository files navigation

EVMole

try it online npm Crates.io PyPI

EVMole is a powerful library that extracts information from Ethereum Virtual Machine (EVM) bytecode, including function selectors, arguments, and state mutability, even for unverified contracts.

Key Features

  • Multi-language support: Available as JavaScript, Rust, and Python libraries.
  • High accurancy 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.

Usage

JavaScript

API documentation and usage examples (node, vite, webpack, parcel, esbuild)

$ npm i evmole
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

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

$ pip install evmole --upgrade
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

$ 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 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.4s · 0.8s · 0.6s 2.9s 38s(*) 0.5s 341s(*) 1.8s
random50k
50000
addresses

1171102
functions
FP addrs 1 🥇 43 1 693 3 4136
FN addrs 9 🥇 11 36 2903 4708 77
FP funcs 3 🥇 51 3 10798 29 14652
FN funcs 10 🥇 12 587 3538 6098 96
Time 4.5s · 12s · 10s 49s 1427s(*) 5.8s 8576s(*) 49s
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.7s · 0.5s 2.2s 60s(*) 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% 🥇
3417
31.1%
7593
58.3%
14242
Time 1.0s · 8.3s · 3.5s 342s(*) 0.7s
random50k
1171102
functions
Errors 4.5% 🥇
52777
19.4%
227612
54.9%
643213
Time 23s · 263s · 104s 8544s(*) 9.7s
vyper
21244
functions
Errors 49.6% 🥇
10544
100.0%
21244
56.8%
12077
Time 0.7s · 5.2s · 2.2s 28s(*) 0.5s

function state mutability

Errors - Results are not equal (treating view and pure as equivalent to nonpayable)

Errors strict - Results are strictly unequal (nonpayableview). 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 19.3% 🥇
4718
79.3%
19370
59.0%
14417
54.9%
13403
60.9%
14864
Time 7.9s · 17s · 10s 3.7s 37s(*) 339s(*) 0.7s
random50k
1160861
functions
Errors 0.0% 🥇
35
30.2%
351060
0.3%
3887
11.6%
134195
2.2%
24961
Errors strict 6.8% 🥇
78676
58.1%
674922
55.7%
647070
27.7%
321494
57.7%
670318
Time 226s · 523s · 309s 80s 1709s(*) 8151s(*) 9.4s
vyper
21166
functions
Errors 0.5% 🥇
110
100.0%
21166
77.8%
16462
100.0%
21166
1.8%
390
Errors strict 11.4% 🥇
2410
100.0%
21166
91.0%
19253
100.0%
21166
59.6%
12610
Time 3.7s · 8.7s · 5.1s 2.2s 59s(*) 28s(*) 0.6s

See benchmark/README.md for the methodology and commands to reproduce these results

versions: evmole v0.4.1; whatsabi v0.14.1; sevm v0.6.19; 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