Skip to content

Commit cf2c7c6

Browse files
committed
push updated deploy_create2_factory refactored with EEST as dep
1 parent f2cd5f9 commit cf2c7c6

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Deploy a simple CREATE2 factory for benchmark tests (REFACTORED with EEST Op codes).
4+
This factory can be reused across all tests and allows deterministic addresses.
5+
6+
This version uses EEST Op code tooling for better readability.
7+
"""
8+
9+
import argparse
10+
import sys
11+
from pathlib import Path
12+
13+
# Add parent directories to path to import EEST tools
14+
sys.path.insert(0, str(Path(__file__).parents[3]))
15+
16+
try:
17+
from eth_utils import keccak
18+
from web3 import Web3
19+
20+
from ethereum_test_tools.vm.opcode import Opcodes as Op
21+
except ImportError as e:
22+
print(f"Error: Missing dependencies - {e}")
23+
print("This refactored version requires the EEST framework.")
24+
print("Run: uv sync --all-extras")
25+
sys.exit(1)
26+
27+
28+
def deploy_factory(rpc_url: str):
29+
"""Deploy a minimal CREATE2 factory using EEST Op codes."""
30+
# Connect to Geth
31+
w3 = Web3(Web3.HTTPProvider(rpc_url))
32+
if not w3.is_connected():
33+
print(f"Failed to connect to {rpc_url}")
34+
return None
35+
36+
test_account = w3.eth.accounts[0]
37+
print(f"Using test account: {test_account}")
38+
39+
# Build CREATE2 factory bytecode using EEST Op codes
40+
# This factory:
41+
# 1. Takes salt (first 32 bytes) from calldata
42+
# 2. Takes bytecode (rest) from calldata
43+
# 3. Deploys via CREATE2
44+
# 4. Returns the deployed address
45+
46+
factory_code = (
47+
# Load salt from calldata[0:32]
48+
Op.PUSH0 # offset 0
49+
+ Op.CALLDATALOAD # load 32 bytes from calldata[0]
50+
# Calculate bytecode length (calldatasize - 32)
51+
+ Op.PUSH1(32) # salt size
52+
+ Op.CALLDATASIZE # total calldata size
53+
+ Op.SUB # bytecode_len = calldatasize - 32
54+
# Copy bytecode from calldata[32:] to memory[0:]
55+
+ Op.DUP1 # duplicate bytecode_len for CREATE2
56+
+ Op.PUSH1(32) # source offset in calldata
57+
+ Op.PUSH0 # dest offset in memory
58+
+ Op.CALLDATACOPY # copy bytecode to memory
59+
# CREATE2(value=0, mem_offset=0, mem_size=bytecode_len, salt)
60+
# Stack: [salt, bytecode_len]
61+
+ Op.PUSH0 # value = 0
62+
+ Op.SWAP2 # Stack: [bytecode_len, 0, salt]
63+
+ Op.PUSH0 # mem_offset = 0
64+
+ Op.SWAP1 # Stack: [bytecode_len, 0, 0, salt]
65+
+ Op.SWAP3 # Stack: [salt, 0, 0, bytecode_len]
66+
+ Op.SWAP2 # Stack: [0, salt, 0, bytecode_len]
67+
+ Op.SWAP1 # Stack: [salt, 0, 0, bytecode_len]
68+
+ Op.CREATE2 # Deploy contract
69+
# Store address in memory and return it
70+
+ Op.PUSH0 # memory offset 0
71+
+ Op.MSTORE # store address at memory[0:32]
72+
+ Op.PUSH1(32) # return 32 bytes
73+
+ Op.PUSH0 # from memory offset 0
74+
+ Op.RETURN # return the address
75+
)
76+
77+
# Convert Op code object to bytes
78+
factory_bytecode = bytes(factory_code)
79+
80+
print(f"\nFactory bytecode ({len(factory_bytecode)} bytes):")
81+
print(f"0x{factory_bytecode.hex()}")
82+
83+
# Deploy the factory
84+
print("\nDeploying CREATE2 factory...")
85+
tx_hash = w3.eth.send_transaction(
86+
{"from": test_account, "data": factory_bytecode, "gas": 3000000}
87+
)
88+
89+
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
90+
91+
if receipt["status"] != 1:
92+
print("Failed to deploy factory")
93+
return None
94+
95+
factory_address = receipt["contractAddress"]
96+
print(f"✅ Factory deployed at: {factory_address}")
97+
98+
# Test the factory with a simple contract
99+
print("\nTesting factory...")
100+
test_bytecode = bytes([0x00]) # Simple STOP opcode
101+
test_salt = 0
102+
103+
calldata = test_salt.to_bytes(32, "big") + test_bytecode
104+
105+
# Use eth_call to get the address that would be created
106+
result = w3.eth.call({"to": factory_address, "data": calldata})
107+
108+
if result:
109+
test_addr = "0x" + result[-20:].hex()
110+
print(f"Test deployment would create: {test_addr}")
111+
112+
# Calculate expected CREATE2 address
113+
expected = keccak(
114+
b"\xff"
115+
+ bytes.fromhex(factory_address[2:])
116+
+ test_salt.to_bytes(32, "big")
117+
+ keccak(test_bytecode)
118+
)[-20:]
119+
expected_addr = "0x" + expected.hex()
120+
print(f"Expected CREATE2 address: {expected_addr}")
121+
122+
return factory_address
123+
124+
125+
def main():
126+
"""Execute the factory deployment script."""
127+
parser = argparse.ArgumentParser(description="Deploy CREATE2 factory (EEST refactored)")
128+
parser.add_argument(
129+
"--rpc-url",
130+
default="http://127.0.0.1:8545",
131+
help="RPC URL (default: http://127.0.0.1:8545)",
132+
)
133+
134+
args = parser.parse_args()
135+
factory_address = deploy_factory(args.rpc_url)
136+
137+
if factory_address:
138+
print("\n" + "=" * 60)
139+
print("Factory deployed successfully!")
140+
print(f"Factory address: {factory_address}")
141+
print("\nAdd this to your test configuration:")
142+
print(f'FACTORY_ADDRESS = Address("{factory_address}")')
143+
print("=" * 60)
144+
145+
146+
if __name__ == "__main__":
147+
main()

0 commit comments

Comments
 (0)