eth-prototype 1.4.1__py3-none-any.whl → 1.5.0b1__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.4.1.dist-info → eth_prototype-1.5.0b1.dist-info}/METADATA +1 -1
- {eth_prototype-1.4.1.dist-info → eth_prototype-1.5.0b1.dist-info}/RECORD +7 -7
- {eth_prototype-1.4.1.dist-info → eth_prototype-1.5.0b1.dist-info}/WHEEL +1 -1
- ethproto/aa_bundler.py +129 -18
- {eth_prototype-1.4.1.dist-info → eth_prototype-1.5.0b1.dist-info}/licenses/AUTHORS.rst +0 -0
- {eth_prototype-1.4.1.dist-info → eth_prototype-1.5.0b1.dist-info}/licenses/LICENSE.txt +0 -0
- {eth_prototype-1.4.1.dist-info → eth_prototype-1.5.0b1.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
eth_prototype-1.
|
|
2
|
-
eth_prototype-1.
|
|
1
|
+
eth_prototype-1.5.0b1.dist-info/licenses/AUTHORS.rst,sha256=Ui-05yYXtDZxna6o1yNcfdm8Jt68UIDQ01osiLxlYlU,95
|
|
2
|
+
eth_prototype-1.5.0b1.dist-info/licenses/LICENSE.txt,sha256=U_Q6_nDYDwZPIuhttHi37hXZ2qU2-HlV2geo9hzHXFw,1087
|
|
3
3
|
ethproto/__init__.py,sha256=YWkAFysBp4tZjLWWB2FFmp5yG23pUYhQvgQW9b3soXs,579
|
|
4
|
-
ethproto/aa_bundler.py,sha256=
|
|
4
|
+
ethproto/aa_bundler.py,sha256=aECUJJzvdEDJCzM8qTET9m309xPnQfvfWVQskkIHEss,22162
|
|
5
5
|
ethproto/build_artifacts.py,sha256=3t-MTSFZU1pQtDwf65zNJkceWleLRlzcEo8CFpu4_6s,10031
|
|
6
6
|
ethproto/contracts.py,sha256=R9lWKPe77jkPBXx798qhnVPWSFF2nhz4AaYowipNIBc,22625
|
|
7
7
|
ethproto/defender_relay.py,sha256=05A8TfRZwiBhCpo924Pf9CjfKSir2Wvgg1p_asFxJbw,1777
|
|
@@ -12,7 +12,7 @@ ethproto/test_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
12
12
|
ethproto/test_utils/factories.py,sha256=G8DnUDG_yThRxMTCkymzcjm9lR_ni0_ZmTsb3sEfIdI,1805
|
|
13
13
|
ethproto/test_utils/hardhat.py,sha256=HzTqIznu6zVd_-doL96ftFJ235ktDCQen1QDQbNuwfM,2361
|
|
14
14
|
ethproto/test_utils/vcr_utils.py,sha256=1FH2sgJlElSjWkJLuO3C7E2J-4HKyFvjAqkCnGRZJyk,797
|
|
15
|
-
eth_prototype-1.
|
|
16
|
-
eth_prototype-1.
|
|
17
|
-
eth_prototype-1.
|
|
18
|
-
eth_prototype-1.
|
|
15
|
+
eth_prototype-1.5.0b1.dist-info/METADATA,sha256=7nJRJXEAzIvwO4C8xNG47vlspDOkhaGQs5crBAWy2TQ,2697
|
|
16
|
+
eth_prototype-1.5.0b1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
17
|
+
eth_prototype-1.5.0b1.dist-info/top_level.txt,sha256=Dl0X7m6N1hxeo4JpGpSNqWC2gtsN0731g-DL1J0mpjc,9
|
|
18
|
+
eth_prototype-1.5.0b1.dist-info/RECORD,,
|
ethproto/aa_bundler.py
CHANGED
|
@@ -7,6 +7,7 @@ from warnings import warn
|
|
|
7
7
|
|
|
8
8
|
from environs import Env
|
|
9
9
|
from eth_abi import encode
|
|
10
|
+
from eth_abi.packed import encode_packed
|
|
10
11
|
from eth_account import Account
|
|
11
12
|
from eth_account.messages import encode_defunct
|
|
12
13
|
from eth_typing import HexAddress
|
|
@@ -24,7 +25,7 @@ AA_BUNDLER_URL = env.str("AA_BUNDLER_URL", env.str("WEB3_PROVIDER_URI", "http://
|
|
|
24
25
|
AA_BUNDLER_SENDER = env.str("AA_BUNDLER_SENDER", None)
|
|
25
26
|
AA_BUNDLER_ENTRYPOINT = env.str("AA_BUNDLER_ENTRYPOINT", "0x0000000071727De22E5E9d8BAf0edAc6f37da032")
|
|
26
27
|
AA_BUNDLER_EXECUTOR_PK = env.str("AA_BUNDLER_EXECUTOR_PK", None)
|
|
27
|
-
AA_BUNDLER_PROVIDER = env.str("AA_BUNDLER_PROVIDER", "
|
|
28
|
+
AA_BUNDLER_PROVIDER = env.str("AA_BUNDLER_PROVIDER", "generic")
|
|
28
29
|
AA_BUNDLER_GAS_LIMIT_FACTOR = env.float("AA_BUNDLER_GAS_LIMIT_FACTOR", 1)
|
|
29
30
|
AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR = env.float("AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR", 1)
|
|
30
31
|
AA_BUNDLER_BASE_GAS_PRICE_FACTOR = env.float("AA_BUNDLER_BASE_GAS_PRICE_FACTOR", 1)
|
|
@@ -47,7 +48,7 @@ NonceMode = Enum(
|
|
|
47
48
|
AA_BUNDLER_NONCE_MODE = env.enum("AA_BUNDLER_NONCE_MODE", default="FIXED_KEY_LOCAL_NONCE", enum=NonceMode)
|
|
48
49
|
AA_BUNDLER_NONCE_KEY = env.int("AA_BUNDLER_NONCE_KEY", 0)
|
|
49
50
|
AA_BUNDLER_MAX_GETNONCE_RETRIES = env.int("AA_BUNDLER_MAX_GETNONCE_RETRIES", 3)
|
|
50
|
-
|
|
51
|
+
AA_BUNDLER_ALCHEMY_GAS_POLICY_ID = env.str("AA_BUNDLER_ALCHEMY_GAS_POLICY_ID", None)
|
|
51
52
|
|
|
52
53
|
GET_NONCE_ABI = [
|
|
53
54
|
{
|
|
@@ -81,6 +82,10 @@ class BundlerRevertError(RevertError):
|
|
|
81
82
|
self.response = response
|
|
82
83
|
|
|
83
84
|
|
|
85
|
+
class BundlerError(Exception):
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
|
|
84
89
|
@dataclass(frozen=True)
|
|
85
90
|
class UserOpEstimation:
|
|
86
91
|
"""eth_estimateUserOperationGas response"""
|
|
@@ -97,6 +102,21 @@ class GasPrice:
|
|
|
97
102
|
max_fee_per_gas: int
|
|
98
103
|
|
|
99
104
|
|
|
105
|
+
@dataclass(frozen=True)
|
|
106
|
+
class PaymasterAndData:
|
|
107
|
+
paymaster: HexAddress
|
|
108
|
+
paymaster_data: HexBytes
|
|
109
|
+
paymaster_verification_gas_limit: int
|
|
110
|
+
paymaster_post_op_gas_limit: int
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass(frozen=True)
|
|
114
|
+
class AlchemyGasAndPaymasterAndData:
|
|
115
|
+
estimation: UserOpEstimation
|
|
116
|
+
gas_price: GasPrice
|
|
117
|
+
paymaster_and_data: PaymasterAndData
|
|
118
|
+
|
|
119
|
+
|
|
100
120
|
@dataclass(frozen=True)
|
|
101
121
|
class Tx:
|
|
102
122
|
target: HexAddress
|
|
@@ -141,7 +161,11 @@ class UserOperation:
|
|
|
141
161
|
signature: HexBytes = DUMMY_SIGNATURE
|
|
142
162
|
|
|
143
163
|
init_code: HexBytes = HexBytes("0x")
|
|
144
|
-
|
|
164
|
+
|
|
165
|
+
paymaster: HexAddress = None
|
|
166
|
+
paymaster_data: HexBytes = HexBytes("0x")
|
|
167
|
+
paymaster_verification_gas_limit: int = 0
|
|
168
|
+
paymaster_post_op_gas_limit: int = 0
|
|
145
169
|
|
|
146
170
|
@classmethod
|
|
147
171
|
def from_tx(cls, tx: Tx, nonce):
|
|
@@ -172,6 +196,10 @@ class UserOperation:
|
|
|
172
196
|
"maxPriorityFeePerGas": "0x%x" % self.max_priority_fee_per_gas,
|
|
173
197
|
"maxFeePerGas": "0x%x" % self.max_fee_per_gas,
|
|
174
198
|
"signature": add_0x_prefix(self.signature.hex()),
|
|
199
|
+
"paymaster": self.paymaster,
|
|
200
|
+
"paymasterData": self.paymaster_data,
|
|
201
|
+
"paymasterVerificationGasLimit": "0x%x" % self.paymaster_verification_gas_limit,
|
|
202
|
+
"paymasterPostOpGasLimit": "0x%x" % self.paymaster_post_op_gas_limit,
|
|
175
203
|
}
|
|
176
204
|
|
|
177
205
|
def add_estimation(self, estimation: UserOpEstimation) -> "UserOperation":
|
|
@@ -189,6 +217,15 @@ class UserOperation:
|
|
|
189
217
|
max_fee_per_gas=gas_price.max_fee_per_gas,
|
|
190
218
|
)
|
|
191
219
|
|
|
220
|
+
def add_paymaster_and_data(self, paymaster_and_data: PaymasterAndData) -> "UserOperation":
|
|
221
|
+
return replace(
|
|
222
|
+
self,
|
|
223
|
+
paymaster=paymaster_and_data.paymaster,
|
|
224
|
+
paymaster_data=paymaster_and_data.paymaster_data,
|
|
225
|
+
paymaster_verification_gas_limit=paymaster_and_data.paymaster_verification_gas_limit,
|
|
226
|
+
paymaster_post_op_gas_limit=paymaster_and_data.paymaster_post_op_gas_limit,
|
|
227
|
+
)
|
|
228
|
+
|
|
192
229
|
def sign(self, private_key: HexBytes, chain_id, entrypoint) -> "UserOperation":
|
|
193
230
|
signature = Account.sign_message(
|
|
194
231
|
encode_defunct(
|
|
@@ -225,7 +262,21 @@ class PackedUserOperation:
|
|
|
225
262
|
pre_verification_gas=user_operation.pre_verification_gas,
|
|
226
263
|
gas_fees=pack_two(user_operation.max_priority_fee_per_gas, user_operation.max_fee_per_gas),
|
|
227
264
|
init_code=user_operation.init_code,
|
|
228
|
-
paymaster_and_data=
|
|
265
|
+
paymaster_and_data=(
|
|
266
|
+
HexBytes(
|
|
267
|
+
encode_packed(
|
|
268
|
+
["address", "uint128", "uint128", "bytes"],
|
|
269
|
+
[
|
|
270
|
+
user_operation.paymaster,
|
|
271
|
+
user_operation.paymaster_verification_gas_limit,
|
|
272
|
+
user_operation.paymaster_post_op_gas_limit,
|
|
273
|
+
user_operation.paymaster_data,
|
|
274
|
+
],
|
|
275
|
+
)
|
|
276
|
+
)
|
|
277
|
+
if user_operation.paymaster is not None
|
|
278
|
+
else HexBytes("0x")
|
|
279
|
+
).to_0x_hex(),
|
|
229
280
|
signature=user_operation.signature,
|
|
230
281
|
)
|
|
231
282
|
|
|
@@ -333,6 +384,7 @@ class Bundler:
|
|
|
333
384
|
max_fee_per_gas: int = AA_BUNDLER_MAX_FEE_PER_GAS,
|
|
334
385
|
executor_pk: HexBytes = AA_BUNDLER_EXECUTOR_PK,
|
|
335
386
|
overrides: StateOverride = AA_BUNDLER_STATE_OVERRIDES,
|
|
387
|
+
alchemy_gas_policy_id: str = AA_BUNDLER_ALCHEMY_GAS_POLICY_ID,
|
|
336
388
|
):
|
|
337
389
|
self.w3 = w3
|
|
338
390
|
self.bundler = Web3(Web3.HTTPProvider(bundler_url), middleware=[])
|
|
@@ -351,6 +403,10 @@ class Bundler:
|
|
|
351
403
|
# https://docs.alchemy.com/reference/eth-estimateuseroperationgas
|
|
352
404
|
self.overrides = overrides
|
|
353
405
|
|
|
406
|
+
if alchemy_gas_policy_id is None and bundler_type == "alchemy":
|
|
407
|
+
raise BundlerError("Must provide alchemy_gas_policy_id when using alchemy bundler_type")
|
|
408
|
+
self.alchemy_gas_policy_id = alchemy_gas_policy_id
|
|
409
|
+
|
|
354
410
|
def __str__(self):
|
|
355
411
|
return (
|
|
356
412
|
f"Bundler(type={self.bundler_type}, entrypoint={self.entrypoint}, nonce_mode={self.nonce_mode}, "
|
|
@@ -404,14 +460,61 @@ class Bundler:
|
|
|
404
460
|
),
|
|
405
461
|
)
|
|
406
462
|
|
|
407
|
-
def
|
|
408
|
-
resp = self.bundler.provider.make_request(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
463
|
+
def alchemy_estimation(self, user_operation: UserOperation) -> AlchemyGasAndPaymasterAndData:
|
|
464
|
+
resp = self.bundler.provider.make_request(
|
|
465
|
+
"alchemy_requestGasAndPaymasterAndData",
|
|
466
|
+
[
|
|
467
|
+
{
|
|
468
|
+
"policyId": self.alchemy_gas_policy_id,
|
|
469
|
+
"entryPoint": self.entrypoint,
|
|
470
|
+
"dummySignature": DUMMY_SIGNATURE,
|
|
471
|
+
"userOperation": user_operation.as_reduced_dict(),
|
|
472
|
+
"overrides": {
|
|
473
|
+
"maxFeePerGas": {"multiplier": self.base_gas_price_factor},
|
|
474
|
+
"maxPriorityFeePerGas": {"multiplier": self.priority_gas_price_factor},
|
|
475
|
+
"callGasLimit": {"multiplier": self.gas_limit_factor},
|
|
476
|
+
"verificationGasLimit": {"multiplier": self.verification_gas_factor},
|
|
477
|
+
},
|
|
478
|
+
}
|
|
479
|
+
],
|
|
480
|
+
)
|
|
413
481
|
|
|
414
|
-
|
|
482
|
+
if "error" in resp:
|
|
483
|
+
raise BundlerRevertError(resp["error"]["message"], userop=user_operation, response=resp)
|
|
484
|
+
|
|
485
|
+
# {
|
|
486
|
+
# "callGasLimit": "0x3dab",
|
|
487
|
+
# "paymasterVerificationGasLimit": "0x9afa",
|
|
488
|
+
# "paymasterPostOpGasLimit": "0x0",
|
|
489
|
+
# "verificationGasLimit": "0xac33",
|
|
490
|
+
# "maxPriorityFeePerGas": "0x7aef40a00",
|
|
491
|
+
# "paymaster": "0x2cc0c7981D846b9F2a16276556f6e8cb52BfB633",
|
|
492
|
+
# "maxFeePerGas": "0xaf9fe62e48",
|
|
493
|
+
# "paymasterData": "0xabcd...",
|
|
494
|
+
# "preVerificationGas": "0xb8ec"
|
|
495
|
+
# }
|
|
496
|
+
|
|
497
|
+
estimation = UserOpEstimation(
|
|
498
|
+
pre_verification_gas=int(resp["result"]["preVerificationGas"], 16),
|
|
499
|
+
verification_gas_limit=int(resp["result"]["verificationGasLimit"], 16),
|
|
500
|
+
call_gas_limit=int(resp["result"]["callGasLimit"], 16),
|
|
501
|
+
paymaster_verification_gas_limit=int(resp["result"]["paymasterVerificationGasLimit"], 16),
|
|
502
|
+
)
|
|
503
|
+
gas_price = GasPrice(
|
|
504
|
+
max_priority_fee_per_gas=int(resp["result"]["maxPriorityFeePerGas"], 16),
|
|
505
|
+
max_fee_per_gas=int(resp["result"]["maxFeePerGas"], 16),
|
|
506
|
+
)
|
|
507
|
+
paymaster_and_data = PaymasterAndData(
|
|
508
|
+
paymaster=resp["result"]["paymaster"],
|
|
509
|
+
paymaster_data=HexBytes(resp["result"]["paymasterData"]),
|
|
510
|
+
paymaster_verification_gas_limit=int(resp["result"]["paymasterVerificationGasLimit"], 16),
|
|
511
|
+
paymaster_post_op_gas_limit=int(resp["result"]["paymasterPostOpGasLimit"], 16),
|
|
512
|
+
)
|
|
513
|
+
return AlchemyGasAndPaymasterAndData(
|
|
514
|
+
estimation=estimation,
|
|
515
|
+
gas_price=gas_price,
|
|
516
|
+
paymaster_and_data=paymaster_and_data,
|
|
517
|
+
)
|
|
415
518
|
|
|
416
519
|
def generic_gas_price(self):
|
|
417
520
|
base_fee = self.get_base_fee()
|
|
@@ -426,21 +529,29 @@ class Bundler:
|
|
|
426
529
|
consume_nonce(nonce_key, nonce)
|
|
427
530
|
|
|
428
531
|
user_operation = UserOperation.from_tx(tx, make_nonce(nonce_key, nonce))
|
|
429
|
-
estimation = self.estimate_user_operation_gas(user_operation)
|
|
430
|
-
|
|
431
|
-
user_operation = user_operation.add_estimation(estimation)
|
|
432
532
|
|
|
433
533
|
if self.bundler_type == "alchemy":
|
|
434
|
-
|
|
534
|
+
estimation_and_paymaster = self.alchemy_estimation(user_operation)
|
|
535
|
+
|
|
536
|
+
user_operation = user_operation.add_estimation(estimation_and_paymaster.estimation)
|
|
537
|
+
user_operation = user_operation.add_gas_price(estimation_and_paymaster.gas_price)
|
|
538
|
+
user_operation = user_operation.add_paymaster_and_data(
|
|
539
|
+
estimation_and_paymaster.paymaster_and_data
|
|
540
|
+
)
|
|
435
541
|
|
|
436
542
|
elif self.bundler_type == "generic":
|
|
543
|
+
estimation = self.estimate_user_operation_gas(user_operation)
|
|
544
|
+
|
|
545
|
+
user_operation = user_operation.add_estimation(estimation)
|
|
546
|
+
|
|
437
547
|
gas_price = self.generic_gas_price()
|
|
438
548
|
|
|
549
|
+
user_operation = user_operation.add_gas_price(gas_price)
|
|
550
|
+
|
|
439
551
|
else:
|
|
440
|
-
|
|
441
|
-
gas_price = GasPrice(0, 0)
|
|
552
|
+
raise BundlerError(f"Unknown bundler_type: {self.bundler_type}")
|
|
442
553
|
|
|
443
|
-
return user_operation
|
|
554
|
+
return user_operation
|
|
444
555
|
|
|
445
556
|
def send_transaction(self, tx: Tx, retry_nonce=None):
|
|
446
557
|
user_operation = self.build_user_operation(tx, retry_nonce).sign(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|