3 releases

0.3.3 Feb 26, 2024
0.3.2 Jan 20, 2024
0.3.1 Dec 24, 2023

#759 in Magic Beans

Download history 43/week @ 2023-12-25 123/week @ 2024-01-01 492/week @ 2024-01-08 777/week @ 2024-01-15 806/week @ 2024-01-22 872/week @ 2024-01-29 710/week @ 2024-02-05 952/week @ 2024-02-12 505/week @ 2024-02-19 943/week @ 2024-02-26 819/week @ 2024-03-04 869/week @ 2024-03-11 701/week @ 2024-03-18 582/week @ 2024-03-25 930/week @ 2024-04-01 704/week @ 2024-04-08

3,035 downloads per month

MIT license

51KB
1K SLoC

EVMole

npm Crates.io PyPI license

This library extracts function selectors and arguments from Ethereum Virtual Machine (EVM) bytecode, even for unverified contracts.

  • JavaScript, Rust and Python implementations
  • Clean code with zero external dependencies (py & js)
  • Faster and more accurate than other existing tools
  • Tested on Solidity and Vyper compiled contracts

Try it online

Usage

JavaScript

$ npm i evmole
import {functionArguments, functionSelectors} from 'evmole'
// Also supported: const e = require('evmole'); e.functionSelectors();

const code = '0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256'
console.log( functionSelectors(code) )
// Output(list): [ '2125b65b', 'b69ef8a8' ]

console.log( functionArguments(code, '2125b65b') )
// Output(str): 'uint32,address,uint224'

Rust

Documentation available on docs.rs

let code = hex::decode("6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256").unwrap();

println!("{:x?}", evmole::function_selectors(&code, 0));
// Output(Vec<[u8;4]>): [[21, 25, b6, 5b], [b6, 9e, f8, a8]]

println!("{}", evmole::function_arguments(&code, &[0x21, 0x25, 0xb6, 0x5b], 0));
// Output(String): uint32,address,uint224

Python

$ pip install evmole --upgrade
from evmole import function_arguments, function_selectors

code = '0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256'
print( function_selectors(code) )
# Output(list): ['2125b65b', 'b69ef8a8']

print( function_arguments(code, '2125b65b') )
# Output(str): 'uint32,address,uint224'

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)
...

See examples for more

Benchmark

function selectors

FP/FN - False Positive/False Negative errors; smaller is better

Dataset evmole rs · js · py whatsabi evm-hound-rs heimdall-rs simple
largest1k
1000
contracts

24427
functions
FP contracts 1 🥈 0 🥇 75 18 95
FN contracts 0 🥇 8 40 102 9
FP functions 192 🥈 0 🥇 720 600 749
FN functions 0 🥇 8 🥈 191 113 12
Time 0.7s · 1.5s · 2.0s 3.0s 0.7s 727.2s 1.9s
random50k
50000
contracts

1171102
functions
FP contracts 1 🥇 43 693 waiting fixes 4136
FN contracts 9 🥇 31 2903 77
FP functions 3 🥇 51 10798 14652
FN functions 10 🥇 32 3538 96
Time 9.8s · 19.6s · 36.4s 52.3s 11.5s 46.3s
vyper
780
contracts

21244
functions
FP contracts 0 🥇 30 19 0 185
FN contracts 0 🥇 780 300 780 480
FP functions 0 🥇 30 19 0 197
FN functions 0 🥇 21244 8273 21244 12971
Time 0.6s · 0.9s · 1.4s 2.3s 0.6s 17.0s 1.2s

function arguments

Errors - when at least 1 argument is incorrect: (uint256,string) != (uint256,bytes); smaller is better

Dataset evmole rs · js · py heimdall-rs simple
largest1k
1000
contracts

24427
functions
Errors 15.0%, 3652 🥇 42.7%, 10438 58.3%, 14242
Time 1.1s · 7.5s · 15.7s 731.4s 0.8s
random50k
50000
contracts

1171102
functions
Errors 5.1%, 59484 🥇 waiting fixes 54.9%, 643213
Time 22.6s · 247.0s · 584.7s 9.5s
vyper
780
contracts

21244
functions
Errors 50.9%, 10805 🥇 100.0%, 21244 56.8%, 12077
Time 0.9s · 7.3s · 13.9s 16.8s 0.7s

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

versions: evmole v0.3.3; whatsabi v0.11.0; evm-hound-rs v0.1.4; heimdall-rs v0.7.3

How it works

Short: Executes code with a custom EVM and traces CALLDATA usage.

Long: TODO

License

MIT

Dependencies

~445KB