eth-prototype 1.2.0b1__py3-none-any.whl → 1.2.1b1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eth-prototype
3
- Version: 1.2.0b1
3
+ Version: 1.2.1b1
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
@@ -0,0 +1,14 @@
1
+ ethproto/__init__.py,sha256=YWkAFysBp4tZjLWWB2FFmp5yG23pUYhQvgQW9b3soXs,579
2
+ ethproto/aa_bundler.py,sha256=k3mUdBXFkD_0NGJkbQeQRGgn0xPvIS6G7mMp5t3VsEA,11104
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=4ZEnJFrc8bV1qHG4dNdom4FL1gEUhgoJORY6cGzlJDk,21549
7
+ ethproto/wadray.py,sha256=JBsu5KcyU9k70bDK03T2IY6qPVFO30WbYPhwrAHdXao,8262
8
+ ethproto/wrappers.py,sha256=9qDwRDOXw3wquzvGfIsub-VPWm98GBWP7dHLFOUPWzg,17307
9
+ eth_prototype-1.2.1b1.dist-info/AUTHORS.rst,sha256=Ui-05yYXtDZxna6o1yNcfdm8Jt68UIDQ01osiLxlYlU,95
10
+ eth_prototype-1.2.1b1.dist-info/LICENSE.txt,sha256=U_Q6_nDYDwZPIuhttHi37hXZ2qU2-HlV2geo9hzHXFw,1087
11
+ eth_prototype-1.2.1b1.dist-info/METADATA,sha256=Tgo1SAw-_6zQBkqK59iLGI9sYMpNg91vBtP6ofWpicc,2484
12
+ eth_prototype-1.2.1b1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
13
+ eth_prototype-1.2.1b1.dist-info/top_level.txt,sha256=Dl0X7m6N1hxeo4JpGpSNqWC2gtsN0731g-DL1J0mpjc,9
14
+ eth_prototype-1.2.1b1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.2)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
ethproto/aa_bundler.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import random
2
+ from collections import defaultdict
2
3
  from enum import Enum
3
4
  from warnings import warn
4
5
 
@@ -22,6 +23,7 @@ AA_BUNDLER_PROVIDER = env.str("AA_BUNDLER_PROVIDER", "alchemy")
22
23
  AA_BUNDLER_GAS_LIMIT_FACTOR = env.float("AA_BUNDLER_GAS_LIMIT_FACTOR", 1)
23
24
  AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR = env.float("AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR", 1)
24
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)
25
27
 
26
28
  NonceMode = Enum(
27
29
  "NonceMode",
@@ -51,7 +53,7 @@ GET_NONCE_ABI = [
51
53
  }
52
54
  ]
53
55
 
54
- NONCE_CACHE = {}
56
+ NONCE_CACHE = defaultdict(lambda: 0)
55
57
  RANDOM_NONCE_KEY = None
56
58
 
57
59
 
@@ -69,6 +71,10 @@ def _to_uint(x):
69
71
  raise RuntimeError(f"Invalid int value {x}")
70
72
 
71
73
 
74
+ def apply_factor(x, factor):
75
+ return int(_to_uint(x) * factor)
76
+
77
+
72
78
  def pack_user_operation(user_operation):
73
79
  # https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/interfaces/PackedUserOperation.sol
74
80
  return {
@@ -153,20 +159,25 @@ def get_nonce_and_key(w3, tx, nonce_mode, entry_point=AA_BUNDLER_ENTRYPOINT, fet
153
159
  if nonce is None:
154
160
  if fetch or nonce_mode == NonceMode.FIXED_KEY_FETCH_ALWAYS:
155
161
  nonce = fetch_nonce(w3, get_sender(tx), entry_point, nonce_key)
156
- elif nonce_key not in NONCE_CACHE:
157
- nonce = 0
158
162
  else:
159
163
  nonce = NONCE_CACHE[nonce_key]
160
164
  return nonce_key, nonce
161
165
 
162
166
 
163
- def handle_response_error(resp, w3, tx, retry_nonce):
167
+ def consume_nonce(nonce_key, nonce):
168
+ NONCE_CACHE[nonce_key] = max(NONCE_CACHE[nonce_key], nonce + 1)
169
+
170
+
171
+ def check_nonce_error(resp, retry_nonce):
172
+ """Returns the next nonce if resp contains a nonce error and retries weren't exhausted
173
+ Raises RevertError otherwise
174
+ """
164
175
  if "AA25" in resp["error"]["message"] and AA_BUNDLER_MAX_GETNONCE_RETRIES > 0:
165
176
  # Retry fetching the nonce
166
177
  if retry_nonce == AA_BUNDLER_MAX_GETNONCE_RETRIES:
167
178
  raise RevertError(resp["error"]["message"])
168
179
  warn(f'{resp["error"]["message"]} error, I will retry fetching the nonce')
169
- return send_transaction(w3, tx, retry_nonce=(retry_nonce or 0) + 1)
180
+ return (retry_nonce or 0) + 1
170
181
  else:
171
182
  raise RevertError(resp["error"]["message"])
172
183
 
@@ -185,7 +196,7 @@ def get_sender(tx):
185
196
  return tx["from"]
186
197
 
187
198
 
188
- def send_transaction(w3, tx, retry_nonce=None):
199
+ def build_user_operation(w3, tx, retry_nonce=None):
189
200
  nonce_key, nonce = get_nonce_and_key(
190
201
  w3, tx, AA_BUNDLER_NONCE_MODE, entry_point=AA_BUNDLER_ENTRYPOINT, fetch=retry_nonce is not None
191
202
  )
@@ -210,18 +221,19 @@ def send_transaction(w3, tx, retry_nonce=None):
210
221
  "eth_estimateUserOperationGas", [user_operation, AA_BUNDLER_ENTRYPOINT]
211
222
  )
212
223
  if "error" in resp:
213
- return handle_response_error(resp, w3, tx, retry_nonce)
224
+ next_nonce = check_nonce_error(resp, retry_nonce)
225
+ return build_user_operation(w3, tx, retry_nonce=next_nonce)
214
226
 
215
227
  user_operation.update(resp["result"])
216
228
 
217
229
  resp = w3.provider.make_request("rundler_maxPriorityFeePerGas", [])
218
230
  if "error" in resp:
219
231
  raise RevertError(resp["error"]["message"])
220
- max_priority_fee_per_gas = int(_to_uint(resp["result"]) * AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR)
232
+ max_priority_fee_per_gas = apply_factor(resp["result"], AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR)
221
233
  user_operation["maxPriorityFeePerGas"] = hex(max_priority_fee_per_gas)
222
234
  user_operation["maxFeePerGas"] = hex(max_priority_fee_per_gas + get_base_fee(w3))
223
235
  user_operation["callGasLimit"] = hex(
224
- int(_to_uint(user_operation["callGasLimit"]) * AA_BUNDLER_GAS_LIMIT_FACTOR)
236
+ apply_factor(user_operation["callGasLimit"], AA_BUNDLER_GAS_LIMIT_FACTOR)
225
237
  )
226
238
  elif AA_BUNDLER_PROVIDER == "gelato":
227
239
  user_operation.update(
@@ -233,21 +245,54 @@ def send_transaction(w3, tx, retry_nonce=None):
233
245
  "maxPriorityFeePerGas": "0x00",
234
246
  }
235
247
  )
236
- user_operation["signature"] = add_0x_prefix(
237
- sign_user_operation(
238
- AA_BUNDLER_EXECUTOR_PK, user_operation, tx["chainId"], AA_BUNDLER_ENTRYPOINT
239
- ).hex()
240
- )
248
+ elif AA_BUNDLER_PROVIDER == "generic":
249
+ resp = w3.provider.make_request(
250
+ "eth_estimateUserOperationGas", [user_operation, AA_BUNDLER_ENTRYPOINT]
251
+ )
252
+ if "error" in resp:
253
+ next_nonce = check_nonce_error(resp, retry_nonce)
254
+ return build_user_operation(w3, tx, retry_nonce=next_nonce)
255
+
256
+ user_operation.update(resp["result"])
257
+
258
+ user_operation["verificationGasLimit"] = apply_factor(
259
+ user_operation["verificationGasLimit"], AA_BUNDLER_VERIFICATION_GAS_FACTOR
260
+ )
261
+ if "maxPriorityFeePerGas" in user_operation:
262
+ user_operation["maxPriorityFeePerGas"] = apply_factor(
263
+ user_operation["maxPriorityFeePerGas"], AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR
264
+ )
265
+
266
+ if "callGasLimit" in user_operation:
267
+ user_operation["callGasLimit"] = apply_factor(
268
+ user_operation["callGasLimit"], AA_BUNDLER_GAS_LIMIT_FACTOR
269
+ )
270
+
271
+ else:
272
+ warn(f"Unknown AA_BUNDLER_PROVIDER: {AA_BUNDLER_PROVIDER}")
273
+
241
274
  # Remove paymaster related fields
242
275
  user_operation.pop("paymaster", None)
243
276
  user_operation.pop("paymasterData", None)
244
277
  user_operation.pop("paymasterVerificationGasLimit", None)
245
278
  user_operation.pop("paymasterPostOpGasLimit", None)
246
279
 
280
+ # Consume the nonce, even if the userop may fail later
281
+ consume_nonce(nonce_key, nonce)
282
+
283
+ return user_operation
284
+
285
+
286
+ def send_transaction(w3, tx, retry_nonce=None):
287
+ user_operation = build_user_operation(w3, tx, retry_nonce)
288
+ user_operation["signature"] = add_0x_prefix(
289
+ sign_user_operation(
290
+ AA_BUNDLER_EXECUTOR_PK, user_operation, tx["chainId"], AA_BUNDLER_ENTRYPOINT
291
+ ).hex()
292
+ )
247
293
  resp = w3.provider.make_request("eth_sendUserOperation", [user_operation, AA_BUNDLER_ENTRYPOINT])
248
294
  if "error" in resp:
249
- return handle_response_error(resp, w3, tx, retry_nonce)
295
+ next_nonce = check_nonce_error(resp, retry_nonce)
296
+ return send_transaction(w3, tx, retry_nonce=next_nonce)
250
297
 
251
- # Store nonce in the cache, so next time uses a new nonce
252
- NONCE_CACHE[nonce_key] = nonce + 1
253
298
  return {"userOpHash": resp["result"]}
ethproto/w3wrappers.py CHANGED
@@ -49,14 +49,21 @@ class W3TimeControl:
49
49
  return self.w3.eth.get_block("latest").timestamp
50
50
 
51
51
 
52
- def register_w3_provider(provider_key="w3", tester=None, provider_kwargs={}):
52
+ def register_w3_provider(provider_key="w3", w3=None, tester=None, provider_kwargs=None):
53
+ if w3 is not None and tester is not None:
54
+ raise ValueError("Cannot inject w3 and use tester at the same time")
55
+
56
+ provider_kwargs = provider_kwargs or {}
53
57
  if tester is None:
54
58
  try:
55
59
  import eth_tester # noqa
56
60
  except ImportError:
57
61
  tester = False
58
62
 
59
- if tester:
63
+ if w3 is not None:
64
+ # the provided w3 instance takes precedence over all other args
65
+ pass
66
+ elif tester:
60
67
  from web3 import Web3
61
68
 
62
69
  w3 = Web3(Web3.EthereumTesterProvider())
@@ -1,14 +0,0 @@
1
- ethproto/__init__.py,sha256=YWkAFysBp4tZjLWWB2FFmp5yG23pUYhQvgQW9b3soXs,579
2
- ethproto/aa_bundler.py,sha256=R4P3o6Cmt05StuVsReMRlhpSTzsGSEhj0Mcfy8HqFv8,9460
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=fEkqvzWFCHirUsfQqyoqsrpDlNfMIgBBik3yTFws8Is,21260
7
- ethproto/wadray.py,sha256=JBsu5KcyU9k70bDK03T2IY6qPVFO30WbYPhwrAHdXao,8262
8
- ethproto/wrappers.py,sha256=9qDwRDOXw3wquzvGfIsub-VPWm98GBWP7dHLFOUPWzg,17307
9
- eth_prototype-1.2.0b1.dist-info/AUTHORS.rst,sha256=Ui-05yYXtDZxna6o1yNcfdm8Jt68UIDQ01osiLxlYlU,95
10
- eth_prototype-1.2.0b1.dist-info/LICENSE.txt,sha256=U_Q6_nDYDwZPIuhttHi37hXZ2qU2-HlV2geo9hzHXFw,1087
11
- eth_prototype-1.2.0b1.dist-info/METADATA,sha256=hz3CfguoZtt1YZck0PhTaVDAcTeX2dlk4MBvcwLobWY,2484
12
- eth_prototype-1.2.0b1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
13
- eth_prototype-1.2.0b1.dist-info/top_level.txt,sha256=Dl0X7m6N1hxeo4JpGpSNqWC2gtsN0731g-DL1J0mpjc,9
14
- eth_prototype-1.2.0b1.dist-info/RECORD,,