eth-prototype 1.1.0__py3-none-any.whl → 1.1.2__py3-none-any.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.
- {eth_prototype-1.1.0.dist-info → eth_prototype-1.1.2.dist-info}/METADATA +1 -1
- eth_prototype-1.1.2.dist-info/RECORD +14 -0
- {eth_prototype-1.1.0.dist-info → eth_prototype-1.1.2.dist-info}/WHEEL +1 -1
- ethproto/aa_bundler.py +84 -36
- ethproto/w3wrappers.py +6 -4
- eth_prototype-1.1.0.dist-info/RECORD +0 -14
- {eth_prototype-1.1.0.dist-info → eth_prototype-1.1.2.dist-info}/AUTHORS.rst +0 -0
- {eth_prototype-1.1.0.dist-info → eth_prototype-1.1.2.dist-info}/LICENSE.txt +0 -0
- {eth_prototype-1.1.0.dist-info → eth_prototype-1.1.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
ethproto/__init__.py,sha256=YWkAFysBp4tZjLWWB2FFmp5yG23pUYhQvgQW9b3soXs,579
|
2
|
+
ethproto/aa_bundler.py,sha256=wWUa-uqTvDKUI7ewxfCQzUsVxIPhu7N-kSHu-_aXtJ4,10495
|
3
|
+
ethproto/build_artifacts.py,sha256=xwCd5hJUHP82IA-y3sSfX6fV15kjCGtV19RxNRcoor0,5441
|
4
|
+
ethproto/contracts.py,sha256=rNVbCK1hURy7lWKhzSdXgVWo3wx9O_Ghk-6PfgOsRNk,18662
|
5
|
+
ethproto/defender_relay.py,sha256=05A8TfRZwiBhCpo924Pf9CjfKSir2Wvgg1p_asFxJbw,1777
|
6
|
+
ethproto/w3wrappers.py,sha256=0lm-h-3QpoKK54HvQ66hm_fbaVRy6QFuzedTks3FeFA,21245
|
7
|
+
ethproto/wadray.py,sha256=JBsu5KcyU9k70bDK03T2IY6qPVFO30WbYPhwrAHdXao,8262
|
8
|
+
ethproto/wrappers.py,sha256=9qDwRDOXw3wquzvGfIsub-VPWm98GBWP7dHLFOUPWzg,17307
|
9
|
+
eth_prototype-1.1.2.dist-info/AUTHORS.rst,sha256=Ui-05yYXtDZxna6o1yNcfdm8Jt68UIDQ01osiLxlYlU,95
|
10
|
+
eth_prototype-1.1.2.dist-info/LICENSE.txt,sha256=U_Q6_nDYDwZPIuhttHi37hXZ2qU2-HlV2geo9hzHXFw,1087
|
11
|
+
eth_prototype-1.1.2.dist-info/METADATA,sha256=Iao560GckmPsEsXAtt1Cm8wEZwElZvzucStqIiTGP9k,2482
|
12
|
+
eth_prototype-1.1.2.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
13
|
+
eth_prototype-1.1.2.dist-info/top_level.txt,sha256=Dl0X7m6N1hxeo4JpGpSNqWC2gtsN0731g-DL1J0mpjc,9
|
14
|
+
eth_prototype-1.1.2.dist-info/RECORD,,
|
ethproto/aa_bundler.py
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
import random
|
2
|
-
from
|
2
|
+
from collections import defaultdict
|
3
3
|
from enum import Enum
|
4
|
-
import
|
4
|
+
from threading import local
|
5
|
+
from warnings import warn
|
6
|
+
|
5
7
|
from environs import Env
|
6
8
|
from eth_abi import encode
|
7
9
|
from eth_account import Account
|
8
10
|
from eth_account.messages import encode_defunct
|
9
11
|
from hexbytes import HexBytes
|
10
12
|
from web3 import Web3
|
11
|
-
from .
|
13
|
+
from web3.constants import ADDRESS_ZERO
|
12
14
|
|
15
|
+
from .contracts import RevertError
|
13
16
|
|
14
17
|
env = Env()
|
15
18
|
|
@@ -17,6 +20,10 @@ AA_BUNDLER_SENDER = env.str("AA_BUNDLER_SENDER", None)
|
|
17
20
|
AA_BUNDLER_ENTRYPOINT = env.str("AA_BUNDLER_ENTRYPOINT", "0x0000000071727De22E5E9d8BAf0edAc6f37da032")
|
18
21
|
AA_BUNDLER_EXECUTOR_PK = env.str("AA_BUNDLER_EXECUTOR_PK", None)
|
19
22
|
AA_BUNDLER_PROVIDER = env.str("AA_BUNDLER_PROVIDER", "alchemy")
|
23
|
+
AA_BUNDLER_GAS_LIMIT_FACTOR = env.float("AA_BUNDLER_GAS_LIMIT_FACTOR", 1)
|
24
|
+
AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR = env.float("AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR", 1)
|
25
|
+
AA_BUNDLER_BASE_GAS_PRICE_FACTOR = env.float("AA_BUNDLER_BASE_GAS_PRICE_FACTOR", 1)
|
26
|
+
AA_BUNDLER_VERIFICATION_GAS_FACTOR = env.float("AA_BUNDLER_VERIFICATION_GAS_FACTOR", 1)
|
20
27
|
|
21
28
|
NonceMode = Enum(
|
22
29
|
"NonceMode",
|
@@ -46,8 +53,8 @@ GET_NONCE_ABI = [
|
|
46
53
|
}
|
47
54
|
]
|
48
55
|
|
49
|
-
NONCE_CACHE =
|
50
|
-
RANDOM_NONCE_KEY =
|
56
|
+
NONCE_CACHE = defaultdict(lambda: 0)
|
57
|
+
RANDOM_NONCE_KEY = local()
|
51
58
|
|
52
59
|
|
53
60
|
def pack_two(a, b):
|
@@ -64,6 +71,10 @@ def _to_uint(x):
|
|
64
71
|
raise RuntimeError(f"Invalid int value {x}")
|
65
72
|
|
66
73
|
|
74
|
+
def apply_factor(x, factor):
|
75
|
+
return int(_to_uint(x) * factor)
|
76
|
+
|
77
|
+
|
67
78
|
def pack_user_operation(user_operation):
|
68
79
|
# https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/interfaces/PackedUserOperation.sol
|
69
80
|
return {
|
@@ -129,10 +140,9 @@ def fetch_nonce(w3, account, entry_point, nonce_key):
|
|
129
140
|
|
130
141
|
|
131
142
|
def get_random_nonce_key():
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
return RANDOM_NONCE_KEY
|
143
|
+
if getattr(RANDOM_NONCE_KEY, "key", None) is None:
|
144
|
+
RANDOM_NONCE_KEY.key = random.randint(1, 2**192 - 1)
|
145
|
+
return RANDOM_NONCE_KEY.key
|
136
146
|
|
137
147
|
|
138
148
|
def get_nonce_and_key(w3, tx, nonce_mode, entry_point=AA_BUNDLER_ENTRYPOINT, fetch=False):
|
@@ -147,31 +157,45 @@ def get_nonce_and_key(w3, tx, nonce_mode, entry_point=AA_BUNDLER_ENTRYPOINT, fet
|
|
147
157
|
|
148
158
|
if nonce is None:
|
149
159
|
if fetch or nonce_mode == NonceMode.FIXED_KEY_FETCH_ALWAYS:
|
150
|
-
nonce = fetch_nonce(w3, tx
|
151
|
-
elif nonce_key not in NONCE_CACHE:
|
152
|
-
nonce = 0
|
160
|
+
nonce = fetch_nonce(w3, get_sender(tx), entry_point, nonce_key)
|
153
161
|
else:
|
154
162
|
nonce = NONCE_CACHE[nonce_key]
|
155
163
|
return nonce_key, nonce
|
156
164
|
|
157
165
|
|
158
|
-
def
|
166
|
+
def consume_nonce(nonce_key, nonce):
|
167
|
+
NONCE_CACHE[nonce_key] = max(NONCE_CACHE[nonce_key], nonce + 1)
|
168
|
+
|
169
|
+
|
170
|
+
def check_nonce_error(resp, retry_nonce):
|
171
|
+
"""Returns the next nonce if resp contains a nonce error and retries weren't exhausted
|
172
|
+
Raises RevertError otherwise
|
173
|
+
"""
|
159
174
|
if "AA25" in resp["error"]["message"] and AA_BUNDLER_MAX_GETNONCE_RETRIES > 0:
|
160
175
|
# Retry fetching the nonce
|
161
176
|
if retry_nonce == AA_BUNDLER_MAX_GETNONCE_RETRIES:
|
162
177
|
raise RevertError(resp["error"]["message"])
|
163
178
|
warn(f'{resp["error"]["message"]} error, I will retry fetching the nonce')
|
164
|
-
return
|
179
|
+
return (retry_nonce or 0) + 1
|
165
180
|
else:
|
166
181
|
raise RevertError(resp["error"]["message"])
|
167
182
|
|
168
183
|
|
169
184
|
def get_base_fee(w3):
|
170
185
|
blk = w3.eth.get_block("latest")
|
171
|
-
return blk["baseFeePerGas"]
|
186
|
+
return int(_to_uint(blk["baseFeePerGas"]) * AA_BUNDLER_BASE_GAS_PRICE_FACTOR)
|
172
187
|
|
173
188
|
|
174
|
-
def
|
189
|
+
def get_sender(tx):
|
190
|
+
if "from" not in tx or tx["from"] == ADDRESS_ZERO:
|
191
|
+
if AA_BUNDLER_SENDER is None:
|
192
|
+
raise RuntimeError("Must define AA_BUNDLER_SENDER or send 'from' in the TX")
|
193
|
+
return AA_BUNDLER_SENDER
|
194
|
+
else:
|
195
|
+
return tx["from"]
|
196
|
+
|
197
|
+
|
198
|
+
def build_user_operation(w3, tx, retry_nonce=None):
|
175
199
|
nonce_key, nonce = get_nonce_and_key(
|
176
200
|
w3, tx, AA_BUNDLER_NONCE_MODE, entry_point=AA_BUNDLER_ENTRYPOINT, fetch=retry_nonce is not None
|
177
201
|
)
|
@@ -185,7 +209,7 @@ def send_transaction(w3, tx, retry_nonce=None):
|
|
185
209
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"
|
186
210
|
)
|
187
211
|
user_operation = {
|
188
|
-
"sender": tx
|
212
|
+
"sender": get_sender(tx),
|
189
213
|
"nonce": hex(make_nonce(nonce_key, nonce)),
|
190
214
|
"callData": call_data,
|
191
215
|
"signature": dummy_signature,
|
@@ -196,39 +220,63 @@ def send_transaction(w3, tx, retry_nonce=None):
|
|
196
220
|
"eth_estimateUserOperationGas", [user_operation, AA_BUNDLER_ENTRYPOINT]
|
197
221
|
)
|
198
222
|
if "error" in resp:
|
199
|
-
|
223
|
+
next_nonce = check_nonce_error(resp, retry_nonce)
|
224
|
+
return build_user_operation(w3, tx, retry_nonce=next_nonce)
|
200
225
|
|
201
226
|
user_operation.update(resp["result"])
|
202
227
|
|
203
228
|
resp = w3.provider.make_request("rundler_maxPriorityFeePerGas", [])
|
204
229
|
if "error" in resp:
|
205
230
|
raise RevertError(resp["error"]["message"])
|
206
|
-
|
207
|
-
user_operation["
|
208
|
-
|
209
|
-
elif AA_BUNDLER_PROVIDER == "
|
210
|
-
|
211
|
-
|
212
|
-
"preVerificationGas": "0x00",
|
213
|
-
"callGasLimit": "0x00",
|
214
|
-
"verificationGasLimit": "0x00",
|
215
|
-
"maxFeePerGas": "0x00",
|
216
|
-
"maxPriorityFeePerGas": "0x00",
|
217
|
-
}
|
231
|
+
user_operation["maxPriorityFeePerGas"] = resp["result"]
|
232
|
+
user_operation["maxFeePerGas"] = hex(int(resp["result"], 16) + get_base_fee(w3))
|
233
|
+
|
234
|
+
elif AA_BUNDLER_PROVIDER == "generic":
|
235
|
+
resp = w3.provider.make_request(
|
236
|
+
"eth_estimateUserOperationGas", [user_operation, AA_BUNDLER_ENTRYPOINT]
|
218
237
|
)
|
219
|
-
|
220
|
-
|
238
|
+
if "error" in resp:
|
239
|
+
next_nonce = check_nonce_error(resp, retry_nonce)
|
240
|
+
return build_user_operation(w3, tx, retry_nonce=next_nonce)
|
241
|
+
|
242
|
+
user_operation.update(resp["result"])
|
243
|
+
|
244
|
+
else:
|
245
|
+
warn(f"Unknown AA_BUNDLER_PROVIDER: {AA_BUNDLER_PROVIDER}")
|
246
|
+
|
247
|
+
# Apply increase factors
|
248
|
+
user_operation["verificationGasLimit"] = hex(
|
249
|
+
apply_factor(user_operation["verificationGasLimit"], AA_BUNDLER_VERIFICATION_GAS_FACTOR)
|
221
250
|
)
|
251
|
+
if "maxPriorityFeePerGas" in user_operation:
|
252
|
+
user_operation["maxPriorityFeePerGas"] = hex(
|
253
|
+
apply_factor(user_operation["maxPriorityFeePerGas"], AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR)
|
254
|
+
)
|
255
|
+
if "callGasLimit" in user_operation:
|
256
|
+
user_operation["callGasLimit"] = hex(
|
257
|
+
apply_factor(user_operation["callGasLimit"], AA_BUNDLER_GAS_LIMIT_FACTOR)
|
258
|
+
)
|
259
|
+
|
222
260
|
# Remove paymaster related fields
|
223
261
|
user_operation.pop("paymaster", None)
|
224
262
|
user_operation.pop("paymasterData", None)
|
225
263
|
user_operation.pop("paymasterVerificationGasLimit", None)
|
226
264
|
user_operation.pop("paymasterPostOpGasLimit", None)
|
227
265
|
|
266
|
+
# Consume the nonce, even if the userop may fail later
|
267
|
+
consume_nonce(nonce_key, nonce)
|
268
|
+
|
269
|
+
return user_operation
|
270
|
+
|
271
|
+
|
272
|
+
def send_transaction(w3, tx, retry_nonce=None):
|
273
|
+
user_operation = build_user_operation(w3, tx, retry_nonce)
|
274
|
+
user_operation["signature"] = sign_user_operation(
|
275
|
+
AA_BUNDLER_EXECUTOR_PK, user_operation, tx["chainId"], AA_BUNDLER_ENTRYPOINT
|
276
|
+
)
|
228
277
|
resp = w3.provider.make_request("eth_sendUserOperation", [user_operation, AA_BUNDLER_ENTRYPOINT])
|
229
278
|
if "error" in resp:
|
230
|
-
|
279
|
+
next_nonce = check_nonce_error(resp, retry_nonce)
|
280
|
+
return send_transaction(w3, tx, retry_nonce=next_nonce)
|
231
281
|
|
232
|
-
|
233
|
-
NONCE_CACHE[nonce_key] = nonce + 1
|
234
|
-
return resp["result"]
|
282
|
+
return {"userOpHash": resp["result"]}
|
ethproto/w3wrappers.py
CHANGED
@@ -375,6 +375,8 @@ class W3ETHCall(ETHCall):
|
|
375
375
|
def normalize_receipt(self, wrapper, receipt):
|
376
376
|
if W3_TRANSACT_MODE == "defender-async":
|
377
377
|
return receipt # Don't do anything because the receipt is just a dict of not-yet-mined tx
|
378
|
+
elif W3_TRANSACT_MODE == "aa-bundler-async":
|
379
|
+
return receipt # Don't do anything because the receipt is just a dict of {"userOpHash": "..."}
|
378
380
|
return ReceiptWrapper(receipt, wrapper.contract)
|
379
381
|
|
380
382
|
def _handle_exception(self, err):
|
@@ -442,7 +444,7 @@ class W3Provider(BaseProvider):
|
|
442
444
|
def get_events(self, eth_wrapper, event_name, filter_kwargs={}):
|
443
445
|
"""Returns a list of events given a filter, like this:
|
444
446
|
|
445
|
-
>>> provider.get_events(currencywrapper, "Transfer", dict(
|
447
|
+
>>> provider.get_events(currencywrapper, "Transfer", dict(from_block=0))
|
446
448
|
[AttributeDict({
|
447
449
|
'args': AttributeDict(
|
448
450
|
{'from': '0x0000000000000000000000000000000000000000',
|
@@ -461,8 +463,8 @@ class W3Provider(BaseProvider):
|
|
461
463
|
"""
|
462
464
|
contract = eth_wrapper.contract
|
463
465
|
event = getattr(contract.events, event_name)
|
464
|
-
if "
|
465
|
-
filter_kwargs["
|
466
|
+
if "from_block" not in filter_kwargs:
|
467
|
+
filter_kwargs["from_block"] = self.get_first_block(eth_wrapper)
|
466
468
|
event_filter = event.create_filter(**filter_kwargs)
|
467
469
|
return event_filter.get_all_entries()
|
468
470
|
|
@@ -488,7 +490,7 @@ class W3Provider(BaseProvider):
|
|
488
490
|
constructor_params, init_params = init_params
|
489
491
|
real_contract = self.construct(eth_contract, constructor_params, {"from": eth_wrapper.owner})
|
490
492
|
ERC1967Proxy = self.get_contract_factory("ERC1967Proxy")
|
491
|
-
init_data = eth_contract.
|
493
|
+
init_data = eth_contract.encode_abi(abi_element_identifier="initialize", args=init_params)
|
492
494
|
proxy_contract = self.construct(
|
493
495
|
ERC1967Proxy,
|
494
496
|
(real_contract.address, init_data),
|
@@ -1,14 +0,0 @@
|
|
1
|
-
ethproto/__init__.py,sha256=YWkAFysBp4tZjLWWB2FFmp5yG23pUYhQvgQW9b3soXs,579
|
2
|
-
ethproto/aa_bundler.py,sha256=34yXgQw_vV81Wmf9cFxcLTxLUb1jzCrBE7XOw5RIjtI,8652
|
3
|
-
ethproto/build_artifacts.py,sha256=xwCd5hJUHP82IA-y3sSfX6fV15kjCGtV19RxNRcoor0,5441
|
4
|
-
ethproto/contracts.py,sha256=rNVbCK1hURy7lWKhzSdXgVWo3wx9O_Ghk-6PfgOsRNk,18662
|
5
|
-
ethproto/defender_relay.py,sha256=05A8TfRZwiBhCpo924Pf9CjfKSir2Wvgg1p_asFxJbw,1777
|
6
|
-
ethproto/w3wrappers.py,sha256=UbSuaB5_TYF4kiGNwIzvPPE7f0A6soZ7gc5jd180mVM,21065
|
7
|
-
ethproto/wadray.py,sha256=JBsu5KcyU9k70bDK03T2IY6qPVFO30WbYPhwrAHdXao,8262
|
8
|
-
ethproto/wrappers.py,sha256=9qDwRDOXw3wquzvGfIsub-VPWm98GBWP7dHLFOUPWzg,17307
|
9
|
-
eth_prototype-1.1.0.dist-info/AUTHORS.rst,sha256=Ui-05yYXtDZxna6o1yNcfdm8Jt68UIDQ01osiLxlYlU,95
|
10
|
-
eth_prototype-1.1.0.dist-info/LICENSE.txt,sha256=U_Q6_nDYDwZPIuhttHi37hXZ2qU2-HlV2geo9hzHXFw,1087
|
11
|
-
eth_prototype-1.1.0.dist-info/METADATA,sha256=uOJw45vu6Xwc3uzJ1IfWV0RW1i2ST_ZHJ775Uwbi7zk,2482
|
12
|
-
eth_prototype-1.1.0.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
13
|
-
eth_prototype-1.1.0.dist-info/top_level.txt,sha256=Dl0X7m6N1hxeo4JpGpSNqWC2gtsN0731g-DL1J0mpjc,9
|
14
|
-
eth_prototype-1.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|