forked from NSPG13/agent-bounties
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathevm.py
More file actions
74 lines (53 loc) · 2.47 KB
/
Copy pathevm.py
File metadata and controls
74 lines (53 loc) · 2.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""Small dependency-free EVM encoding helpers shared by deployment tooling."""
from __future__ import annotations
import re
from typing import Any
from Crypto.Hash import keccak
def keccak_bytes(data: bytes) -> bytes:
digest = keccak.new(digest_bits=256)
digest.update(data)
return digest.digest()
def keccak256(data: bytes) -> str:
return f"0x{keccak_bytes(data).hex()}"
def address_bytes(value: str) -> bytes:
raw = value.removeprefix("0x")
if not re.fullmatch(r"[0-9a-fA-F]{40}", raw):
raise ValueError(f"invalid EVM address: {value}")
return bytes.fromhex(raw)
def address_word(value: str) -> bytes:
return address_bytes(value).rjust(32, b"\0")
def uint_word(value: int) -> bytes:
if value < 0 or value >= 1 << 256:
raise ValueError("uint256 is out of range")
return value.to_bytes(32, "big")
def _rlp_bytes(value: bytes) -> bytes:
if len(value) == 1 and value[0] < 0x80:
return value
if len(value) <= 55:
return bytes([0x80 + len(value)]) + value
length = len(value).to_bytes((len(value).bit_length() + 7) // 8, "big")
return bytes([0xB7 + len(length)]) + length + value
def _rlp_list(values: list[bytes]) -> bytes:
payload = b"".join(values)
if len(payload) <= 55:
return bytes([0xC0 + len(payload)]) + payload
length = len(payload).to_bytes((len(payload).bit_length() + 7) // 8, "big")
return bytes([0xF7 + len(length)]) + length + payload
def create_address(deployer: str, nonce: int) -> str:
if nonce < 0:
raise ValueError("deployer nonce must be nonnegative")
encoded_nonce = b"" if nonce == 0 else nonce.to_bytes((nonce.bit_length() + 7) // 8, "big")
payload = _rlp_list([_rlp_bytes(address_bytes(deployer)), _rlp_bytes(encoded_nonce)])
return f"0x{keccak_bytes(payload).hex()[-40:]}"
def artifact_hex(field: Any, name: str, *, distinct_odd_length_error: bool = False) -> bytes:
value = field.get("object") if isinstance(field, dict) else None
if not isinstance(value, str):
raise ValueError(f"artifact {name} is missing concrete bytecode")
raw = value.removeprefix("0x")
if not raw or not re.fullmatch(r"[0-9a-fA-F]+", raw):
raise ValueError(f"artifact {name} is missing concrete bytecode")
if len(raw) % 2:
if distinct_odd_length_error:
raise ValueError(f"artifact {name} has odd-length bytecode")
raise ValueError(f"artifact {name} is missing concrete bytecode")
return bytes.fromhex(raw)