web3 6.20.3__py3-none-any.whl → 7.0.0__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.
- ens/__init__.py +13 -2
- ens/_normalization.py +2 -17
- ens/async_ens.py +33 -21
- ens/base_ens.py +3 -1
- ens/ens.py +16 -11
- ens/exceptions.py +16 -29
- ens/specs/nf.json +1 -1
- ens/specs/normalization_spec.json +1 -1
- ens/utils.py +52 -63
- web3/__init__.py +20 -24
- web3/_utils/abi.py +115 -271
- web3/_utils/async_transactions.py +7 -4
- web3/_utils/batching.py +217 -0
- web3/_utils/blocks.py +6 -2
- web3/_utils/caching.py +128 -5
- web3/_utils/compat/__init__.py +2 -3
- web3/_utils/contract_sources/compile_contracts.py +1 -1
- web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
- web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/event_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
- web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
- web3/_utils/contracts.py +130 -236
- web3/_utils/datatypes.py +5 -1
- web3/_utils/decorators.py +13 -23
- web3/_utils/empty.py +1 -1
- web3/_utils/encoding.py +16 -12
- web3/_utils/ens.py +2 -1
- web3/_utils/error_formatters_utils.py +5 -3
- web3/_utils/events.py +66 -69
- web3/_utils/fee_utils.py +1 -3
- web3/_utils/filters.py +24 -22
- web3/_utils/formatters.py +2 -2
- web3/_utils/http.py +5 -3
- web3/_utils/http_session_manager.py +303 -0
- web3/_utils/math.py +14 -15
- web3/_utils/method_formatters.py +34 -36
- web3/_utils/module.py +2 -1
- web3/_utils/module_testing/__init__.py +0 -3
- web3/_utils/module_testing/eth_module.py +695 -643
- web3/_utils/module_testing/module_testing_utils.py +61 -34
- web3/_utils/module_testing/persistent_connection_provider.py +56 -25
- web3/_utils/module_testing/utils.py +258 -0
- web3/_utils/module_testing/web3_module.py +438 -17
- web3/_utils/normalizers.py +13 -11
- web3/_utils/rpc_abi.py +5 -32
- web3/_utils/threads.py +8 -7
- web3/_utils/transactions.py +14 -12
- web3/_utils/type_conversion.py +5 -1
- web3/_utils/validation.py +17 -17
- web3/auto/gethdev.py +7 -2
- web3/beacon/__init__.py +6 -1
- web3/beacon/async_beacon.py +9 -5
- web3/beacon/{main.py → beacon.py} +7 -5
- web3/contract/__init__.py +7 -0
- web3/contract/async_contract.py +47 -46
- web3/contract/base_contract.py +183 -158
- web3/contract/contract.py +49 -43
- web3/contract/utils.py +203 -59
- web3/datastructures.py +79 -31
- web3/eth/__init__.py +7 -0
- web3/eth/async_eth.py +39 -51
- web3/eth/base_eth.py +17 -10
- web3/eth/eth.py +30 -68
- web3/exceptions.py +108 -82
- web3/gas_strategies/time_based.py +8 -6
- web3/geth.py +1 -254
- web3/main.py +75 -122
- web3/manager.py +316 -146
- web3/method.py +38 -31
- web3/middleware/__init__.py +67 -89
- web3/middleware/attrdict.py +36 -49
- web3/middleware/base.py +174 -0
- web3/middleware/buffered_gas_estimate.py +20 -21
- web3/middleware/filter.py +157 -117
- web3/middleware/formatting.py +124 -108
- web3/middleware/gas_price_strategy.py +20 -32
- web3/middleware/names.py +29 -26
- web3/middleware/proof_of_authority.py +68 -0
- web3/middleware/pythonic.py +2 -2
- web3/middleware/signing.py +74 -89
- web3/middleware/stalecheck.py +52 -79
- web3/middleware/validation.py +5 -13
- web3/module.py +54 -10
- web3/providers/__init__.py +10 -6
- web3/providers/async_base.py +117 -39
- web3/providers/auto.py +3 -3
- web3/providers/base.py +89 -33
- web3/providers/eth_tester/__init__.py +5 -0
- web3/providers/eth_tester/defaults.py +1 -64
- web3/providers/eth_tester/main.py +99 -31
- web3/providers/eth_tester/middleware.py +45 -73
- web3/providers/ipc.py +42 -46
- web3/providers/{websocket/websocket.py → legacy_websocket.py} +32 -7
- web3/providers/persistent/__init__.py +22 -0
- web3/providers/persistent/async_ipc.py +153 -0
- web3/providers/{persistent.py → persistent/persistent.py} +106 -25
- web3/providers/persistent/persistent_connection.py +84 -0
- web3/providers/{websocket → persistent}/request_processor.py +94 -32
- web3/providers/persistent/utils.py +43 -0
- web3/providers/{websocket/websocket_v2.py → persistent/websocket.py} +29 -28
- web3/providers/rpc/__init__.py +11 -0
- web3/providers/rpc/async_rpc.py +171 -0
- web3/providers/rpc/rpc.py +179 -0
- web3/providers/rpc/utils.py +92 -0
- web3/testing.py +4 -4
- web3/tools/benchmark/main.py +22 -22
- web3/tools/benchmark/node.py +2 -8
- web3/tools/benchmark/reporting.py +2 -2
- web3/tools/benchmark/utils.py +1 -1
- web3/tracing.py +9 -5
- web3/types.py +30 -107
- web3/utils/__init__.py +58 -5
- web3/utils/abi.py +575 -10
- web3/utils/async_exception_handling.py +19 -7
- web3/utils/caching.py +32 -13
- web3/utils/exception_handling.py +7 -5
- {web3-6.20.3.dist-info → web3-7.0.0.dist-info}/LICENSE +1 -1
- web3-7.0.0.dist-info/METADATA +112 -0
- web3-7.0.0.dist-info/RECORD +167 -0
- {web3-6.20.3.dist-info → web3-7.0.0.dist-info}/top_level.txt +0 -1
- ethpm/__init__.py +0 -20
- ethpm/_utils/__init__.py +0 -0
- ethpm/_utils/backend.py +0 -93
- ethpm/_utils/cache.py +0 -44
- ethpm/_utils/chains.py +0 -119
- ethpm/_utils/contract.py +0 -35
- ethpm/_utils/deployments.py +0 -145
- ethpm/_utils/ipfs.py +0 -116
- ethpm/_utils/protobuf/__init__.py +0 -0
- ethpm/_utils/protobuf/ipfs_file_pb2.py +0 -33
- ethpm/_utils/registry.py +0 -29
- ethpm/assets/__init__.py +0 -0
- ethpm/assets/ens/v3.json +0 -1
- ethpm/assets/escrow/with_bytecode_v3.json +0 -1
- ethpm/assets/ipfs_file.proto +0 -32
- ethpm/assets/owned/output_v3.json +0 -1
- ethpm/assets/owned/with_contract_type_v3.json +0 -1
- ethpm/assets/registry/contracts/Authority.sol +0 -156
- ethpm/assets/registry/contracts/IndexedOrderedSetLib.sol +0 -106
- ethpm/assets/registry/contracts/PackageDB.sol +0 -225
- ethpm/assets/registry/contracts/PackageRegistry.sol +0 -361
- ethpm/assets/registry/contracts/PackageRegistryInterface.sol +0 -97
- ethpm/assets/registry/contracts/ReleaseDB.sol +0 -309
- ethpm/assets/registry/contracts/ReleaseValidator.sol +0 -152
- ethpm/assets/registry/solc_input.json +0 -1
- ethpm/assets/registry/solc_output.json +0 -1
- ethpm/assets/registry/v3.json +0 -1
- ethpm/assets/safe-math-lib/v3-strict-no-deployments.json +0 -1
- ethpm/assets/simple-registry/contracts/Ownable.sol +0 -63
- ethpm/assets/simple-registry/contracts/PackageRegistry.sol +0 -373
- ethpm/assets/simple-registry/contracts/PackageRegistryInterface.sol +0 -96
- ethpm/assets/simple-registry/solc_input.json +0 -33
- ethpm/assets/simple-registry/solc_output.json +0 -1
- ethpm/assets/simple-registry/v3.json +0 -1
- ethpm/assets/standard-token/output_v3.json +0 -1
- ethpm/assets/standard-token/with_bytecode_v3.json +0 -1
- ethpm/assets/vyper_registry/0.1.0.json +0 -1
- ethpm/assets/vyper_registry/registry.vy +0 -216
- ethpm/assets/vyper_registry/registry_with_delete.vy +0 -244
- ethpm/backends/__init__.py +0 -0
- ethpm/backends/base.py +0 -43
- ethpm/backends/http.py +0 -108
- ethpm/backends/ipfs.py +0 -219
- ethpm/backends/registry.py +0 -154
- ethpm/constants.py +0 -17
- ethpm/contract.py +0 -187
- ethpm/dependencies.py +0 -58
- ethpm/deployments.py +0 -80
- ethpm/ethpm-spec/examples/escrow/1.0.0-pretty.json +0 -146
- ethpm/ethpm-spec/examples/escrow/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/escrow/contracts/Escrow.sol +0 -32
- ethpm/ethpm-spec/examples/escrow/contracts/SafeSendLib.sol +0 -20
- ethpm/ethpm-spec/examples/escrow/v3-pretty.json +0 -171
- ethpm/ethpm-spec/examples/escrow/v3.json +0 -1
- ethpm/ethpm-spec/examples/owned/1.0.0-pretty.json +0 -21
- ethpm/ethpm-spec/examples/owned/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/owned/contracts/Owned.sol +0 -12
- ethpm/ethpm-spec/examples/owned/v3-pretty.json +0 -27
- ethpm/ethpm-spec/examples/owned/v3.json +0 -1
- ethpm/ethpm-spec/examples/piper-coin/1.0.0-pretty.json +0 -31
- ethpm/ethpm-spec/examples/piper-coin/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/piper-coin/v3-pretty.json +0 -21
- ethpm/ethpm-spec/examples/piper-coin/v3.json +0 -1
- ethpm/ethpm-spec/examples/safe-math-lib/1.0.0-pretty.json +0 -85
- ethpm/ethpm-spec/examples/safe-math-lib/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/safe-math-lib/contracts/SafeMathLib.sol +0 -24
- ethpm/ethpm-spec/examples/safe-math-lib/v3-pretty.json +0 -117
- ethpm/ethpm-spec/examples/safe-math-lib/v3.json +0 -1
- ethpm/ethpm-spec/examples/standard-token/1.0.0-pretty.json +0 -55
- ethpm/ethpm-spec/examples/standard-token/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/standard-token/contracts/AbstractToken.sol +0 -20
- ethpm/ethpm-spec/examples/standard-token/contracts/StandardToken.sol +0 -84
- ethpm/ethpm-spec/examples/standard-token/v3-pretty.json +0 -460
- ethpm/ethpm-spec/examples/standard-token/v3.json +0 -1
- ethpm/ethpm-spec/examples/transferable/1.0.0-pretty.json +0 -21
- ethpm/ethpm-spec/examples/transferable/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/transferable/contracts/Transferable.sol +0 -14
- ethpm/ethpm-spec/examples/transferable/v3-pretty.json +0 -27
- ethpm/ethpm-spec/examples/transferable/v3.json +0 -1
- ethpm/ethpm-spec/examples/wallet/1.0.0-pretty.json +0 -120
- ethpm/ethpm-spec/examples/wallet/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/wallet/contracts/Wallet.sol +0 -41
- ethpm/ethpm-spec/examples/wallet/v3-pretty.json +0 -181
- ethpm/ethpm-spec/examples/wallet/v3.json +0 -1
- ethpm/ethpm-spec/examples/wallet-with-send/1.0.0-pretty.json +0 -135
- ethpm/ethpm-spec/examples/wallet-with-send/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/wallet-with-send/contracts/WalletWithSend.sol +0 -18
- ethpm/ethpm-spec/examples/wallet-with-send/v3-pretty.json +0 -207
- ethpm/ethpm-spec/examples/wallet-with-send/v3.json +0 -1
- ethpm/ethpm-spec/spec/package.spec.json +0 -379
- ethpm/ethpm-spec/spec/v3.spec.json +0 -483
- ethpm/exceptions.py +0 -68
- ethpm/package.py +0 -438
- ethpm/tools/__init__.py +0 -4
- ethpm/tools/builder.py +0 -930
- ethpm/tools/checker.py +0 -312
- ethpm/tools/get_manifest.py +0 -19
- ethpm/uri.py +0 -141
- ethpm/validation/__init__.py +0 -0
- ethpm/validation/manifest.py +0 -146
- ethpm/validation/misc.py +0 -39
- ethpm/validation/package.py +0 -80
- ethpm/validation/uri.py +0 -163
- web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
- web3/_utils/miner.py +0 -88
- web3/_utils/module_testing/go_ethereum_personal_module.py +0 -323
- web3/_utils/request.py +0 -265
- web3/middleware/abi.py +0 -11
- web3/middleware/async_cache.py +0 -99
- web3/middleware/cache.py +0 -374
- web3/middleware/exception_handling.py +0 -49
- web3/middleware/exception_retry_request.py +0 -188
- web3/middleware/fixture.py +0 -190
- web3/middleware/geth_poa.py +0 -81
- web3/middleware/normalize_request_parameters.py +0 -11
- web3/middleware/simulate_unmined_transaction.py +0 -43
- web3/pm.py +0 -602
- web3/providers/async_rpc.py +0 -99
- web3/providers/rpc.py +0 -98
- web3/providers/websocket/__init__.py +0 -11
- web3/providers/websocket/websocket_connection.py +0 -42
- web3/tools/__init__.py +0 -4
- web3/tools/pytest_ethereum/__init__.py +0 -0
- web3/tools/pytest_ethereum/_utils.py +0 -145
- web3/tools/pytest_ethereum/deployer.py +0 -48
- web3/tools/pytest_ethereum/exceptions.py +0 -22
- web3/tools/pytest_ethereum/linker.py +0 -128
- web3/tools/pytest_ethereum/plugins.py +0 -33
- web3-6.20.3.dist-info/METADATA +0 -104
- web3-6.20.3.dist-info/RECORD +0 -283
- web3-6.20.3.dist-info/entry_points.txt +0 -2
- /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
- {web3-6.20.3.dist-info → web3-7.0.0.dist-info}/WHEEL +0 -0
web3/providers/rpc.py
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import (
|
|
3
|
-
Any,
|
|
4
|
-
Dict,
|
|
5
|
-
Iterable,
|
|
6
|
-
Optional,
|
|
7
|
-
Tuple,
|
|
8
|
-
Union,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
from eth_typing import (
|
|
12
|
-
URI,
|
|
13
|
-
)
|
|
14
|
-
from eth_utils import (
|
|
15
|
-
to_dict,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
from web3._utils.http import (
|
|
19
|
-
construct_user_agent,
|
|
20
|
-
)
|
|
21
|
-
from web3._utils.request import (
|
|
22
|
-
cache_and_return_session,
|
|
23
|
-
get_default_http_endpoint,
|
|
24
|
-
make_post_request,
|
|
25
|
-
)
|
|
26
|
-
from web3.datastructures import (
|
|
27
|
-
NamedElementOnion,
|
|
28
|
-
)
|
|
29
|
-
from web3.middleware import (
|
|
30
|
-
http_retry_request_middleware,
|
|
31
|
-
)
|
|
32
|
-
from web3.types import (
|
|
33
|
-
Middleware,
|
|
34
|
-
RPCEndpoint,
|
|
35
|
-
RPCResponse,
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
from .base import (
|
|
39
|
-
JSONBaseProvider,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class HTTPProvider(JSONBaseProvider):
|
|
44
|
-
logger = logging.getLogger("web3.providers.HTTPProvider")
|
|
45
|
-
endpoint_uri = None
|
|
46
|
-
_request_args = None
|
|
47
|
-
_request_kwargs = None
|
|
48
|
-
# type ignored b/c conflict with _middlewares attr on BaseProvider
|
|
49
|
-
_middlewares: Tuple[Middleware, ...] = NamedElementOnion([(http_retry_request_middleware, "http_retry_request")]) # type: ignore # noqa: E501
|
|
50
|
-
|
|
51
|
-
def __init__(
|
|
52
|
-
self,
|
|
53
|
-
endpoint_uri: Optional[Union[URI, str]] = None,
|
|
54
|
-
request_kwargs: Optional[Any] = None,
|
|
55
|
-
session: Optional[Any] = None,
|
|
56
|
-
) -> None:
|
|
57
|
-
if endpoint_uri is None:
|
|
58
|
-
self.endpoint_uri = get_default_http_endpoint()
|
|
59
|
-
else:
|
|
60
|
-
self.endpoint_uri = URI(endpoint_uri)
|
|
61
|
-
|
|
62
|
-
self._request_kwargs = request_kwargs or {}
|
|
63
|
-
|
|
64
|
-
if session:
|
|
65
|
-
cache_and_return_session(self.endpoint_uri, session)
|
|
66
|
-
|
|
67
|
-
super().__init__()
|
|
68
|
-
|
|
69
|
-
def __str__(self) -> str:
|
|
70
|
-
return f"RPC connection {self.endpoint_uri}"
|
|
71
|
-
|
|
72
|
-
@to_dict
|
|
73
|
-
def get_request_kwargs(self) -> Iterable[Tuple[str, Any]]:
|
|
74
|
-
if "headers" not in self._request_kwargs:
|
|
75
|
-
yield "headers", self.get_request_headers()
|
|
76
|
-
for key, value in self._request_kwargs.items():
|
|
77
|
-
yield key, value
|
|
78
|
-
|
|
79
|
-
def get_request_headers(self) -> Dict[str, str]:
|
|
80
|
-
return {
|
|
81
|
-
"Content-Type": "application/json",
|
|
82
|
-
"User-Agent": construct_user_agent(str(type(self))),
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
86
|
-
self.logger.debug(
|
|
87
|
-
f"Making request HTTP. URI: {self.endpoint_uri}, Method: {method}"
|
|
88
|
-
)
|
|
89
|
-
request_data = self.encode_rpc_request(method, params)
|
|
90
|
-
raw_response = make_post_request(
|
|
91
|
-
self.endpoint_uri, request_data, **self.get_request_kwargs()
|
|
92
|
-
)
|
|
93
|
-
response = self.decode_rpc_response(raw_response)
|
|
94
|
-
self.logger.debug(
|
|
95
|
-
f"Getting response HTTP. URI: {self.endpoint_uri}, "
|
|
96
|
-
f"Method: {method}, Response: {response}"
|
|
97
|
-
)
|
|
98
|
-
return response
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
from typing import (
|
|
2
|
-
TYPE_CHECKING,
|
|
3
|
-
Any,
|
|
4
|
-
Dict,
|
|
5
|
-
)
|
|
6
|
-
|
|
7
|
-
from web3.types import (
|
|
8
|
-
RPCEndpoint,
|
|
9
|
-
RPCResponse,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from web3.main import ( # noqa: F401
|
|
14
|
-
_PersistentConnectionWeb3,
|
|
15
|
-
)
|
|
16
|
-
from web3.manager import ( # noqa: F401
|
|
17
|
-
_AsyncPersistentMessageStream,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class WebsocketConnection:
|
|
22
|
-
"""
|
|
23
|
-
A class that houses the public API for interacting with the websocket connection
|
|
24
|
-
via a `_PersistentConnectionWeb3` instance.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
def __init__(self, w3: "_PersistentConnectionWeb3"):
|
|
28
|
-
self._manager = w3.manager
|
|
29
|
-
|
|
30
|
-
# -- public methods -- #
|
|
31
|
-
@property
|
|
32
|
-
def subscriptions(self) -> Dict[str, Any]:
|
|
33
|
-
return self._manager._request_processor.active_subscriptions
|
|
34
|
-
|
|
35
|
-
async def send(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
36
|
-
return await self._manager.ws_send(method, params)
|
|
37
|
-
|
|
38
|
-
async def recv(self) -> Any:
|
|
39
|
-
return await self._manager._get_next_ws_message()
|
|
40
|
-
|
|
41
|
-
def process_subscriptions(self) -> "_AsyncPersistentMessageStream":
|
|
42
|
-
return self._manager._persistent_message_stream()
|
web3/tools/__init__.py
DELETED
|
File without changes
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
from typing import (
|
|
2
|
-
Any,
|
|
3
|
-
Dict,
|
|
4
|
-
Iterable,
|
|
5
|
-
List,
|
|
6
|
-
Tuple,
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
from eth_typing import (
|
|
10
|
-
URI,
|
|
11
|
-
Address,
|
|
12
|
-
ContractName,
|
|
13
|
-
Manifest,
|
|
14
|
-
)
|
|
15
|
-
from eth_utils import (
|
|
16
|
-
to_dict,
|
|
17
|
-
to_hex,
|
|
18
|
-
to_list,
|
|
19
|
-
)
|
|
20
|
-
from eth_utils.toolz import (
|
|
21
|
-
assoc,
|
|
22
|
-
assoc_in,
|
|
23
|
-
dissoc,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
from ethpm import (
|
|
27
|
-
Package,
|
|
28
|
-
)
|
|
29
|
-
from ethpm.uri import (
|
|
30
|
-
check_if_chain_matches_chain_uri,
|
|
31
|
-
)
|
|
32
|
-
from web3 import (
|
|
33
|
-
Web3,
|
|
34
|
-
)
|
|
35
|
-
from web3.tools.pytest_ethereum.exceptions import (
|
|
36
|
-
LinkerError,
|
|
37
|
-
)
|
|
38
|
-
from web3.types import (
|
|
39
|
-
TxReceipt,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def pluck_matching_uri(deployment_data: Dict[URI, Dict[str, str]], w3: Web3) -> URI:
|
|
44
|
-
"""
|
|
45
|
-
Return any blockchain uri that matches w3-connected chain, if one
|
|
46
|
-
is present in the deployment data keys.
|
|
47
|
-
"""
|
|
48
|
-
for uri in deployment_data.keys():
|
|
49
|
-
if check_if_chain_matches_chain_uri(w3, uri):
|
|
50
|
-
return uri
|
|
51
|
-
raise LinkerError(
|
|
52
|
-
"No matching blockchain URI found in deployment_data: "
|
|
53
|
-
f"{list(deployment_data.keys())}, for w3 instance: {w3.__repr__()}."
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def contains_matching_uri(deployment_data: Dict[str, Dict[str, str]], w3: Web3) -> bool:
|
|
58
|
-
"""
|
|
59
|
-
Returns true if any blockchain uri in deployment data matches
|
|
60
|
-
w3-connected chain.
|
|
61
|
-
"""
|
|
62
|
-
for uri in deployment_data.keys():
|
|
63
|
-
if check_if_chain_matches_chain_uri(w3, uri):
|
|
64
|
-
return True
|
|
65
|
-
return False
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def insert_deployment(
|
|
69
|
-
package: Package,
|
|
70
|
-
deployment_name: str,
|
|
71
|
-
deployment_data: Dict[str, str],
|
|
72
|
-
latest_block_uri: URI,
|
|
73
|
-
) -> Manifest:
|
|
74
|
-
"""
|
|
75
|
-
Returns a new manifest. If a matching chain uri is found
|
|
76
|
-
in the old manifest, it will update the chain uri along
|
|
77
|
-
with the new deployment data. If no match, it will simply add
|
|
78
|
-
the new chain uri and deployment data.
|
|
79
|
-
"""
|
|
80
|
-
old_deployments_data = package.manifest.get("deployments")
|
|
81
|
-
if old_deployments_data and contains_matching_uri(old_deployments_data, package.w3):
|
|
82
|
-
old_chain_uri = pluck_matching_uri(old_deployments_data, package.w3)
|
|
83
|
-
old_deployments_chain_data = old_deployments_data[old_chain_uri]
|
|
84
|
-
# Replace specific on-chain deployment (i.e. deployment_name)
|
|
85
|
-
new_deployments_chain_data_init = dissoc(
|
|
86
|
-
old_deployments_chain_data, deployment_name
|
|
87
|
-
)
|
|
88
|
-
new_deployments_chain_data = {
|
|
89
|
-
**new_deployments_chain_data_init,
|
|
90
|
-
**{deployment_name: deployment_data},
|
|
91
|
-
}
|
|
92
|
-
# Replace all on-chain deployments
|
|
93
|
-
new_deployments_data_init = dissoc(
|
|
94
|
-
old_deployments_data, "deployments", old_chain_uri
|
|
95
|
-
)
|
|
96
|
-
new_deployments_data = {
|
|
97
|
-
**new_deployments_data_init,
|
|
98
|
-
**{latest_block_uri: new_deployments_chain_data},
|
|
99
|
-
}
|
|
100
|
-
return assoc(package.manifest, "deployments", new_deployments_data)
|
|
101
|
-
|
|
102
|
-
return assoc_in(
|
|
103
|
-
package.manifest,
|
|
104
|
-
("deployments", latest_block_uri, deployment_name),
|
|
105
|
-
deployment_data,
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@to_dict
|
|
110
|
-
def create_deployment_data(
|
|
111
|
-
contract_name: ContractName,
|
|
112
|
-
new_address: Address,
|
|
113
|
-
tx_receipt: TxReceipt,
|
|
114
|
-
link_refs: List[Dict[str, Any]] = None,
|
|
115
|
-
) -> Iterable[Tuple[str, Any]]:
|
|
116
|
-
yield "contractType", contract_name
|
|
117
|
-
yield "address", new_address
|
|
118
|
-
yield "transaction", to_hex(tx_receipt["transactionHash"])
|
|
119
|
-
yield "block", to_hex(tx_receipt["blockHash"])
|
|
120
|
-
if link_refs:
|
|
121
|
-
yield "runtimeBytecode", {"linkDependencies": create_link_dep(link_refs)}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
@to_list
|
|
125
|
-
def create_link_dep(link_refs: List[Dict[str, Any]]) -> Iterable[Dict[str, Any]]:
|
|
126
|
-
for link_ref in link_refs:
|
|
127
|
-
yield {
|
|
128
|
-
"offsets": link_ref["offsets"],
|
|
129
|
-
"type": "reference",
|
|
130
|
-
"value": link_ref["name"],
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def get_deployment_address(linked_type: str, package: Package) -> Address:
|
|
135
|
-
"""
|
|
136
|
-
Return the address of a linked_type found in a package's manifest deployments.
|
|
137
|
-
"""
|
|
138
|
-
try:
|
|
139
|
-
deployment_address = package.deployments.get(linked_type)["address"]
|
|
140
|
-
except KeyError:
|
|
141
|
-
raise LinkerError(
|
|
142
|
-
f"Package data does not contain a valid deployment of {linked_type} on the "
|
|
143
|
-
"current w3-connected chain."
|
|
144
|
-
)
|
|
145
|
-
return deployment_address
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
from typing import (
|
|
2
|
-
Any,
|
|
3
|
-
Callable,
|
|
4
|
-
Dict,
|
|
5
|
-
)
|
|
6
|
-
|
|
7
|
-
from eth_typing import (
|
|
8
|
-
ContractName,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
from ethpm import (
|
|
12
|
-
Package,
|
|
13
|
-
)
|
|
14
|
-
from web3.tools.pytest_ethereum.exceptions import (
|
|
15
|
-
DeployerError,
|
|
16
|
-
)
|
|
17
|
-
from web3.tools.pytest_ethereum.linker import (
|
|
18
|
-
deploy,
|
|
19
|
-
linker,
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class Deployer:
|
|
24
|
-
def __init__(self, package: Package) -> None:
|
|
25
|
-
if not isinstance(package, Package):
|
|
26
|
-
raise TypeError(
|
|
27
|
-
f"Expected a Package object, instead received {type(package)}."
|
|
28
|
-
)
|
|
29
|
-
self.package = package
|
|
30
|
-
self.strategies: Dict[str, Callable[[Package], Package]] = {}
|
|
31
|
-
|
|
32
|
-
def deploy(self, contract_type: ContractName, *args: Any, **kwargs: Any) -> Package:
|
|
33
|
-
factory = self.package.get_contract_factory(contract_type)
|
|
34
|
-
if contract_type in self.strategies:
|
|
35
|
-
strategy = self.strategies[contract_type]
|
|
36
|
-
return strategy(self.package)
|
|
37
|
-
if factory.needs_bytecode_linking:
|
|
38
|
-
raise DeployerError(
|
|
39
|
-
"Unable to deploy an unlinked factory. "
|
|
40
|
-
"Please register a strategy for this contract type."
|
|
41
|
-
)
|
|
42
|
-
strategy = linker(deploy(contract_type, *args, **kwargs))
|
|
43
|
-
return strategy(self.package)
|
|
44
|
-
|
|
45
|
-
def register_strategy(
|
|
46
|
-
self, contract_type: ContractName, strategy: Callable[[Package], Package]
|
|
47
|
-
) -> None:
|
|
48
|
-
self.strategies[contract_type] = strategy
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
class PytestEthereumError(Exception):
|
|
2
|
-
"""
|
|
3
|
-
Base class for all Pytest-Ethereum errors.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
pass
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class DeployerError(PytestEthereumError):
|
|
10
|
-
"""
|
|
11
|
-
Raised when the Deployer is unable to deploy a contract type.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class LinkerError(PytestEthereumError):
|
|
18
|
-
"""
|
|
19
|
-
Raised when the Linker is unable to link two contract types.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
pass
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import (
|
|
3
|
-
Any,
|
|
4
|
-
Callable,
|
|
5
|
-
Dict,
|
|
6
|
-
)
|
|
7
|
-
|
|
8
|
-
from eth_typing import (
|
|
9
|
-
ContractName,
|
|
10
|
-
)
|
|
11
|
-
from eth_utils import (
|
|
12
|
-
to_checksum_address,
|
|
13
|
-
to_hex,
|
|
14
|
-
)
|
|
15
|
-
from eth_utils.toolz import (
|
|
16
|
-
assoc_in,
|
|
17
|
-
curry,
|
|
18
|
-
pipe,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
from ethpm import (
|
|
22
|
-
Package,
|
|
23
|
-
)
|
|
24
|
-
from ethpm.uri import (
|
|
25
|
-
create_latest_block_uri,
|
|
26
|
-
)
|
|
27
|
-
from web3.tools.pytest_ethereum._utils import (
|
|
28
|
-
create_deployment_data,
|
|
29
|
-
get_deployment_address,
|
|
30
|
-
insert_deployment,
|
|
31
|
-
)
|
|
32
|
-
from web3.tools.pytest_ethereum.exceptions import (
|
|
33
|
-
LinkerError,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
logger = logging.getLogger("pytest_ethereum.linker")
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def linker(*args: Callable[..., Any]) -> Callable[..., Any]:
|
|
40
|
-
return _linker(args)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@curry
|
|
44
|
-
def _linker(operations: Callable[..., Any], package: Package) -> Callable[..., Package]:
|
|
45
|
-
return pipe(package, *operations)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def deploy(
|
|
49
|
-
contract_name: str, *args: Any, transaction: Dict[str, Any] = None
|
|
50
|
-
) -> Callable[..., Package]:
|
|
51
|
-
"""
|
|
52
|
-
Return a newly created package and contract address.
|
|
53
|
-
Will deploy the given contract_name, if data exists in package. If
|
|
54
|
-
a deployment is found on the current w3 instance, it will return that deployment
|
|
55
|
-
rather than creating a new instance.
|
|
56
|
-
"""
|
|
57
|
-
return _deploy(contract_name, args, transaction)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@curry
|
|
61
|
-
def _deploy(
|
|
62
|
-
contract_name: ContractName,
|
|
63
|
-
args: Any,
|
|
64
|
-
transaction: Dict[str, Any],
|
|
65
|
-
package: Package,
|
|
66
|
-
) -> Package:
|
|
67
|
-
# Deploy new instance
|
|
68
|
-
factory = package.get_contract_factory(contract_name)
|
|
69
|
-
if not factory.linked_references and factory.unlinked_references:
|
|
70
|
-
raise LinkerError(
|
|
71
|
-
f"Contract factory: {contract_name} is missing runtime link references, "
|
|
72
|
-
"which are necessary to populate manifest deployments that have a link "
|
|
73
|
-
"reference. If using the builder tool, use "
|
|
74
|
-
"`contract_type(..., runtime_bytecode=True)`."
|
|
75
|
-
)
|
|
76
|
-
tx_hash = factory.constructor(*args).transact(transaction)
|
|
77
|
-
tx_receipt = package.w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
78
|
-
# Create manifest copy with new deployment instance
|
|
79
|
-
latest_block_uri = create_latest_block_uri(package.w3, 0)
|
|
80
|
-
deployment_data = create_deployment_data(
|
|
81
|
-
contract_name,
|
|
82
|
-
to_checksum_address(tx_receipt["contractAddress"]),
|
|
83
|
-
tx_receipt,
|
|
84
|
-
factory.linked_references,
|
|
85
|
-
)
|
|
86
|
-
manifest = insert_deployment(
|
|
87
|
-
package, contract_name, deployment_data, latest_block_uri
|
|
88
|
-
)
|
|
89
|
-
logger.info(f"{contract_name} deployed.")
|
|
90
|
-
return Package(manifest, package.w3)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@curry
|
|
94
|
-
def link(contract: ContractName, linked_type: str, package: Package) -> Package:
|
|
95
|
-
"""
|
|
96
|
-
Return a new package, created with a new manifest after applying the linked type
|
|
97
|
-
reference to the contract factory.
|
|
98
|
-
"""
|
|
99
|
-
deployment_address = get_deployment_address(linked_type, package)
|
|
100
|
-
unlinked_factory = package.get_contract_factory(contract)
|
|
101
|
-
if not unlinked_factory.needs_bytecode_linking:
|
|
102
|
-
raise LinkerError(
|
|
103
|
-
f"Contract factory: {unlinked_factory.__repr__()} does not need "
|
|
104
|
-
"bytecode linking, so it is not a valid contract type for link()"
|
|
105
|
-
)
|
|
106
|
-
linked_factory = unlinked_factory.link_bytecode({linked_type: deployment_address})
|
|
107
|
-
# todo replace runtime_bytecode in manifest
|
|
108
|
-
manifest = assoc_in(
|
|
109
|
-
package.manifest,
|
|
110
|
-
("contractTypes", contract, "deploymentBytecode", "bytecode"),
|
|
111
|
-
to_hex(linked_factory.bytecode),
|
|
112
|
-
)
|
|
113
|
-
logger.info(
|
|
114
|
-
f"{contract} linked to {linked_type} at address "
|
|
115
|
-
f"{to_checksum_address(deployment_address)}."
|
|
116
|
-
)
|
|
117
|
-
return Package(manifest, package.w3)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@curry
|
|
121
|
-
def run_python(callback_fn: Callable[..., None], package: Package) -> Package:
|
|
122
|
-
"""
|
|
123
|
-
Return the unmodified package, after performing any user-defined
|
|
124
|
-
callback function on the contracts in the package.
|
|
125
|
-
"""
|
|
126
|
-
callback_fn(package)
|
|
127
|
-
logger.info(f"{callback_fn.__name__} python function ran.")
|
|
128
|
-
return package
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from pathlib import (
|
|
3
|
-
Path,
|
|
4
|
-
)
|
|
5
|
-
import pytest
|
|
6
|
-
from typing import (
|
|
7
|
-
Callable,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
from ethpm import (
|
|
11
|
-
Package,
|
|
12
|
-
)
|
|
13
|
-
from web3 import (
|
|
14
|
-
Web3,
|
|
15
|
-
)
|
|
16
|
-
from web3.tools.pytest_ethereum.deployer import (
|
|
17
|
-
Deployer,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@pytest.fixture
|
|
22
|
-
def deployer(w3: Web3) -> Callable[[Path], Deployer]:
|
|
23
|
-
"""
|
|
24
|
-
Returns a `Deployer` instance composed from a `Package` instance
|
|
25
|
-
generated from the manifest located at the provided `path` folder.
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
def _deployer(path: Path) -> Deployer:
|
|
29
|
-
manifest = json.loads(path.read_text())
|
|
30
|
-
package = Package(manifest, w3)
|
|
31
|
-
return Deployer(package)
|
|
32
|
-
|
|
33
|
-
return _deployer
|
web3-6.20.3.dist-info/METADATA
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: web3
|
|
3
|
-
Version: 6.20.3
|
|
4
|
-
Summary: web3.py
|
|
5
|
-
Home-page: https://github.com/ethereum/web3.py
|
|
6
|
-
Author: The Ethereum Foundation
|
|
7
|
-
Author-email: snakecharmers@ethereum.org
|
|
8
|
-
License: MIT
|
|
9
|
-
Keywords: ethereum
|
|
10
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
-
Classifier: Natural Language :: English
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Requires-Python: >=3.7.2
|
|
21
|
-
Description-Content-Type: text/markdown
|
|
22
|
-
License-File: LICENSE
|
|
23
|
-
Requires-Dist: aiohttp >=3.7.4.post0
|
|
24
|
-
Requires-Dist: ckzg <2
|
|
25
|
-
Requires-Dist: eth-abi >=4.0.0
|
|
26
|
-
Requires-Dist: eth-account <0.13,>=0.8.0
|
|
27
|
-
Requires-Dist: eth-hash[pycryptodome] >=0.5.1
|
|
28
|
-
Requires-Dist: eth-typing !=4.2.0,<5.0.0,>=3.0.0
|
|
29
|
-
Requires-Dist: eth-utils <5,>=2.1.0
|
|
30
|
-
Requires-Dist: hexbytes <0.4.0,>=0.1.0
|
|
31
|
-
Requires-Dist: jsonschema >=4.0.0
|
|
32
|
-
Requires-Dist: lru-dict <1.3.0,>=1.1.6
|
|
33
|
-
Requires-Dist: protobuf >=4.21.6
|
|
34
|
-
Requires-Dist: requests >=2.16.0
|
|
35
|
-
Requires-Dist: typing-extensions >=4.0.1
|
|
36
|
-
Requires-Dist: websockets >=10.0.0
|
|
37
|
-
Requires-Dist: pyunormalize >=15.0.0
|
|
38
|
-
Requires-Dist: pywin32 >=223 ; platform_system == "Windows"
|
|
39
|
-
Provides-Extra: dev
|
|
40
|
-
Requires-Dist: py-geth <4,>=3.14.0 ; extra == 'dev'
|
|
41
|
-
Requires-Dist: sphinx >=5.3.0 ; extra == 'dev'
|
|
42
|
-
Requires-Dist: sphinx-rtd-theme >=1.0.0 ; extra == 'dev'
|
|
43
|
-
Requires-Dist: towncrier <22,>=21 ; extra == 'dev'
|
|
44
|
-
Requires-Dist: ipfshttpclient ==0.8.0a2 ; extra == 'dev'
|
|
45
|
-
Requires-Dist: bumpversion ; extra == 'dev'
|
|
46
|
-
Requires-Dist: flaky >=3.7.0 ; extra == 'dev'
|
|
47
|
-
Requires-Dist: hypothesis >=3.31.2 ; extra == 'dev'
|
|
48
|
-
Requires-Dist: pre-commit >=2.21.0 ; extra == 'dev'
|
|
49
|
-
Requires-Dist: pytest >=7.0.0 ; extra == 'dev'
|
|
50
|
-
Requires-Dist: pytest-asyncio <0.23,>=0.21.2 ; extra == 'dev'
|
|
51
|
-
Requires-Dist: pytest-mock >=1.10 ; extra == 'dev'
|
|
52
|
-
Requires-Dist: pytest-watch >=4.2 ; extra == 'dev'
|
|
53
|
-
Requires-Dist: pytest-xdist >=1.29 ; extra == 'dev'
|
|
54
|
-
Requires-Dist: setuptools >=38.6.0 ; extra == 'dev'
|
|
55
|
-
Requires-Dist: tox >=3.18.0 ; extra == 'dev'
|
|
56
|
-
Requires-Dist: tqdm >4.32 ; extra == 'dev'
|
|
57
|
-
Requires-Dist: twine >=1.13 ; extra == 'dev'
|
|
58
|
-
Requires-Dist: when-changed >=0.3.0 ; extra == 'dev'
|
|
59
|
-
Requires-Dist: build >=0.9.0 ; extra == 'dev'
|
|
60
|
-
Requires-Dist: importlib-metadata <5.0 ; (python_version < "3.8") and extra == 'dev'
|
|
61
|
-
Requires-Dist: eth-tester[py-evm] <0.10.0b1,>=0.9.0b1 ; (python_version <= "3.7") and extra == 'dev'
|
|
62
|
-
Requires-Dist: eth-tester[py-evm] <0.12.0b1,>=0.11.0b1 ; (python_version > "3.7") and extra == 'dev'
|
|
63
|
-
Provides-Extra: docs
|
|
64
|
-
Requires-Dist: sphinx >=5.3.0 ; extra == 'docs'
|
|
65
|
-
Requires-Dist: sphinx-rtd-theme >=1.0.0 ; extra == 'docs'
|
|
66
|
-
Requires-Dist: towncrier <22,>=21 ; extra == 'docs'
|
|
67
|
-
Provides-Extra: ipfs
|
|
68
|
-
Requires-Dist: ipfshttpclient ==0.8.0a2 ; extra == 'ipfs'
|
|
69
|
-
Provides-Extra: tester
|
|
70
|
-
Requires-Dist: py-geth <4,>=3.14.0 ; extra == 'tester'
|
|
71
|
-
Requires-Dist: eth-tester[py-evm] <0.10.0b1,>=0.9.0b1 ; (python_version <= "3.7") and extra == 'tester'
|
|
72
|
-
Requires-Dist: eth-tester[py-evm] <0.12.0b1,>=0.11.0b1 ; (python_version > "3.7") and extra == 'tester'
|
|
73
|
-
|
|
74
|
-
# web3.py
|
|
75
|
-
|
|
76
|
-
[](https://web3py.readthedocs.io/en/latest/?badge=latest)
|
|
77
|
-
[](https://discord.gg/GHryRvPB84)
|
|
78
|
-
[](https://circleci.com/gh/ethereum/web3.py)
|
|
79
|
-
|
|
80
|
-
A Python library for interacting with Ethereum.
|
|
81
|
-
|
|
82
|
-
- Python 3.7.2+ support
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Quickstart
|
|
87
|
-
|
|
88
|
-
[Get started in 5 minutes](https://web3py.readthedocs.io/en/latest/quickstart.html) or
|
|
89
|
-
[take a tour](https://web3py.readthedocs.io/en/latest/overview.html) of the library.
|
|
90
|
-
|
|
91
|
-
## Documentation
|
|
92
|
-
|
|
93
|
-
For additional guides, examples, and APIs, see the [documentation](https://web3py.readthedocs.io/en/latest/).
|
|
94
|
-
|
|
95
|
-
## Want to help?
|
|
96
|
-
|
|
97
|
-
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
|
|
98
|
-
guidelines for [contributing](https://web3py.readthedocs.io/en/latest/contributing.html),
|
|
99
|
-
then check out issues that are labeled
|
|
100
|
-
[Good First Issue](https://github.com/ethereum/web3.py/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+First+Issue%22).
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
#### Questions on implementation or usage? Join the conversation on [discord](https://discord.gg/GHryRvPB84).
|