-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathexample_eip7702.py
More file actions
147 lines (116 loc) · 5.05 KB
/
example_eip7702.py
File metadata and controls
147 lines (116 loc) · 5.05 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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env python3
"""
EIP-7702 Delegation Example: Counter Contract
This example demonstrates how to use EIP-7702 delegation utilities to sponsor
a delegated call to a Counter contract's increment method.
Usage:
export SPONSOR_PRIVATE_KEY="0x..."
python example_eip7702.py
The workflow:
1. Sponsor wallet (with existing funds) pays gas for the transaction
2. Delegate wallet (randomly created) authorizes setting its code to the Counter contract via EIP-7702
3. Counter contract's increment method is executed on the delegate's account
4. The delegate's account code is set to the Counter contract during execution
"""
import asyncio
import os
import sys
from typing import Annotated
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "packages/eth_rpc/src"))
from eth_rpc import TransactionReceipt
from eth_rpc.contract import ContractFunc, ProtocolBase
from eth_rpc.delegation import sponsor_delegation
from eth_rpc.networks import Sepolia
from eth_rpc.types import METHOD, Name, NoArgs
from eth_rpc.wallet import PrivateKeyWallet
from eth_typing import HexAddress, HexStr
class Counter(ProtocolBase):
"""
Example Counter contract with increment method.
Solidity equivalent:
contract Counter {
uint256 public count;
address public lastToEverUpdate;
function increment() external {
count++;
lastToEverUpdate = msg.sender;
}
}
"""
increment: ContractFunc[NoArgs, None] = METHOD
number: ContractFunc[NoArgs, int] = METHOD
last_to_ever_update: Annotated[
ContractFunc[NoArgs, HexAddress],
Name("lastToEverUpdate"),
] = METHOD
async def main():
"""Demonstrate EIP-7702 delegation workflow with Counter contract"""
print("🔗 EIP-7702 Delegation Example: Counter Contract")
print("=" * 50)
sponsor_private_key = os.getenv("SPONSOR_PRIVATE_KEY")
if not sponsor_private_key:
print("❌ Error: SPONSOR_PRIVATE_KEY environment variable not set")
print("Usage: export SPONSOR_PRIVATE_KEY='0x...' && python example_eip7702.py")
sys.exit(1)
print("\n1. Setting up wallets...")
sponsor_wallet = PrivateKeyWallet[Sepolia](private_key=HexStr(sponsor_private_key))
delegate_wallet = PrivateKeyWallet.create_new()
print(f" Sponsor wallet: {sponsor_wallet.address} (has funds, pays gas fees)")
print(
f" Delegate wallet: {delegate_wallet.address} (randomly created, authorizes code setting)"
)
counter_address = HexAddress("0x0271297dcc0CceA3640bbaf34801025E6F63F448")
print(f" Counter contract: {counter_address}")
print("\n2. Creating Counter contract instance...")
counter = Counter[Sepolia](address=counter_address)
print(f" Counter.increment function: {counter.increment}")
print("\n3. Preparing increment call...")
increment_call_data = counter.increment().data
print(f" Increment call data: {increment_call_data}")
# Create sponsored delegation transaction
print("\n4. Creating sponsored delegation transaction...")
print(" This transaction will:")
print(" - Be paid for by the sponsor wallet (which has ETH for gas)")
print(" - Set the delegate's account code to the Counter contract")
print(" - Execute the increment method within the same transaction")
print(" - Automatically handle network-aware nonce lookup")
print(" Using the enhanced execute method with delegation...")
tx_hash = await counter.increment().execute(
wallet=sponsor_wallet,
delegate_wallet=delegate_wallet,
)
print(f" ✅ Transaction sent using enhanced execute method: {tx_hash}")
print(f"\n5. Demonstrating simple wallet delegation (without contract data)...")
print(" Using the wallet delegation utility method...")
simple_delegate = PrivateKeyWallet.create_new()
print(f" New delegate wallet: {simple_delegate.address}")
delegation_tx_hash = await simple_delegate.delegate_to_contract(
sponsor_wallet=sponsor_wallet,
contract_address=counter_address,
)
print(f" Delegation transaction sent: {delegation_tx_hash}")
print(f"\n🎉 EIP-7702 delegation workflow complete!")
print(" Both utility methods successfully demonstrated.")
print("Waiting for transaction to be mined...")
while True:
receipt = await TransactionReceipt[Sepolia].get_by_hash(tx_hash)
if receipt:
if receipt.status == 1:
print("Transaction mined successfully")
break
if receipt.status == 0:
raise Exception(f"Transaction failed: {receipt.status}")
await asyncio.sleep(4)
counter = Counter[Sepolia](address=delegate_wallet.address)
print(f" Counter.number: {await counter.number().get()}")
print(
f" Counter.last_to_ever_update: {await counter.last_to_ever_update().get()}"
)
if __name__ == "__main__":
try:
asyncio.run(main())
except Exception as e:
print(f"\n❌ Example failed: {e}")
import traceback
traceback.print_exc()
sys.exit(1)