eth-prototype 1.3.1__tar.gz → 1.3.3__tar.gz

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.
Files changed (71) hide show
  1. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/PKG-INFO +1 -1
  2. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/eth_prototype.egg-info/PKG-INFO +1 -1
  3. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/aa_bundler.py +47 -13
  4. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/cassettes/test_aa_bundler/test_build_user_operation.yaml +1 -1
  5. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/test_aa_bundler.py +2 -1
  6. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/.coveragerc +0 -0
  7. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/.github/workflows/publish.yaml +0 -0
  8. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/.github/workflows/test.yaml +0 -0
  9. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/.gitignore +0 -0
  10. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/.isort.cfg +0 -0
  11. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/.pre-commit-config.yaml +0 -0
  12. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/.readthedocs.yml +0 -0
  13. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/AUTHORS.rst +0 -0
  14. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/CHANGELOG.rst +0 -0
  15. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/LICENSE.txt +0 -0
  16. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/README.md +0 -0
  17. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/Makefile +0 -0
  18. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/_static/.gitignore +0 -0
  19. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/authors.rst +0 -0
  20. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/changelog.rst +0 -0
  21. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/conf.py +0 -0
  22. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/index.rst +0 -0
  23. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/license.rst +0 -0
  24. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/readme.rst +0 -0
  25. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/docs/requirements.txt +0 -0
  26. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/pyproject.toml +0 -0
  27. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/setup.cfg +0 -0
  28. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/setup.py +0 -0
  29. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/eth_prototype.egg-info/SOURCES.txt +0 -0
  30. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/eth_prototype.egg-info/dependency_links.txt +0 -0
  31. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/eth_prototype.egg-info/not-zip-safe +0 -0
  32. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/eth_prototype.egg-info/requires.txt +0 -0
  33. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/eth_prototype.egg-info/top_level.txt +0 -0
  34. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/__init__.py +0 -0
  35. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/build_artifacts.py +0 -0
  36. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/contracts.py +0 -0
  37. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/defender_relay.py +0 -0
  38. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/test_utils/__init__.py +0 -0
  39. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/test_utils/factories.py +0 -0
  40. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/test_utils/hardhat.py +0 -0
  41. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/test_utils/vcr_utils.py +0 -0
  42. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/w3wrappers.py +0 -0
  43. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/wadray.py +0 -0
  44. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/src/ethproto/wrappers.py +0 -0
  45. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/__init__.py +0 -0
  46. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/conftest.py +0 -0
  47. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/README.md +0 -0
  48. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/artifacts2/TestCurrency.sol/TestCurrency.json +0 -0
  49. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/Count.sol +0 -0
  50. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/Counter.sol +0 -0
  51. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/CounterUpgradeable.sol +0 -0
  52. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/CounterUpgradeableWithLibrary.sol +0 -0
  53. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/CounterWithLibrary.sol +0 -0
  54. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/Datatypes.sol +0 -0
  55. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/EventLauncher.sol +0 -0
  56. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/TestCurrency.sol +0 -0
  57. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/TestCurrencyUUPS.sol +0 -0
  58. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/contracts/TestNFT.sol +0 -0
  59. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/hardhat.config.js +0 -0
  60. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/package-lock.json +0 -0
  61. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/package.json +0 -0
  62. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/verifiable-binaries/@anotherOrg/aPkg/1.0.2/build/contracts/TestCurrency.sol/TestCurrency.json +0 -0
  63. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/verifiable-binaries/@org/pkg/0.2.1/build/contracts/TestCurrency.json +0 -0
  64. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/hardhat-project/verifiable-binaries/@org/pkg/0.3.0/build/contracts/TestCurrency.json +0 -0
  65. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/test_build_artifacts.py +0 -0
  66. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/test_contracts.py +0 -0
  67. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/test_defender.py +0 -0
  68. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/test_time_control.py +0 -0
  69. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/test_w3.py +0 -0
  70. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tests/test_wadray.py +0 -0
  71. {eth_prototype-1.3.1 → eth_prototype-1.3.3}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eth-prototype
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Prototype Ethereum Smart Contracts in Python
5
5
  Home-page: https://github.com/gnarvaja/eth-prototype
6
6
  Author: Guillermo M. Narvaja
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eth-prototype
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Prototype Ethereum Smart Contracts in Python
5
5
  Home-page: https://github.com/gnarvaja/eth-prototype
6
6
  Author: Guillermo M. Narvaja
@@ -14,7 +14,7 @@ from eth_utils import add_0x_prefix, function_signature_to_4byte_selector
14
14
  from hexbytes import HexBytes
15
15
  from web3 import Web3
16
16
  from web3.constants import ADDRESS_ZERO
17
- from web3.types import TxParams
17
+ from web3.types import StateOverride, TxParams
18
18
 
19
19
  from .contracts import RevertError
20
20
 
@@ -29,6 +29,9 @@ AA_BUNDLER_GAS_LIMIT_FACTOR = env.float("AA_BUNDLER_GAS_LIMIT_FACTOR", 1)
29
29
  AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR = env.float("AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR", 1)
30
30
  AA_BUNDLER_BASE_GAS_PRICE_FACTOR = env.float("AA_BUNDLER_BASE_GAS_PRICE_FACTOR", 1)
31
31
  AA_BUNDLER_VERIFICATION_GAS_FACTOR = env.float("AA_BUNDLER_VERIFICATION_GAS_FACTOR", 1)
32
+ AA_BUNDLER_MAX_FEE_PER_GAS = env.int("AA_BUNDLER_MAX_FEE_PER_GAS", 200000000000) # 200 gwei
33
+
34
+ AA_BUNDLER_STATE_OVERRIDES = env.json("AA_BUNDLER_STATE_OVERRIDES", default={})
32
35
 
33
36
  NonceMode = Enum(
34
37
  "NonceMode",
@@ -68,6 +71,16 @@ DUMMY_SIGNATURE = HexBytes(
68
71
  )
69
72
 
70
73
 
74
+ class BundlerRevertError(RevertError):
75
+ """Bundler specific revert error"""
76
+
77
+ def __init__(self, message, userop=None, response=None):
78
+ super().__init__(message)
79
+ self.message = message
80
+ self.userop = userop
81
+ self.response = response
82
+
83
+
71
84
  @dataclass(frozen=True)
72
85
  class UserOpEstimation:
73
86
  """eth_estimateUserOperationGas response"""
@@ -288,11 +301,11 @@ def check_nonce_error(resp, retry_nonce):
288
301
  if "AA25" in resp["error"]["message"] and AA_BUNDLER_MAX_GETNONCE_RETRIES > 0:
289
302
  # Retry fetching the nonce
290
303
  if retry_nonce == AA_BUNDLER_MAX_GETNONCE_RETRIES:
291
- raise RevertError(resp["error"]["message"])
304
+ raise BundlerRevertError(resp["error"]["message"], response=resp)
292
305
  warn(f'{resp["error"]["message"]} error, I will retry fetching the nonce')
293
306
  return (retry_nonce or 0) + 1
294
307
  else:
295
- raise RevertError(resp["error"]["message"])
308
+ raise BundlerRevertError(resp["error"]["message"], response=resp)
296
309
 
297
310
 
298
311
  def get_sender(tx):
@@ -317,7 +330,9 @@ class Bundler:
317
330
  gas_limit_factor: float = AA_BUNDLER_GAS_LIMIT_FACTOR,
318
331
  priority_gas_price_factor: float = AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR,
319
332
  base_gas_price_factor: float = AA_BUNDLER_BASE_GAS_PRICE_FACTOR,
333
+ max_fee_per_gas: int = AA_BUNDLER_MAX_FEE_PER_GAS,
320
334
  executor_pk: HexBytes = AA_BUNDLER_EXECUTOR_PK,
335
+ overrides: StateOverride = AA_BUNDLER_STATE_OVERRIDES,
321
336
  ):
322
337
  self.w3 = w3
323
338
  self.bundler = Web3(Web3.HTTPProvider(bundler_url), middleware=[])
@@ -330,13 +345,18 @@ class Bundler:
330
345
  self.priority_gas_price_factor = priority_gas_price_factor
331
346
  self.base_gas_price_factor = base_gas_price_factor
332
347
  self.executor_pk = executor_pk
348
+ self.max_fee_per_gas = max_fee_per_gas
349
+
350
+ # stateOverrideSet mapping to use when calling eth_estimateUserOperationGas
351
+ # https://docs.alchemy.com/reference/eth-estimateuseroperationgas
352
+ self.overrides = overrides
333
353
 
334
354
  def __str__(self):
335
355
  return (
336
356
  f"Bundler(type={self.bundler_type}, entrypoint={self.entrypoint}, nonce_mode={self.nonce_mode}, "
337
357
  f"fixed_nonce_key={self.fixed_nonce_key}, verification_gas_factor={self.verification_gas_factor}, "
338
358
  f"gas_limit_factor={self.gas_limit_factor}, priority_gas_price_factor={self.priority_gas_price_factor}, "
339
- f"base_gas_price_factor={self.base_gas_price_factor})"
359
+ f"base_gas_price_factor={self.base_gas_price_factor}, max_fee_per_gas={self.max_fee_per_gas})"
340
360
  )
341
361
 
342
362
  def get_nonce_and_key(self, tx: Tx, fetch=False):
@@ -364,10 +384,11 @@ class Bundler:
364
384
 
365
385
  def estimate_user_operation_gas(self, user_operation: UserOperation) -> UserOpEstimation:
366
386
  resp = self.bundler.provider.make_request(
367
- "eth_estimateUserOperationGas", [user_operation.as_reduced_dict(), self.entrypoint]
387
+ "eth_estimateUserOperationGas",
388
+ [user_operation.as_reduced_dict(), self.entrypoint, self.overrides],
368
389
  )
369
390
  if "error" in resp:
370
- raise RevertError(resp["error"]["message"])
391
+ raise BundlerRevertError(resp["error"]["message"], user_operation, resp)
371
392
 
372
393
  paymaster_verification_gas_limit = resp["result"].get("paymasterVerificationGasLimit", "0x00")
373
394
  return UserOpEstimation(
@@ -386,10 +407,17 @@ class Bundler:
386
407
  def alchemy_gas_price(self):
387
408
  resp = self.bundler.provider.make_request("rundler_maxPriorityFeePerGas", [])
388
409
  if "error" in resp:
389
- raise RevertError(resp["error"]["message"])
410
+ raise BundlerRevertError(resp["error"]["message"], response=resp)
390
411
  max_priority_fee_per_gas = int(int(resp["result"], 16) * self.priority_gas_price_factor)
391
- max_fee_per_gas = max_priority_fee_per_gas + self.get_base_fee()
412
+ max_fee_per_gas = min(max_priority_fee_per_gas + self.get_base_fee(), self.max_fee_per_gas)
413
+
414
+ return GasPrice(max_priority_fee_per_gas=max_priority_fee_per_gas, max_fee_per_gas=max_fee_per_gas)
392
415
 
416
+ def generic_gas_price(self):
417
+ base_fee = self.get_base_fee()
418
+ priority_fee = self.w3.eth.max_priority_fee
419
+ max_priority_fee_per_gas = int(priority_fee * self.priority_gas_price_factor)
420
+ max_fee_per_gas = min(max_priority_fee_per_gas + base_fee, self.max_fee_per_gas)
393
421
  return GasPrice(max_priority_fee_per_gas=max_priority_fee_per_gas, max_fee_per_gas=max_fee_per_gas)
394
422
 
395
423
  def build_user_operation(self, tx: Tx, retry_nonce=None) -> UserOperation:
@@ -404,16 +432,15 @@ class Bundler:
404
432
 
405
433
  if self.bundler_type == "alchemy":
406
434
  gas_price = self.alchemy_gas_price()
407
- user_operation = user_operation.add_gas_price(gas_price)
408
435
 
409
436
  elif self.bundler_type == "generic":
410
- # At the moment generic just prices the gas at 0
411
- pass
437
+ gas_price = self.generic_gas_price()
412
438
 
413
439
  else:
414
440
  warn(f"Unknown bundler_type: {self.bundler_type}")
441
+ gas_price = GasPrice(0, 0)
415
442
 
416
- return user_operation
443
+ return user_operation.add_gas_price(gas_price)
417
444
 
418
445
  def send_transaction(self, tx: Tx, retry_nonce=None):
419
446
  user_operation = self.build_user_operation(tx, retry_nonce).sign(
@@ -424,7 +451,14 @@ class Bundler:
424
451
  "eth_sendUserOperation", [user_operation.as_dict(), self.entrypoint]
425
452
  )
426
453
  if "error" in resp:
427
- next_nonce = check_nonce_error(resp, retry_nonce)
454
+ try:
455
+ next_nonce = check_nonce_error(resp, retry_nonce)
456
+ except BundlerRevertError as e:
457
+ raise BundlerRevertError(
458
+ e.message,
459
+ userop=user_operation,
460
+ response=e.response,
461
+ )
428
462
  return self.send_transaction(tx, retry_nonce=next_nonce)
429
463
 
430
464
  return {"userOpHash": resp["result"]}
@@ -23,7 +23,7 @@ interactions:
23
23
  [{"sender": "0xE8B412158c205B0F605e0FC09dCdA27d3F140FE9", "nonce": "0xae85c374ae0606ed34d0ee009a9ca43a757a8a46a324510000000000000000",
24
24
  "callData": "0xb61d27f60000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000007ace242f32208d836a2245df957c08547059bf45ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000",
25
25
  "signature": "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"},
26
- "0x0000000071727De22E5E9d8BAf0edAc6f37da032"], "id": 0}'
26
+ "0x0000000071727De22E5E9d8BAf0edAc6f37da032", {}], "id": 0}'
27
27
  headers:
28
28
  Content-Length:
29
29
  - "885"
@@ -182,7 +182,8 @@ def test_send_transaction():
182
182
 
183
183
  def make_request(method, params):
184
184
  if method == "eth_estimateUserOperationGas":
185
- assert len(params) == 2
185
+ assert len(params) == 3
186
+ assert params[2] == {}
186
187
  assert params[1] == ENTRYPOINT
187
188
  assert params[0] == {
188
189
  "sender": "0xE8B412158c205B0F605e0FC09dCdA27d3F140FE9",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes