evmole 0.4.1__cp39-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
evmole/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ from .evmole import *
2
+
3
+ __doc__ = evmole.__doc__
4
+ if hasattr(evmole, "__all__"):
5
+ __all__ = evmole.__all__
evmole/__init__.pyi ADDED
@@ -0,0 +1,42 @@
1
+ from typing import List, Union
2
+
3
+ def function_selectors(code: Union[bytes, str], gas_limit: int = 500000) -> List[str]:
4
+ """
5
+ Extracts function selectors from the given bytecode.
6
+
7
+ Args:
8
+ code (Union[bytes, str]): Runtime bytecode as a hex string or bytes.
9
+ gas_limit (int, optional): Maximum gas to use. Defaults to 500000.
10
+
11
+ Returns:
12
+ List[str]: List of selectors encoded as hex strings.
13
+ """
14
+ ...
15
+
16
+ def function_arguments(code: Union[bytes, str], selector: Union[bytes, str], gas_limit: int = 50000) -> str:
17
+ """
18
+ Extracts function arguments for a given selector from the bytecode.
19
+
20
+ Args:
21
+ code (Union[bytes, str]): Runtime bytecode as a hex string or bytes.
22
+ selector (Union[bytes, str]): Function selector as a hex string or bytes.
23
+ gas_limit (int, optional): Maximum gas to use. Defaults to 50000.
24
+
25
+ Returns:
26
+ str: Arguments of the function.
27
+ """
28
+ ...
29
+
30
+ def function_state_mutability(code: Union[bytes, str], selector: Union[bytes, str], gas_limit: int = 500000) -> str:
31
+ """
32
+ Extracts function state mutability for a given selector from the bytecode.
33
+
34
+ Args:
35
+ code (Union[bytes, str]): Runtime bytecode as a hex string or bytes.
36
+ selector (Union[bytes, str]): Function selector as a hex string or bytes.
37
+ gas_limit (int, optional): Maximum gas to use. Defaults to 500000.
38
+
39
+ Returns:
40
+ str: "payable" | "nonpayable" | "view" | "pure"
41
+ """
42
+ ...
Binary file
evmole/py.typed ADDED
File without changes
@@ -0,0 +1,414 @@
1
+ Metadata-Version: 2.3
2
+ Name: evmole
3
+ Version: 0.4.1
4
+ Summary: Extracts function selectors and arguments from EVM bytecode
5
+ Author: Maxim Andreev <andreevmaxim@gmail.com>
6
+ Author-email: Maxim Andreev <andreevmaxim@gmail.com>
7
+ License: MIT
8
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
9
+ Project-URL: Source Code, https://github.com/cdump/evmole
10
+
11
+ # EVMole
12
+
13
+ [![try it online](https://img.shields.io/badge/Try_It_Online-github.io-brightgreen)](https://cdump.github.io/evmole/)
14
+ [![npm](https://img.shields.io/npm/v/evmole)](https://www.npmjs.com/package/evmole)
15
+ [![Crates.io](https://img.shields.io/crates/v/evmole?color=e9b44f)](https://crates.io/crates/evmole)
16
+ [![PyPI](https://img.shields.io/pypi/v/evmole?color=006dad)](https://pypi.org/project/evmole)
17
+
18
+ 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.
19
+
20
+
21
+ ## Key Features
22
+
23
+ - Multi-language support: Available as [JavaScript](#javascript), [Rust](#rust), and [Python](#python) libraries.
24
+ - High accurancy and performance: [Outperforms](#benchmark) existing tools.
25
+ - Broad compatibility: Tested with both Solidity and Vyper compiled contracts.
26
+ - Lightweight: Clean codebase with minimal external dependencies.
27
+ - Unverified contract analysis: Extracts information even from unverified bytecode.
28
+
29
+
30
+ ## Usage
31
+ ### JavaScript
32
+ [API documentation](./javascript/#api) and [usage examples](./javascript#usage) (node, vite, webpack, parcel, esbuild)
33
+ ```sh
34
+ $ npm i evmole
35
+ ```
36
+ ```javascript
37
+ import { functionSelectors, functionArguments, functionStateMutability } from 'evmole'
38
+
39
+ const code = '0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256'
40
+
41
+ console.log(functionSelectors(code)); // [ '2125b65b', 'b69ef8a8' ]
42
+ console.log(functionArguments(code, '2125b65b')); // 'uint32,address,uint224'
43
+ console.log(functionStateMutability(code, '2125b65b')); // 'pure'
44
+ ```
45
+
46
+ ### Rust
47
+ Documentation is available on [docs.rs](https://docs.rs/evmole/latest/evmole/)
48
+ ```rust
49
+ let code = hex::decode("6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256").unwrap();
50
+
51
+ println!("{:x?} | {} | {}",
52
+ evmole::function_selectors(&code, 0),
53
+ evmole::function_arguments(&code, &[0x21, 0x25, 0xb6, 0x5b], 0),
54
+ evmole::function_state_mutability(&code, &[0x21, 0x25, 0xb6, 0x5b], 0),
55
+ );
56
+ // [[21, 25, b6, 5b], [b6, 9e, f8, a8]] | uint32,address,uint224 | pure
57
+ ```
58
+
59
+ ### Python
60
+ [API documentation](./python/#api)
61
+ ```sh
62
+ $ pip install evmole --upgrade
63
+ ```
64
+ ```python
65
+ from evmole import function_selectors, function_arguments, function_state_mutability
66
+
67
+ code = '0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256'
68
+
69
+ print(function_selectors(code)) # ['2125b65b', 'b69ef8a8']
70
+ print(function_arguments(code, '2125b65b')) # uint32,address,uint224
71
+ print(function_state_mutability(code, '2125b65b')) # pure
72
+ ```
73
+
74
+ ### Foundry
75
+ <a href="https://getfoundry.sh/">Foundy's cast</a> uses the Rust implementation of EVMole
76
+ ```sh
77
+
78
+ $ cast selectors $(cast code 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)
79
+ 0x06fdde03
80
+ 0x095ea7b3 address,uint256
81
+ 0x18160ddd
82
+ 0x23b872dd address,address,uint256
83
+ ...
84
+
85
+ $ cast selectors --resolve $(cast code 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)
86
+ 0x06fdde03 name()
87
+ 0x095ea7b3 address,uint256 approve(address,uint256)
88
+ 0x18160ddd totalSupply()
89
+ 0x23b872dd address,address,uint256 transferFrom(address,address,uint256)
90
+ ...
91
+ ```
92
+
93
+ ## Benchmark
94
+
95
+ ### function selectors
96
+ <i>FP/FN</i> - [False Positive/False Negative](https://en.wikipedia.org/wiki/False_positives_and_false_negatives) errors; <b>smaller is better</b>
97
+
98
+ <table>
99
+ <tr>
100
+ <td>Dataset</td>
101
+ <td></td>
102
+ <td><b><i>evmole</i><b> <a href="benchmark/providers/evmole-rs/"><b><i>rs</i></b></a> · <a href="benchmark/providers/evmole-js/"><b><i>js</i></b></a> · <a href="benchmark/providers/evmole-py/"><b><i>py</i></b></a></td>
103
+ <td><a href="benchmark/providers/whatsabi/"><b><i>whatsabi</i></b></a></td>
104
+ <td><a href="benchmark/providers/sevm/"><b><i>sevm</i></b></a></td>
105
+ <td><a href="benchmark/providers/evm-hound-rs/"><b><i>evmhound</i></b></a></td>
106
+ <td><a href="benchmark/providers/heimdall-rs/"><b><i>heimdall</i></b></a></td>
107
+ <td><a href="benchmark/providers/simple/"><b><i>smpl</i></b></a></td>
108
+ </tr>
109
+ <tr>
110
+ <td rowspan="5"><b>largest1k</b><br><sub>1000<br>addresses<br><br>24427<br>functions</sub></td>
111
+ <td><i>FP <sub>addrs</sub></i></td>
112
+ <td>1 🥈</td>
113
+ <td>0 🥇</td>
114
+ <td>0 🥇</td>
115
+ <td>75</td>
116
+ <td>18</td>
117
+ <td>95</td>
118
+ </tr>
119
+ <tr>
120
+ <td><i>FN <sub>addrs</sub></i></td>
121
+ <td>0 🥇</td>
122
+ <td>0 🥇</td>
123
+ <td>0 🥇</td>
124
+ <td>40</td>
125
+ <td>111</td>
126
+ <td>9</td>
127
+ </tr>
128
+ <tr>
129
+ <td><i>FP <sub>funcs</sub></i></td>
130
+ <td>192 🥈</td>
131
+ <td>0 🥇</td>
132
+ <td>0 🥇</td>
133
+ <td>720</td>
134
+ <td>600</td>
135
+ <td>749</td>
136
+ </tr>
137
+ <tr>
138
+ <td><i>FN <sub>funcs</sub></i></td>
139
+ <td>0 🥇</td>
140
+ <td>0 🥇</td>
141
+ <td>0 🥇</td>
142
+ <td>191</td>
143
+ <td>147</td>
144
+ <td>12</td>
145
+ </tr>
146
+ <tr>
147
+ <td><i>Time</i></td>
148
+ <td>0.4s · 0.8s · 0.6s</td>
149
+ <td>2.9s</td>
150
+ <td>38s<sup>(*)</sup></td>
151
+ <td>0.5s</td>
152
+ <td>341s<sup>(*)</sup></td>
153
+ <td>1.8s</td>
154
+ </tr>
155
+ <tr><td colspan="8"></td></tr>
156
+ <tr>
157
+ <td rowspan="5"><b>random50k</b><br><sub>50000<br>addresses<br><br>1171102<br>functions</sub></td>
158
+ <td><i>FP <sub>addrs</sub></i></td>
159
+ <td>1 🥇</td>
160
+ <td>43</td>
161
+ <td>1</td>
162
+ <td>693</td>
163
+ <td>3</td>
164
+ <td>4136</td>
165
+ </tr>
166
+ <tr>
167
+ <td><i>FN <sub>addrs</sub></i></td>
168
+ <td>9 🥇</td>
169
+ <td>11</td>
170
+ <td>36</td>
171
+ <td>2903</td>
172
+ <td>4708</td>
173
+ <td>77</td>
174
+ </tr>
175
+ <tr>
176
+ <td><i>FP <sub>funcs</sub></i></td>
177
+ <td>3 🥇</td>
178
+ <td>51</td>
179
+ <td>3</td>
180
+ <td>10798</td>
181
+ <td>29</td>
182
+ <td>14652</td>
183
+ </tr>
184
+ <tr>
185
+ <td><i>FN <sub>funcs</sub></i></td>
186
+ <td>10 🥇</td>
187
+ <td>12</td>
188
+ <td>587</td>
189
+ <td>3538</td>
190
+ <td>6098</td>
191
+ <td>96</td>
192
+ </tr>
193
+ <tr>
194
+ <td><i>Time</i></td>
195
+ <td>4.5s · 12s · 10s</td>
196
+ <td>49s</td>
197
+ <td>1427s<sup>(*)</sup></td>
198
+ <td>5.8s</td>
199
+ <td>8576s<sup>(*)</sup></td>
200
+ <td>49s</td>
201
+ </tr>
202
+ <tr><td colspan="8"></td></tr>
203
+ <tr>
204
+ <td rowspan="5"><b>vyper</b><br><sub>780<br>addresses<br><br>21244<br>functions</sub></td>
205
+ <td><i>FP <sub>addrs</sub></i></td>
206
+ <td>0 🥇</td>
207
+ <td>30</td>
208
+ <td>0</td>
209
+ <td>19</td>
210
+ <td>0</td>
211
+ <td>185</td>
212
+ </tr>
213
+ <tr>
214
+ <td><i>FN <sub>addrs</sub></i></td>
215
+ <td>0 🥇</td>
216
+ <td>780</td>
217
+ <td>21</td>
218
+ <td>300</td>
219
+ <td>780</td>
220
+ <td>480</td>
221
+ </tr>
222
+ <tr>
223
+ <td><i>FP <sub>funcs</sub></i></td>
224
+ <td>0 🥇</td>
225
+ <td>30</td>
226
+ <td>0</td>
227
+ <td>19</td>
228
+ <td>0</td>
229
+ <td>197</td>
230
+ </tr>
231
+ <tr>
232
+ <td><i>FN <sub>funcs</sub></i></td>
233
+ <td>0 🥇</td>
234
+ <td>21244</td>
235
+ <td>336</td>
236
+ <td>8273</td>
237
+ <td>21244</td>
238
+ <td>12971</td>
239
+ </tr>
240
+ <tr>
241
+ <td><i>Time</i></td>
242
+ <td>0.4s · 0.7s · 0.5s</td>
243
+ <td>2.2s</td>
244
+ <td>60s<sup>(*)</sup></td>
245
+ <td>0.4s</td>
246
+ <td>27s<sup>(*)</sup></td>
247
+ <td>1.1s</td>
248
+ </tr>
249
+ </table>
250
+
251
+ ### function arguments
252
+ <i>Errors</i> - when at least 1 argument is incorrect: `(uint256,string)` ≠ `(uint256,bytes)`
253
+
254
+ <table>
255
+ <tr>
256
+ <td>Dataset</td>
257
+ <td></td>
258
+ <td><b><i>evmole</i><b> <a href="benchmark/providers/evmole-rs/"><b><i>rs</i></b></a> · <a href="benchmark/providers/evmole-js/"><b><i>js</i></b></a> · <a href="benchmark/providers/evmole-py/"><b><i>py</i></b></a></td>
259
+ <td><a href="benchmark/providers/heimdall-rs/"><b><i>heimdall</i></b></a></td>
260
+ <td><a href="benchmark/providers/simple/"><b><i>smpl</i></b></a></td>
261
+ </tr>
262
+ <tr>
263
+ <td rowspan="2"><b>largest1k</b><br><sub>24427<br>functions</sub></td>
264
+ <td><i>Errors</i></td>
265
+ <td>14.0% 🥇<br><sub>3417</sub></td>
266
+ <td>31.1%<br><sub>7593</sub></td>
267
+ <td>58.3%<br><sub>14242</sub></td>
268
+ </tr>
269
+ <tr>
270
+ <td><i>Time</i></td>
271
+ <td>1.0s · 8.3s · 3.5s</td>
272
+ <td>342s<sup>(*)</sup></td>
273
+ <td>0.7s</td>
274
+ </tr>
275
+ <tr><td colspan="5"></td></tr>
276
+ <tr>
277
+ <td rowspan="2"><b>random50k</b><br><sub>1171102<br>functions</sub></td>
278
+ <td><i>Errors</i></td>
279
+ <td>4.5% 🥇<br><sub>52777</sub></td>
280
+ <td>19.4%<br><sub>227612</sub></td>
281
+ <td>54.9%<br><sub>643213</sub></td>
282
+ </tr>
283
+ <tr>
284
+ <td><i>Time</i></td>
285
+ <td>23s · 263s · 104s</td>
286
+ <td>8544s<sup>(*)</sup></td>
287
+ <td>9.7s</td>
288
+ </tr>
289
+ <tr><td colspan="5"></td></tr>
290
+ <tr>
291
+ <td rowspan="2"><b>vyper</b><br><sub>21244<br>functions</sub></td>
292
+ <td><i>Errors</i></td>
293
+ <td>49.6% 🥇<br><sub>10544</sub></td>
294
+ <td>100.0%<br><sub>21244</sub></td>
295
+ <td>56.8%<br><sub>12077</sub></td>
296
+ </tr>
297
+ <tr>
298
+ <td><i>Time</i></td>
299
+ <td>0.7s · 5.2s · 2.2s</td>
300
+ <td>28s<sup>(*)</sup></td>
301
+ <td>0.5s</td>
302
+ </tr>
303
+ </table>
304
+
305
+ ### function state mutability
306
+
307
+ <i>Errors</i> - Results are not equal (treating `view` and `pure` as equivalent to `nonpayable`)
308
+
309
+ <i>Errors strict</i> - Results are strictly unequal (`nonpayable` ≠ `view`). Some ABIs mark `pure`/`view` functions as `nonpayable`, so not all strict errors indicate real issues.
310
+
311
+ <table>
312
+ <tr>
313
+ <td>Dataset</td>
314
+ <td></td>
315
+ <td><b><i>evmole</i><b> <a href="benchmark/providers/evmole-rs/"><b><i>rs</i></b></a> · <a href="benchmark/providers/evmole-js/"><b><i>js</i></b></a> · <a href="benchmark/providers/evmole-py/"><b><i>py</i></b></a></td>
316
+ <td><a href="benchmark/providers/whatsabi/"><b><i>whatsabi</i></b></a></td>
317
+ <td><a href="benchmark/providers/sevm/"><b><i>sevm</i></b></a></td>
318
+ <td><a href="benchmark/providers/heimdall-rs/"><b><i>heimdall</i></b></a></td>
319
+ <td><a href="benchmark/providers/simple/"><b><i>smpl</i></b></a></td>
320
+ </tr>
321
+ <tr>
322
+ <td rowspan="3"><b>largest1k</b><br><sub>24427<br>functions</sub></td>
323
+ <td><i>Errors</i></td>
324
+ <td>0.0% 🥇<br><sub>0</sub></td>
325
+ <td>68.1%<br><sub>16623</sub></td>
326
+ <td>2.1%<br><sub>501</sub></td>
327
+ <td>25.4%<br><sub>6201</sub></td>
328
+ <td>2.6%<br><sub>643</sub></td>
329
+ </tr>
330
+ <tr>
331
+ <td><i>Errors strict</i></td>
332
+ <td>19.3% 🥇<br><sub>4718</sub></td>
333
+ <td>79.3%<br><sub>19370</sub></td>
334
+ <td>59.0%<br><sub>14417</sub></td>
335
+ <td>54.9%<br><sub>13403</sub></td>
336
+ <td>60.9%<br><sub>14864</sub></td>
337
+ </tr>
338
+ <tr>
339
+ <td><i>Time</i></td>
340
+ <td>7.9s · 17s · 10s</td>
341
+ <td>3.7s</td>
342
+ <td>37s<sup>(*)</sup></td>
343
+ <td>339s<sup>(*)</sup></td>
344
+ <td>0.7s</td>
345
+ </tr>
346
+ <tr><td colspan="6"></td></tr>
347
+ <tr>
348
+ <td rowspan="3"><b>random50k</b><br><sub>1160861<br>functions</sub></td>
349
+ <td><i>Errors</i></td>
350
+ <td>0.0% 🥇<br><sub>35</sub></td>
351
+ <td>30.2%<br><sub>351060</sub></td>
352
+ <td>0.3%<br><sub>3887</sub></td>
353
+ <td>11.6%<br><sub>134195</sub></td>
354
+ <td>2.2%<br><sub>24961</sub></td>
355
+ </tr>
356
+ <tr>
357
+ <td><i>Errors strict</i></td>
358
+ <td>6.8% 🥇<br><sub>78676</sub></td>
359
+ <td>58.1%<br><sub>674922</sub></td>
360
+ <td>55.7%<br><sub>647070</sub></td>
361
+ <td>27.7%<br><sub>321494</sub></td>
362
+ <td>57.7%<br><sub>670318</sub></td>
363
+ </tr>
364
+ <tr>
365
+ <td><i>Time</i></td>
366
+ <td>226s · 523s · 309s</td>
367
+ <td>80s</td>
368
+ <td>1709s<sup>(*)</sup></td>
369
+ <td>8151s<sup>(*)</sup></td>
370
+ <td>9.4s</td>
371
+ </tr>
372
+ <tr><td colspan="6"></td></tr>
373
+ <tr>
374
+ <td rowspan="3"><b>vyper</b><br><sub>21166<br>functions</sub></td>
375
+ <td><i>Errors</i></td>
376
+ <td>0.5% 🥇<br><sub>110</sub></td>
377
+ <td>100.0%<br><sub>21166</sub></td>
378
+ <td>77.8%<br><sub>16462</sub></td>
379
+ <td>100.0%<br><sub>21166</sub></td>
380
+ <td>1.8%<br><sub>390</sub></td>
381
+ </tr>
382
+ <tr>
383
+ <td><i>Errors strict</i></td>
384
+ <td>11.4% 🥇<br><sub>2410</sub></td>
385
+ <td>100.0%<br><sub>21166</sub></td>
386
+ <td>91.0%<br><sub>19253</sub></td>
387
+ <td>100.0%<br><sub>21166</sub></td>
388
+ <td>59.6%<br><sub>12610</sub></td>
389
+ </tr>
390
+ <tr>
391
+ <td><i>Time</i></td>
392
+ <td>3.7s · 8.7s · 5.1s</td>
393
+ <td>2.2s</td>
394
+ <td>59s<sup>(*)</sup></td>
395
+ <td>28s<sup>(*)</sup></td>
396
+ <td>0.6s</td>
397
+ </tr>
398
+ </table>
399
+
400
+ See [benchmark/README.md](./benchmark/) for the methodology and commands to reproduce these results
401
+
402
+ <i>versions: evmole v0.4.1; <a href="https://github.com/shazow/whatsabi">whatsabi</a> v0.14.1; <a href="https://github.com/acuarica/evm">sevm</a> v0.6.19; <a href="https://github.com/g00dv1n/evm-hound-rs">evm-hound-rs</a> v0.1.4; <a href="https://github.com/Jon-Becker/heimdall-rs">heimdall-rs</a> v0.8.4</i>
403
+
404
+ <sup>(*)</sup>: <b>sevm</b> and <b>heimdall-rs</b> are full decompilers, not limited to extracting function selectors
405
+
406
+ ## How it works
407
+
408
+ Short: Executes code with a custom EVM and traces CALLDATA usage.
409
+
410
+ Long: TODO
411
+
412
+ ## License
413
+ MIT
414
+
@@ -0,0 +1,7 @@
1
+ evmole-0.4.1.dist-info/METADATA,sha256=IUy7lilP6d-ezorBnL7PEx8O__TziUB6kvWwXMtQS8k,13703
2
+ evmole-0.4.1.dist-info/WHEEL,sha256=iLyJQhiiBYwo5FdZQS-97uaKimQdR9d5M5S1bVJlIxM,94
3
+ evmole/__init__.py,sha256=wCCbPQR_fm5B9AXbbbf1cp8SierPV7s3eoctmhcQRqg,107
4
+ evmole/__init__.pyi,sha256=JSJoxDfuaNLF2DT1poK4ihA-A_fb8bFvSJ9nQ7E0P58,1520
5
+ evmole/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ evmole/evmole.cp39-win_amd64.pyd,sha256=UBwZ5S3Xd1jMPWxm24PGCVLGAzPQBlpOsxA2SJQX0qI,394752
7
+ evmole-0.4.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.7.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp39-none-win_amd64