eth-prototype 1.3.0b2__py3-none-any.whl → 1.3.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.3.0b2.dist-info → eth_prototype-1.3.2.dist-info}/METADATA +3 -2
- eth_prototype-1.3.2.dist-info/RECORD +18 -0
- {eth_prototype-1.3.0b2.dist-info → eth_prototype-1.3.2.dist-info}/WHEEL +1 -1
- ethproto/aa_bundler.py +36 -11
- ethproto/build_artifacts.py +118 -1
- ethproto/w3wrappers.py +36 -9
- eth_prototype-1.3.0b2.dist-info/RECORD +0 -18
- {eth_prototype-1.3.0b2.dist-info → eth_prototype-1.3.2.dist-info/licenses}/AUTHORS.rst +0 -0
- {eth_prototype-1.3.0b2.dist-info → eth_prototype-1.3.2.dist-info/licenses}/LICENSE.txt +0 -0
- {eth_prototype-1.3.0b2.dist-info → eth_prototype-1.3.2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: eth-prototype
|
3
|
-
Version: 1.3.
|
3
|
+
Version: 1.3.2
|
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
|
@@ -35,6 +35,7 @@ Requires-Dist: pytest-mock; extra == "testing"
|
|
35
35
|
Requires-Dist: pytest-recording; extra == "testing"
|
36
36
|
Requires-Dist: setuptools; extra == "testing"
|
37
37
|
Requires-Dist: web3[tester]==7.*; extra == "testing"
|
38
|
+
Dynamic: license-file
|
38
39
|
|
39
40
|
# eth-prototype
|
40
41
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
eth_prototype-1.3.2.dist-info/licenses/AUTHORS.rst,sha256=Ui-05yYXtDZxna6o1yNcfdm8Jt68UIDQ01osiLxlYlU,95
|
2
|
+
eth_prototype-1.3.2.dist-info/licenses/LICENSE.txt,sha256=U_Q6_nDYDwZPIuhttHi37hXZ2qU2-HlV2geo9hzHXFw,1087
|
3
|
+
ethproto/__init__.py,sha256=YWkAFysBp4tZjLWWB2FFmp5yG23pUYhQvgQW9b3soXs,579
|
4
|
+
ethproto/aa_bundler.py,sha256=yl-kgLtjIi4ratPquD0B71QtA29SNAwOiIOXNLvxCOk,16780
|
5
|
+
ethproto/build_artifacts.py,sha256=whIXEqnh5f89UYu4Cb3KDigGV7juUCbDnfZkg-SYMKA,9878
|
6
|
+
ethproto/contracts.py,sha256=rNVbCK1hURy7lWKhzSdXgVWo3wx9O_Ghk-6PfgOsRNk,18662
|
7
|
+
ethproto/defender_relay.py,sha256=05A8TfRZwiBhCpo924Pf9CjfKSir2Wvgg1p_asFxJbw,1777
|
8
|
+
ethproto/w3wrappers.py,sha256=aA5yQ25d01s8gtWkGSxSEZlVRdq6JM1ceS3cfvSj4uM,22614
|
9
|
+
ethproto/wadray.py,sha256=JBsu5KcyU9k70bDK03T2IY6qPVFO30WbYPhwrAHdXao,8262
|
10
|
+
ethproto/wrappers.py,sha256=Mj2sgZmcLVmqsnNab6PqIXtNMMPyRVvUj2_8ButEd4w,17304
|
11
|
+
ethproto/test_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
+
ethproto/test_utils/factories.py,sha256=G8DnUDG_yThRxMTCkymzcjm9lR_ni0_ZmTsb3sEfIdI,1805
|
13
|
+
ethproto/test_utils/hardhat.py,sha256=HzTqIznu6zVd_-doL96ftFJ235ktDCQen1QDQbNuwfM,2361
|
14
|
+
ethproto/test_utils/vcr_utils.py,sha256=1FH2sgJlElSjWkJLuO3C7E2J-4HKyFvjAqkCnGRZJyk,797
|
15
|
+
eth_prototype-1.3.2.dist-info/METADATA,sha256=vkIpd-qbMF_GtzUe4TW2_rwV9ypTQqxDW3V9uDhtIR8,2650
|
16
|
+
eth_prototype-1.3.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
17
|
+
eth_prototype-1.3.2.dist-info/top_level.txt,sha256=Dl0X7m6N1hxeo4JpGpSNqWC2gtsN0731g-DL1J0mpjc,9
|
18
|
+
eth_prototype-1.3.2.dist-info/RECORD,,
|
ethproto/aa_bundler.py
CHANGED
@@ -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
|
|
@@ -30,6 +30,8 @@ AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR = env.float("AA_BUNDLER_PRIORITY_GAS_PRICE_
|
|
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
32
|
|
33
|
+
AA_BUNDLER_STATE_OVERRIDES = env.json("AA_BUNDLER_STATE_OVERRIDES", default={})
|
34
|
+
|
33
35
|
NonceMode = Enum(
|
34
36
|
"NonceMode",
|
35
37
|
[
|
@@ -41,7 +43,7 @@ NonceMode = Enum(
|
|
41
43
|
],
|
42
44
|
)
|
43
45
|
|
44
|
-
AA_BUNDLER_NONCE_MODE = env.enum("AA_BUNDLER_NONCE_MODE", default="FIXED_KEY_LOCAL_NONCE",
|
46
|
+
AA_BUNDLER_NONCE_MODE = env.enum("AA_BUNDLER_NONCE_MODE", default="FIXED_KEY_LOCAL_NONCE", enum=NonceMode)
|
45
47
|
AA_BUNDLER_NONCE_KEY = env.int("AA_BUNDLER_NONCE_KEY", 0)
|
46
48
|
AA_BUNDLER_MAX_GETNONCE_RETRIES = env.int("AA_BUNDLER_MAX_GETNONCE_RETRIES", 3)
|
47
49
|
|
@@ -68,6 +70,16 @@ DUMMY_SIGNATURE = HexBytes(
|
|
68
70
|
)
|
69
71
|
|
70
72
|
|
73
|
+
class BundlerRevertError(RevertError):
|
74
|
+
"""Bundler specific revert error"""
|
75
|
+
|
76
|
+
def __init__(self, message, userop=None, response=None):
|
77
|
+
super().__init__(message)
|
78
|
+
self.message = message
|
79
|
+
self.userop = userop
|
80
|
+
self.response = response
|
81
|
+
|
82
|
+
|
71
83
|
@dataclass(frozen=True)
|
72
84
|
class UserOpEstimation:
|
73
85
|
"""eth_estimateUserOperationGas response"""
|
@@ -288,11 +300,11 @@ def check_nonce_error(resp, retry_nonce):
|
|
288
300
|
if "AA25" in resp["error"]["message"] and AA_BUNDLER_MAX_GETNONCE_RETRIES > 0:
|
289
301
|
# Retry fetching the nonce
|
290
302
|
if retry_nonce == AA_BUNDLER_MAX_GETNONCE_RETRIES:
|
291
|
-
raise
|
303
|
+
raise BundlerRevertError(resp["error"]["message"], response=resp)
|
292
304
|
warn(f'{resp["error"]["message"]} error, I will retry fetching the nonce')
|
293
305
|
return (retry_nonce or 0) + 1
|
294
306
|
else:
|
295
|
-
raise
|
307
|
+
raise BundlerRevertError(resp["error"]["message"], response=resp)
|
296
308
|
|
297
309
|
|
298
310
|
def get_sender(tx):
|
@@ -318,6 +330,7 @@ class Bundler:
|
|
318
330
|
priority_gas_price_factor: float = AA_BUNDLER_PRIORITY_GAS_PRICE_FACTOR,
|
319
331
|
base_gas_price_factor: float = AA_BUNDLER_BASE_GAS_PRICE_FACTOR,
|
320
332
|
executor_pk: HexBytes = AA_BUNDLER_EXECUTOR_PK,
|
333
|
+
overrides: StateOverride = AA_BUNDLER_STATE_OVERRIDES,
|
321
334
|
):
|
322
335
|
self.w3 = w3
|
323
336
|
self.bundler = Web3(Web3.HTTPProvider(bundler_url), middleware=[])
|
@@ -331,11 +344,15 @@ class Bundler:
|
|
331
344
|
self.base_gas_price_factor = base_gas_price_factor
|
332
345
|
self.executor_pk = executor_pk
|
333
346
|
|
347
|
+
# stateOverrideSet mapping to use when calling eth_estimateUserOperationGas
|
348
|
+
# https://docs.alchemy.com/reference/eth-estimateuseroperationgas
|
349
|
+
self.overrides = overrides
|
350
|
+
|
334
351
|
def __str__(self):
|
335
352
|
return (
|
336
|
-
f"Bundler(type={self.bundler_type}, entrypoint={self.entrypoint}, nonce_mode={self.nonce_mode}"
|
337
|
-
f"fixed_nonce_key={self.fixed_nonce_key}, verification_gas_factor={self.verification_gas_factor},"
|
338
|
-
f"gas_limit_factor={self.gas_limit_factor}, priority_gas_price_factor={self.priority_gas_price_factor},"
|
353
|
+
f"Bundler(type={self.bundler_type}, entrypoint={self.entrypoint}, nonce_mode={self.nonce_mode}, "
|
354
|
+
f"fixed_nonce_key={self.fixed_nonce_key}, verification_gas_factor={self.verification_gas_factor}, "
|
355
|
+
f"gas_limit_factor={self.gas_limit_factor}, priority_gas_price_factor={self.priority_gas_price_factor}, "
|
339
356
|
f"base_gas_price_factor={self.base_gas_price_factor})"
|
340
357
|
)
|
341
358
|
|
@@ -364,10 +381,11 @@ class Bundler:
|
|
364
381
|
|
365
382
|
def estimate_user_operation_gas(self, user_operation: UserOperation) -> UserOpEstimation:
|
366
383
|
resp = self.bundler.provider.make_request(
|
367
|
-
"eth_estimateUserOperationGas",
|
384
|
+
"eth_estimateUserOperationGas",
|
385
|
+
[user_operation.as_reduced_dict(), self.entrypoint, self.overrides],
|
368
386
|
)
|
369
387
|
if "error" in resp:
|
370
|
-
raise
|
388
|
+
raise BundlerRevertError(resp["error"]["message"], user_operation, resp)
|
371
389
|
|
372
390
|
paymaster_verification_gas_limit = resp["result"].get("paymasterVerificationGasLimit", "0x00")
|
373
391
|
return UserOpEstimation(
|
@@ -386,7 +404,7 @@ class Bundler:
|
|
386
404
|
def alchemy_gas_price(self):
|
387
405
|
resp = self.bundler.provider.make_request("rundler_maxPriorityFeePerGas", [])
|
388
406
|
if "error" in resp:
|
389
|
-
raise
|
407
|
+
raise BundlerRevertError(resp["error"]["message"], response=resp)
|
390
408
|
max_priority_fee_per_gas = int(int(resp["result"], 16) * self.priority_gas_price_factor)
|
391
409
|
max_fee_per_gas = max_priority_fee_per_gas + self.get_base_fee()
|
392
410
|
|
@@ -424,7 +442,14 @@ class Bundler:
|
|
424
442
|
"eth_sendUserOperation", [user_operation.as_dict(), self.entrypoint]
|
425
443
|
)
|
426
444
|
if "error" in resp:
|
427
|
-
|
445
|
+
try:
|
446
|
+
next_nonce = check_nonce_error(resp, retry_nonce)
|
447
|
+
except BundlerRevertError as e:
|
448
|
+
raise BundlerRevertError(
|
449
|
+
e.message,
|
450
|
+
userop=user_operation,
|
451
|
+
response=e.response,
|
452
|
+
)
|
428
453
|
return self.send_transaction(tx, retry_nonce=next_nonce)
|
429
454
|
|
430
455
|
return {"userOpHash": resp["result"]}
|
ethproto/build_artifacts.py
CHANGED
@@ -6,10 +6,14 @@ import os.path
|
|
6
6
|
import re
|
7
7
|
from dataclasses import dataclass
|
8
8
|
from pathlib import Path
|
9
|
-
from typing import
|
9
|
+
from typing import Tuple, Union
|
10
10
|
|
11
11
|
LIBRARY_PLACEHOLDER_MATCHER = re.compile(r"__\$[0-9a-f]{34}\$__")
|
12
12
|
|
13
|
+
CONTRACT_REF_MATCHER = re.compile(r"^(?:(?P<package>.*)/)?(?P<contract>[^@]+)(?:@(?P<version>.+))?$")
|
14
|
+
|
15
|
+
VERSION_MATCHER = re.compile(r"^\d+\.\d+\.\d+$")
|
16
|
+
|
13
17
|
|
14
18
|
@dataclass
|
15
19
|
class Artifact:
|
@@ -94,6 +98,7 @@ class ArtifactLibrary:
|
|
94
98
|
self.lookup_paths = [Path(p).absolute() for p in paths]
|
95
99
|
self._fullpath_cache = {}
|
96
100
|
self._name_cache = {}
|
101
|
+
self._ref_cache = None
|
97
102
|
|
98
103
|
def get_artifact(self, contract: str) -> Artifact:
|
99
104
|
"""Returns a build artifact by full contract path
|
@@ -139,3 +144,115 @@ class ArtifactLibrary:
|
|
139
144
|
raise FileNotFoundError(f"Could not find artifact for {contract_name} on {self.lookup_paths}")
|
140
145
|
|
141
146
|
return self._name_cache[contract_name]
|
147
|
+
|
148
|
+
def _load_ref_cache(self):
|
149
|
+
self._ref_cache = {}
|
150
|
+
for path in self.lookup_paths:
|
151
|
+
path = Path(path)
|
152
|
+
json_files = path.rglob("*.json")
|
153
|
+
|
154
|
+
for json_file in json_files:
|
155
|
+
# Skip build-info and debug files
|
156
|
+
if json_file.parent.stem == "build-info" or json_file.stem.endswith(".dbg"):
|
157
|
+
continue
|
158
|
+
|
159
|
+
parts = json_file.parts[len(path.parts) - 1 :]
|
160
|
+
|
161
|
+
# Find the first parent named either "build" or "artifacts"
|
162
|
+
try:
|
163
|
+
build_idx = next(i for i, part in enumerate(parts) if part in ("build", "artifacts"))
|
164
|
+
except StopIteration:
|
165
|
+
continue
|
166
|
+
|
167
|
+
if build_idx == 0:
|
168
|
+
# Our lookup path is already a build directory, we're probably looking at a hardhat build output
|
169
|
+
version = "local"
|
170
|
+
else:
|
171
|
+
# If we have a version number right before the build directory, we're probably looking at a
|
172
|
+
# verifiable binaries directory
|
173
|
+
version = parts[build_idx - 1]
|
174
|
+
if not VERSION_MATCHER.match(version):
|
175
|
+
version = "local"
|
176
|
+
|
177
|
+
if version == "local":
|
178
|
+
# For hardhat output dir, package is everything up to "contracts"
|
179
|
+
try:
|
180
|
+
package = "/".join(parts[build_idx + 1 : parts.index("contracts")])
|
181
|
+
except ValueError:
|
182
|
+
# There are exceptions, like @openzeppelin/contracts-upgradeable
|
183
|
+
# For those the package is everythin up to the contract directory
|
184
|
+
package = "/".join(parts[build_idx + 1 : -2])
|
185
|
+
|
186
|
+
else:
|
187
|
+
# For verifiable binaries dir, package is everything up to version
|
188
|
+
package = "/".join(parts[1 : build_idx - 1])
|
189
|
+
|
190
|
+
if json_file.stem not in self._ref_cache:
|
191
|
+
self._ref_cache[json_file.stem] = []
|
192
|
+
self._ref_cache[json_file.stem].append(
|
193
|
+
{
|
194
|
+
"path": json_file,
|
195
|
+
"package": package,
|
196
|
+
"version": version,
|
197
|
+
}
|
198
|
+
)
|
199
|
+
|
200
|
+
def _find_ref(self, contract_ref: str):
|
201
|
+
if self._ref_cache is None:
|
202
|
+
self._load_ref_cache()
|
203
|
+
|
204
|
+
ref_match = CONTRACT_REF_MATCHER.match(contract_ref)
|
205
|
+
if not ref_match:
|
206
|
+
raise ValueError(f"Invalid contract reference: {contract_ref}")
|
207
|
+
|
208
|
+
contract = ref_match.group("contract")
|
209
|
+
if contract not in self._ref_cache:
|
210
|
+
return None
|
211
|
+
|
212
|
+
ref = self._ref_cache[contract]
|
213
|
+
|
214
|
+
package = ref_match.group("package")
|
215
|
+
if package:
|
216
|
+
ref = [r for r in ref if r["package"] == package]
|
217
|
+
|
218
|
+
version = ref_match.group("version")
|
219
|
+
if version:
|
220
|
+
ref = [r for r in ref if r["version"] == version]
|
221
|
+
|
222
|
+
if not ref:
|
223
|
+
return None
|
224
|
+
|
225
|
+
# Sort by version ascending, forcing local to be last
|
226
|
+
ref = sorted(
|
227
|
+
ref,
|
228
|
+
key=lambda x: (
|
229
|
+
x["version"] == "local",
|
230
|
+
tuple(map(int, x["version"].split("."))) if x["version"] != "local" else None,
|
231
|
+
),
|
232
|
+
)[-1]
|
233
|
+
|
234
|
+
return ref
|
235
|
+
|
236
|
+
def get_artifact_by_ref(self, contract_ref: str) -> Artifact:
|
237
|
+
"""Returns a build artifact by looking for a matching contract reference.
|
238
|
+
|
239
|
+
This is compatible with the verifiable binaries structure.
|
240
|
+
|
241
|
+
Accepts the following kind of references:
|
242
|
+
|
243
|
+
- <ContractClass>
|
244
|
+
- <ContractClass>@<version>
|
245
|
+
- <package>/<ContractClass>
|
246
|
+
- <package>/<ContractClass>@<version>
|
247
|
+
|
248
|
+
If version is not specified it uses the latest version available.
|
249
|
+
|
250
|
+
Calling with contract_ref <ContractClass>@local is the same as calling get_artifact_by_name(<ContractClass>).
|
251
|
+
"""
|
252
|
+
ref = self._find_ref(contract_ref)
|
253
|
+
|
254
|
+
if ref is None:
|
255
|
+
raise FileNotFoundError(f"Could not find artifact for {contract_ref} on {self.lookup_paths}")
|
256
|
+
|
257
|
+
with open(ref["path"]) as f:
|
258
|
+
return Artifact(**json.load(f))
|
ethproto/w3wrappers.py
CHANGED
@@ -5,9 +5,10 @@ from typing import Iterator, List, Union
|
|
5
5
|
from environs import Env
|
6
6
|
from eth_account.account import Account, LocalAccount
|
7
7
|
from eth_account.signers.base import BaseAccount
|
8
|
-
from eth_utils
|
8
|
+
from eth_utils import add_0x_prefix, event_abi_to_log_topic
|
9
9
|
from hexbytes import HexBytes
|
10
10
|
from web3.contract import Contract
|
11
|
+
from web3.contract.contract import ContractEvent
|
11
12
|
from web3.exceptions import ContractLogicError, ExtraDataLengthError
|
12
13
|
from web3.middleware import ExtraDataToPOAMiddleware
|
13
14
|
|
@@ -437,7 +438,7 @@ class W3Provider(BaseProvider):
|
|
437
438
|
self.tx_kwargs = tx_kwargs or {}
|
438
439
|
|
439
440
|
def get_contract_def(self, eth_contract):
|
440
|
-
return self.artifact_library.
|
441
|
+
return self.artifact_library.get_artifact_by_ref(eth_contract)
|
441
442
|
|
442
443
|
def get_contract_factory(self, eth_contract):
|
443
444
|
contract_def = self.get_contract_def(eth_contract)
|
@@ -448,7 +449,9 @@ class W3Provider(BaseProvider):
|
|
448
449
|
kwargs["from"] = from_
|
449
450
|
return self.construct(factory, init_params, kwargs)
|
450
451
|
|
451
|
-
def get_events(
|
452
|
+
def get_events(
|
453
|
+
self, eth_wrapper, event_names: Union[list[Union[str, ContractEvent]], str], filter_kwargs=None
|
454
|
+
):
|
452
455
|
"""Returns a list of events given a filter, like this:
|
453
456
|
|
454
457
|
>>> provider.get_events(currencywrapper, "Transfer", dict(from_block=0))
|
@@ -468,12 +471,36 @@ class W3Provider(BaseProvider):
|
|
468
471
|
'blockNumber': 23
|
469
472
|
})]
|
470
473
|
"""
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
474
|
+
if filter_kwargs is None:
|
475
|
+
filter_kwargs = {}
|
476
|
+
|
477
|
+
if isinstance(event_names, (str, ContractEvent)):
|
478
|
+
# Backwards compatibility, if we don't get a list we're getting a single event name/ref
|
479
|
+
event_names = [event_names]
|
480
|
+
|
481
|
+
topics = {}
|
482
|
+
|
483
|
+
for name in event_names:
|
484
|
+
if isinstance(name, str):
|
485
|
+
# We got a plain event name, let's get the event from the contract
|
486
|
+
event: ContractEvent = getattr(eth_wrapper.contract.events, name)
|
487
|
+
else:
|
488
|
+
# Assume we already got an event reference
|
489
|
+
event: ContractEvent = name
|
490
|
+
|
491
|
+
topics[event.topic] = event
|
492
|
+
|
493
|
+
filter_params = {
|
494
|
+
"fromBlock": filter_kwargs.get("from_block", self.get_first_block(eth_wrapper)),
|
495
|
+
"toBlock": filter_kwargs.get("to_block", "latest"),
|
496
|
+
"address": eth_wrapper.contract.address,
|
497
|
+
"topics": [list(topics.keys())],
|
498
|
+
}
|
499
|
+
|
500
|
+
logs = self.w3.eth.get_logs(filter_params)
|
501
|
+
|
502
|
+
parsed_events = [topics[add_0x_prefix(log["topics"][0].hex())].process_log(log) for log in logs]
|
503
|
+
return parsed_events
|
477
504
|
|
478
505
|
def init_eth_wrapper(self, eth_wrapper, owner, init_params, kwargs):
|
479
506
|
eth_wrapper.owner = self.address_book.get_account(owner)
|
@@ -1,18 +0,0 @@
|
|
1
|
-
ethproto/__init__.py,sha256=YWkAFysBp4tZjLWWB2FFmp5yG23pUYhQvgQW9b3soXs,579
|
2
|
-
ethproto/aa_bundler.py,sha256=HupCu7fRCwlE556WXDqytRU5GEFLdBoFYzjpqDHBtE4,15789
|
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=lmyfJLhQmPYrclmbzzsthH2cShlQb6LwavKq30jqxFE,21651
|
7
|
-
ethproto/wadray.py,sha256=JBsu5KcyU9k70bDK03T2IY6qPVFO30WbYPhwrAHdXao,8262
|
8
|
-
ethproto/wrappers.py,sha256=Mj2sgZmcLVmqsnNab6PqIXtNMMPyRVvUj2_8ButEd4w,17304
|
9
|
-
ethproto/test_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
ethproto/test_utils/factories.py,sha256=G8DnUDG_yThRxMTCkymzcjm9lR_ni0_ZmTsb3sEfIdI,1805
|
11
|
-
ethproto/test_utils/hardhat.py,sha256=HzTqIznu6zVd_-doL96ftFJ235ktDCQen1QDQbNuwfM,2361
|
12
|
-
ethproto/test_utils/vcr_utils.py,sha256=1FH2sgJlElSjWkJLuO3C7E2J-4HKyFvjAqkCnGRZJyk,797
|
13
|
-
eth_prototype-1.3.0b2.dist-info/AUTHORS.rst,sha256=Ui-05yYXtDZxna6o1yNcfdm8Jt68UIDQ01osiLxlYlU,95
|
14
|
-
eth_prototype-1.3.0b2.dist-info/LICENSE.txt,sha256=U_Q6_nDYDwZPIuhttHi37hXZ2qU2-HlV2geo9hzHXFw,1087
|
15
|
-
eth_prototype-1.3.0b2.dist-info/METADATA,sha256=VGLInjZc46w_OraflEsO2vG9yXmA_crJL0DVP5dFLvM,2630
|
16
|
-
eth_prototype-1.3.0b2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
17
|
-
eth_prototype-1.3.0b2.dist-info/top_level.txt,sha256=Dl0X7m6N1hxeo4JpGpSNqWC2gtsN0731g-DL1J0mpjc,9
|
18
|
-
eth_prototype-1.3.0b2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|