solver-multirpc 3.1.4__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.
@@ -0,0 +1,241 @@
1
+ Metadata-Version: 2.3
2
+ Name: solver-multirpc
3
+ Version: 3.1.4
4
+ Summary: A robust Python library for interacting with Ethereum smart contracts via multiple RPC endpoints, ensuring reliability, availability, and load distribution with automatic retries on failure.
5
+ License: MIT
6
+ Author: rorschach
7
+ Author-email: rorschach45001@gmail.com
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Dist: eth-account (>=0.13.0)
16
+ Requires-Dist: multicallable (>=6.0.0)
17
+ Requires-Dist: web3 (>7.0.0)
18
+ Description-Content-Type: text/markdown
19
+
20
+ # solver-MultiRpc: Reliable Ethereum Interactions with Multiple RPCs
21
+
22
+ `solver-MultiRpc` is a robust library designed to interact with Ethereum smart contracts
23
+ using multiple RPC endpoints. This ensures reliability and availability
24
+ by distributing the load across various endpoints and retrying operations on failure.
25
+ The library provides both asynchronous (`AsyncMultiRpc`) and
26
+ synchronous (`MultiRpc`) interfaces to suit different use cases.
27
+
28
+ ## Features
29
+
30
+ - **Multiple RPC Support**: Seamlessly switch between different RPCs to ensure uninterrupted interactions.
31
+ - **Gas Management**: Fetch gas prices from multiple sources to ensure transactions are sent with an appropriate fee.
32
+ - **Robust Error Handling**: Designed to handle failures gracefully, increasing the reliability of your applications.
33
+ - **Easy-to-use API**: Interact with Ethereum smart contracts using a simple and intuitive API.
34
+
35
+ ## Installation
36
+
37
+ Install `solver-MultiRpc` using pip:
38
+
39
+ ```bash
40
+ pip install solver-multiRPC
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ Here's a quick example to get you started:
46
+
47
+ ### Asynchronous Usage
48
+
49
+ Below is an example of how to use the AsyncMultiRpc class for asynchronous operations:
50
+
51
+ ```python
52
+ import asyncio
53
+ import json
54
+ from src.multirpc.utils import NestedDict
55
+ from multirpc import AsyncMultiRpc
56
+
57
+
58
+ async def main():
59
+ rpcs = NestedDict({
60
+ "view": {
61
+ 1: ['https://1rpc.io/ftm', 'https://rpcapi.fantom.network', 'https://rpc3.fantom.network'],
62
+ 2: ['https://rpc.fantom.network', 'https://rpc2.fantom.network', ],
63
+ 3: ['https://rpc.ankr.com/fantom'],
64
+ },
65
+ "transaction": {
66
+ 1: ['https://1rpc.io/ftm', 'https://rpcapi.fantom.network', 'https://rpc3.fantom.network'],
67
+ 2: ['https://rpc.fantom.network', 'https://rpc2.fantom.network', ],
68
+ 3: ['https://rpc.ankr.com/fantom'],
69
+ }
70
+ })
71
+ with open("abi.json", "r") as f:
72
+ abi = json.load(f)
73
+ multi_rpc = AsyncMultiRpc(rpcs, 'YOUR_CONTRACT_ADDRESS', contract_abi=abi, enable_estimate_gas_limit=True)
74
+ multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
75
+
76
+ result = await multi_rpc.functions.YOUR_FUNCTION().call()
77
+ print(result)
78
+
79
+
80
+ asyncio.run(main())
81
+ ```
82
+
83
+ ### Synchronous Usage
84
+
85
+ Below is an example of how to use the MultiRpc class for synchronous operations:
86
+
87
+ ```python
88
+ from multirpc import MultiRpc
89
+
90
+
91
+ def main():
92
+ multi_rpc = MultiRpc(rpcs, 'YOUR_CONTRACT_ADDRESS', contract_abi=abi, enable_estimate_gas_limit=True)
93
+ multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
94
+
95
+ result = multi_rpc.functions.YOUR_FUNCTION().call()
96
+ print(result)
97
+
98
+
99
+ main()
100
+ ```
101
+
102
+ Replace placeholders like `YOUR_CONTRACT_ADDRESS`, `YOUR_PUBLIC_ADDRESS`, `YOUR_PRIVATE_KEY`, and `YOUR_FUNCTION` with
103
+ appropriate values.
104
+
105
+ ## Documentation
106
+
107
+ ### Initialization
108
+
109
+ Initialize the `MultiRpc` class with your RPC URLs, contract address, and contract ABI:
110
+
111
+ ```python
112
+ multi_rpc = MultiRpc(rpcs, contract_address='YOUR_CONTRACT_ADDRESS', contract_abi=abi)
113
+ ```
114
+ - `enable_estimate_gas_limit=True` will check if tx can be done successfully without paying fee,
115
+ and also calculate gas limit for tx
116
+ - You can pass a list of RPCs to `rpcs_supporting_tx_trace=[]` to identify which of the provided RPCs (`rpcs`) support `tx_trace`.
117
+ Then, when a transaction fails, you can retrieve the trace of the transaction.
118
+
119
+ ### Setting Account
120
+
121
+ Set the Ethereum account details (address and private key) for sending transactions:
122
+
123
+ ```python
124
+ multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
125
+ ```
126
+
127
+ ### Calling Contract Functions
128
+
129
+ Call a function from your contract:
130
+
131
+ ```python
132
+ result = await multi_rpc.functions.YOUR_FUNCTION().call()
133
+ ```
134
+ By default we return tx_receipt(wait for 90 second).
135
+ if you don't want to return tx_receipt, pass `wait_for_receipt=0` to `call()`
136
+
137
+ ### Calling Contract with another Private Key
138
+
139
+ You can call a transaction function with a different private key by passing the
140
+ `private_key`, `address` parameter to the `call()` method. Here’s an example:
141
+
142
+ ```python
143
+ result = await multi_rpc.functions.YOUR_FUNCTION().call(address=PublicKey, private_key=PrivateKey)
144
+ ```
145
+
146
+ ### Using Block Identifier in Calls
147
+
148
+ You can specify a block identifier when calling view functions to get the state of the
149
+ contract at a specific block. Here's an example:
150
+
151
+ _Note that the majority of free RPCs only support querying blocks up to 10 minutes earlier._
152
+
153
+ ```python
154
+ # You can use 'latest', 'earliest', or a specific block number
155
+ result = multi_rpc.functions.yourViewFunction().call(block_identifier='latest')
156
+ ```
157
+
158
+ ### Using multicall for view function Calls
159
+
160
+ you can also use `mutlicall()` for calling a view function multiple time with different parameters. Here's an example:
161
+
162
+ ```python
163
+ results = multi_rpc.functions.yourViewFunction([(param1, params2), (param1, params2)]).multicall()
164
+ ```
165
+
166
+ ### Passing View Policy
167
+
168
+ You can specify a view policy to determine how view function calls are handled.
169
+ The available view policies are `MostUpdated` and `FirstSuccess`. Here’s an example:
170
+
171
+ ```python
172
+ multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, view_policy=ViewPolicy.FirstSuccess)
173
+ ```
174
+
175
+ ### Passing Gas Estimation to MultiRpc
176
+
177
+ You can pass a `GasEstimation` object to the `MultiRpc` or `AsyncMultiRpc` class
178
+ to configure how gas prices are estimated. Here is an example of how to do this:
179
+
180
+ ```python
181
+ from multirpc import MultiRpc, GasEstimation, GasEstimationMethod
182
+
183
+ gas_estimation = GasEstimation(
184
+ chain_id=1, # Mainnet
185
+ providers=[], # List of AsyncWeb3 providers
186
+ default_method=GasEstimationMethod.GAS_API_PROVIDER,
187
+ gas_api_provider='https://gasstation-mainnet.matic.network' # Replace with your API provider
188
+ )
189
+
190
+ # Pass the GasEstimation object to MultiRpc
191
+ multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, gas_estimation=gas_estimation)
192
+ ```
193
+
194
+ The `GasEstimation` class allows you to implement a custom gas estimation method.
195
+ You need to extend the `GasEstimation` class and override the _`custom_gas_estimation` method with your custom logic.
196
+ Here is an example:
197
+
198
+ ```python
199
+ from multirpc import GasEstimation, TxPriority, GasEstimationMethod
200
+ from web3 import Web3
201
+ from web3.types import Wei
202
+
203
+
204
+ class CustomGasEstimation(GasEstimation):
205
+
206
+ async def _custom_gas_estimation(self, priority: TxPriority, gas_upper_bound: float) -> dict:
207
+ # Your custom gas estimation logic here
208
+ custom_gas_price = 50 # Replace with your custom logic
209
+ if custom_gas_price > gas_upper_bound:
210
+ raise OutOfRangeTransactionFee(f"Custom gas price {custom_gas_price} exceeds upper bound {gas_upper_bound}")
211
+ return {
212
+ "gasPrice": Web3.to_wei(custom_gas_price, 'gwei')
213
+ }
214
+
215
+
216
+ # Create an instance of your custom gas estimation
217
+ custom_gas_estimation = CustomGasEstimation(
218
+ chain_id=1,
219
+ providers=[],
220
+ default_method=GasEstimationMethod.CUSTOM,
221
+ )
222
+
223
+ # Use it with MultiRpc
224
+ multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, gas_estimation=custom_gas_estimation)
225
+ ```
226
+
227
+ You can specify which gas estimation method in `call()` method. Here's an example:
228
+
229
+ ```python
230
+ tx_hash = multi_rpc.functions.yourTransactionFunction().call(
231
+ gas_estimation_method=GasEstimationMethod.RPC, # Specify the gas estimation method
232
+ )
233
+ ```
234
+
235
+ By default, we check all possible ways(api, rpc, fixed, custom) to get `gasPrice`.
236
+ but, if you pass method we only use passed method
237
+
238
+ ## Contributing
239
+
240
+ Contributions are welcome! Please open an issue or submit a pull request on our GitHub repository.
241
+
@@ -0,0 +1,221 @@
1
+ # solver-MultiRpc: Reliable Ethereum Interactions with Multiple RPCs
2
+
3
+ `solver-MultiRpc` is a robust library designed to interact with Ethereum smart contracts
4
+ using multiple RPC endpoints. This ensures reliability and availability
5
+ by distributing the load across various endpoints and retrying operations on failure.
6
+ The library provides both asynchronous (`AsyncMultiRpc`) and
7
+ synchronous (`MultiRpc`) interfaces to suit different use cases.
8
+
9
+ ## Features
10
+
11
+ - **Multiple RPC Support**: Seamlessly switch between different RPCs to ensure uninterrupted interactions.
12
+ - **Gas Management**: Fetch gas prices from multiple sources to ensure transactions are sent with an appropriate fee.
13
+ - **Robust Error Handling**: Designed to handle failures gracefully, increasing the reliability of your applications.
14
+ - **Easy-to-use API**: Interact with Ethereum smart contracts using a simple and intuitive API.
15
+
16
+ ## Installation
17
+
18
+ Install `solver-MultiRpc` using pip:
19
+
20
+ ```bash
21
+ pip install solver-multiRPC
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ Here's a quick example to get you started:
27
+
28
+ ### Asynchronous Usage
29
+
30
+ Below is an example of how to use the AsyncMultiRpc class for asynchronous operations:
31
+
32
+ ```python
33
+ import asyncio
34
+ import json
35
+ from src.multirpc.utils import NestedDict
36
+ from multirpc import AsyncMultiRpc
37
+
38
+
39
+ async def main():
40
+ rpcs = NestedDict({
41
+ "view": {
42
+ 1: ['https://1rpc.io/ftm', 'https://rpcapi.fantom.network', 'https://rpc3.fantom.network'],
43
+ 2: ['https://rpc.fantom.network', 'https://rpc2.fantom.network', ],
44
+ 3: ['https://rpc.ankr.com/fantom'],
45
+ },
46
+ "transaction": {
47
+ 1: ['https://1rpc.io/ftm', 'https://rpcapi.fantom.network', 'https://rpc3.fantom.network'],
48
+ 2: ['https://rpc.fantom.network', 'https://rpc2.fantom.network', ],
49
+ 3: ['https://rpc.ankr.com/fantom'],
50
+ }
51
+ })
52
+ with open("abi.json", "r") as f:
53
+ abi = json.load(f)
54
+ multi_rpc = AsyncMultiRpc(rpcs, 'YOUR_CONTRACT_ADDRESS', contract_abi=abi, enable_estimate_gas_limit=True)
55
+ multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
56
+
57
+ result = await multi_rpc.functions.YOUR_FUNCTION().call()
58
+ print(result)
59
+
60
+
61
+ asyncio.run(main())
62
+ ```
63
+
64
+ ### Synchronous Usage
65
+
66
+ Below is an example of how to use the MultiRpc class for synchronous operations:
67
+
68
+ ```python
69
+ from multirpc import MultiRpc
70
+
71
+
72
+ def main():
73
+ multi_rpc = MultiRpc(rpcs, 'YOUR_CONTRACT_ADDRESS', contract_abi=abi, enable_estimate_gas_limit=True)
74
+ multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
75
+
76
+ result = multi_rpc.functions.YOUR_FUNCTION().call()
77
+ print(result)
78
+
79
+
80
+ main()
81
+ ```
82
+
83
+ Replace placeholders like `YOUR_CONTRACT_ADDRESS`, `YOUR_PUBLIC_ADDRESS`, `YOUR_PRIVATE_KEY`, and `YOUR_FUNCTION` with
84
+ appropriate values.
85
+
86
+ ## Documentation
87
+
88
+ ### Initialization
89
+
90
+ Initialize the `MultiRpc` class with your RPC URLs, contract address, and contract ABI:
91
+
92
+ ```python
93
+ multi_rpc = MultiRpc(rpcs, contract_address='YOUR_CONTRACT_ADDRESS', contract_abi=abi)
94
+ ```
95
+ - `enable_estimate_gas_limit=True` will check if tx can be done successfully without paying fee,
96
+ and also calculate gas limit for tx
97
+ - You can pass a list of RPCs to `rpcs_supporting_tx_trace=[]` to identify which of the provided RPCs (`rpcs`) support `tx_trace`.
98
+ Then, when a transaction fails, you can retrieve the trace of the transaction.
99
+
100
+ ### Setting Account
101
+
102
+ Set the Ethereum account details (address and private key) for sending transactions:
103
+
104
+ ```python
105
+ multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
106
+ ```
107
+
108
+ ### Calling Contract Functions
109
+
110
+ Call a function from your contract:
111
+
112
+ ```python
113
+ result = await multi_rpc.functions.YOUR_FUNCTION().call()
114
+ ```
115
+ By default we return tx_receipt(wait for 90 second).
116
+ if you don't want to return tx_receipt, pass `wait_for_receipt=0` to `call()`
117
+
118
+ ### Calling Contract with another Private Key
119
+
120
+ You can call a transaction function with a different private key by passing the
121
+ `private_key`, `address` parameter to the `call()` method. Here’s an example:
122
+
123
+ ```python
124
+ result = await multi_rpc.functions.YOUR_FUNCTION().call(address=PublicKey, private_key=PrivateKey)
125
+ ```
126
+
127
+ ### Using Block Identifier in Calls
128
+
129
+ You can specify a block identifier when calling view functions to get the state of the
130
+ contract at a specific block. Here's an example:
131
+
132
+ _Note that the majority of free RPCs only support querying blocks up to 10 minutes earlier._
133
+
134
+ ```python
135
+ # You can use 'latest', 'earliest', or a specific block number
136
+ result = multi_rpc.functions.yourViewFunction().call(block_identifier='latest')
137
+ ```
138
+
139
+ ### Using multicall for view function Calls
140
+
141
+ you can also use `mutlicall()` for calling a view function multiple time with different parameters. Here's an example:
142
+
143
+ ```python
144
+ results = multi_rpc.functions.yourViewFunction([(param1, params2), (param1, params2)]).multicall()
145
+ ```
146
+
147
+ ### Passing View Policy
148
+
149
+ You can specify a view policy to determine how view function calls are handled.
150
+ The available view policies are `MostUpdated` and `FirstSuccess`. Here’s an example:
151
+
152
+ ```python
153
+ multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, view_policy=ViewPolicy.FirstSuccess)
154
+ ```
155
+
156
+ ### Passing Gas Estimation to MultiRpc
157
+
158
+ You can pass a `GasEstimation` object to the `MultiRpc` or `AsyncMultiRpc` class
159
+ to configure how gas prices are estimated. Here is an example of how to do this:
160
+
161
+ ```python
162
+ from multirpc import MultiRpc, GasEstimation, GasEstimationMethod
163
+
164
+ gas_estimation = GasEstimation(
165
+ chain_id=1, # Mainnet
166
+ providers=[], # List of AsyncWeb3 providers
167
+ default_method=GasEstimationMethod.GAS_API_PROVIDER,
168
+ gas_api_provider='https://gasstation-mainnet.matic.network' # Replace with your API provider
169
+ )
170
+
171
+ # Pass the GasEstimation object to MultiRpc
172
+ multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, gas_estimation=gas_estimation)
173
+ ```
174
+
175
+ The `GasEstimation` class allows you to implement a custom gas estimation method.
176
+ You need to extend the `GasEstimation` class and override the _`custom_gas_estimation` method with your custom logic.
177
+ Here is an example:
178
+
179
+ ```python
180
+ from multirpc import GasEstimation, TxPriority, GasEstimationMethod
181
+ from web3 import Web3
182
+ from web3.types import Wei
183
+
184
+
185
+ class CustomGasEstimation(GasEstimation):
186
+
187
+ async def _custom_gas_estimation(self, priority: TxPriority, gas_upper_bound: float) -> dict:
188
+ # Your custom gas estimation logic here
189
+ custom_gas_price = 50 # Replace with your custom logic
190
+ if custom_gas_price > gas_upper_bound:
191
+ raise OutOfRangeTransactionFee(f"Custom gas price {custom_gas_price} exceeds upper bound {gas_upper_bound}")
192
+ return {
193
+ "gasPrice": Web3.to_wei(custom_gas_price, 'gwei')
194
+ }
195
+
196
+
197
+ # Create an instance of your custom gas estimation
198
+ custom_gas_estimation = CustomGasEstimation(
199
+ chain_id=1,
200
+ providers=[],
201
+ default_method=GasEstimationMethod.CUSTOM,
202
+ )
203
+
204
+ # Use it with MultiRpc
205
+ multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, gas_estimation=custom_gas_estimation)
206
+ ```
207
+
208
+ You can specify which gas estimation method in `call()` method. Here's an example:
209
+
210
+ ```python
211
+ tx_hash = multi_rpc.functions.yourTransactionFunction().call(
212
+ gas_estimation_method=GasEstimationMethod.RPC, # Specify the gas estimation method
213
+ )
214
+ ```
215
+
216
+ By default, we check all possible ways(api, rpc, fixed, custom) to get `gasPrice`.
217
+ but, if you pass method we only use passed method
218
+
219
+ ## Contributing
220
+
221
+ Contributions are welcome! Please open an issue or submit a pull request on our GitHub repository.
@@ -0,0 +1,21 @@
1
+ [tool.poetry]
2
+ name = "solver-multirpc"
3
+ version = "3.1.4"
4
+ description = "A robust Python library for interacting with Ethereum smart contracts via multiple RPC endpoints, ensuring reliability, availability, and load distribution with automatic retries on failure."
5
+ authors = ["rorschach <rorschach45001@gmail.com>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ packages = [
9
+ { include = "src" }
10
+ ]
11
+
12
+ [tool.poetry.dependencies]
13
+ python = ">=3.10,<4.0"
14
+ web3 = ">7.0.0"
15
+ multicallable = ">=6.0.0"
16
+ eth-account = ">=0.13.0"
17
+
18
+
19
+ [build-system]
20
+ requires = ["poetry-core"]
21
+ build-backend = "poetry.core.masonry.api"
File without changes
@@ -0,0 +1 @@
1
+ from .base_multi_rpc_interface import BaseMultiRpc
@@ -0,0 +1,125 @@
1
+ import asyncio
2
+ import logging
3
+ from typing import Dict, List, Optional, Union
4
+
5
+ from eth_typing import Address, ChecksumAddress
6
+ from web3._utils.contracts import encode_transaction_data # noqa
7
+ from web3.types import BlockData, BlockIdentifier, TxReceipt
8
+
9
+ from . import BaseMultiRpc
10
+ from .base_multi_rpc_interface import BaseContractFunction
11
+ from .constants import GasLimit, GasUpperBound, ViewPolicy
12
+ from .exceptions import DontHaveThisRpcType, KwargsNotSupportedInMultiCall, TransactionTypeNotSupportedInMultiCall
13
+ from .gas_estimation import GasEstimation, GasEstimationMethod
14
+ from .utils import ContractFunctionType, NestedDict, TxPriority, thread_safe
15
+
16
+
17
+ class AsyncMultiRpc(BaseMultiRpc):
18
+ """
19
+ This class is used to be more sure when running web3 view calls and sending transactions by using of multiple RPCs.
20
+ """
21
+
22
+ @thread_safe
23
+ def __init__(
24
+ self,
25
+ rpc_urls: NestedDict,
26
+ contract_address: Union[Address, ChecksumAddress, str],
27
+ contract_abi: Dict,
28
+ rpcs_supporting_tx_trace: Optional[List[str]] = None,
29
+ view_policy: ViewPolicy = ViewPolicy.MostUpdated,
30
+ gas_estimation: Optional[GasEstimation] = None,
31
+ gas_limit: int = GasLimit,
32
+ gas_upper_bound: int = GasUpperBound,
33
+ apm=None,
34
+ enable_estimate_gas_limit: bool = False,
35
+ is_proof_authority: bool = False,
36
+ multicall_custom_address: str = None,
37
+ log_level: logging = logging.WARN,
38
+ setup_on_init: bool = True
39
+ ):
40
+ super().__init__(rpc_urls, contract_address, contract_abi, rpcs_supporting_tx_trace,
41
+ view_policy, gas_estimation, gas_limit,
42
+ gas_upper_bound, apm, enable_estimate_gas_limit,
43
+ is_proof_authority, multicall_custom_address, log_level)
44
+
45
+ for func_abi in self.contract_abi:
46
+ if func_abi.get("stateMutability") in ("view", "pure"):
47
+ function_type = ContractFunctionType.View
48
+ elif func_abi.get("type") == "function":
49
+ function_type = ContractFunctionType.Transaction
50
+ else:
51
+ continue
52
+ self.functions.__setattr__(
53
+ func_abi["name"],
54
+ self.ContractFunction(func_abi["name"], func_abi, self, function_type),
55
+ )
56
+ if setup_on_init:
57
+ asyncio.run(self.setup())
58
+
59
+ async def get_nonce(self, address: Union[Address, ChecksumAddress, str]) -> int:
60
+ return await super()._get_nonce(address)
61
+
62
+ async def get_tx_receipt(self, tx_hash) -> TxReceipt:
63
+ return await super().get_tx_receipt(tx_hash)
64
+
65
+ async def get_block(self, block_identifier: BlockIdentifier = 'latest',
66
+ full_transactions: bool = False) -> BlockData:
67
+ return await super().get_block(block_identifier, full_transactions)
68
+
69
+ async def get_block_number(self) -> int:
70
+ return await super().get_block_number()
71
+
72
+ class ContractFunction(BaseContractFunction):
73
+ def __call__(self, *args, **kwargs):
74
+ cf = AsyncMultiRpc.ContractFunction(self.name, self.abi, self.mr, self.typ)
75
+ cf.args = args
76
+ cf.kwargs = kwargs
77
+ return cf
78
+
79
+ async def call(
80
+ self,
81
+ address: str = None,
82
+ private_key: str = None,
83
+ gas_limit: int = None,
84
+ gas_upper_bound: int = None,
85
+ wait_for_receipt: int = 90,
86
+ priority: TxPriority = TxPriority.Low,
87
+ gas_estimation_method: GasEstimationMethod = None,
88
+ block_identifier: Union[str, int] = 'latest',
89
+ enable_estimate_gas_limit: Optional[bool] = None,
90
+ ):
91
+ if self.mr.providers.get(self.typ) is None:
92
+ raise DontHaveThisRpcType(f"Doesn't have {self.typ} RPCs")
93
+ if self.typ == ContractFunctionType.View:
94
+ return await self.mr._call_view_function(
95
+ self.name, block_identifier, False, *self.args, **self.kwargs,
96
+ )
97
+ elif self.typ == ContractFunctionType.Transaction:
98
+ return await self.mr._call_tx_function(
99
+ func_name=self.name,
100
+ func_args=self.args,
101
+ func_kwargs=self.kwargs,
102
+ address=address or self.mr.address,
103
+ private_key=private_key or self.mr.private_key,
104
+ gas_limit=gas_limit or self.mr.gas_limit,
105
+ gas_upper_bound=gas_upper_bound or self.mr.gas_upper_bound,
106
+ wait_for_receipt=wait_for_receipt,
107
+ priority=priority,
108
+ gas_estimation_method=gas_estimation_method,
109
+ enable_estimate_gas_limit=enable_estimate_gas_limit
110
+ )
111
+
112
+ async def multicall(
113
+ self,
114
+ block_identifier: Union[str, int] = 'latest',
115
+ ):
116
+ if self.mr.providers.get(self.typ) is None:
117
+ raise DontHaveThisRpcType(f"Doesn't have {self.typ} RPCs")
118
+ if self.kwargs != {}:
119
+ raise KwargsNotSupportedInMultiCall
120
+ if self.typ == ContractFunctionType.View:
121
+ return await self.mr._call_view_function(
122
+ self.name, block_identifier, True, *self.args, **self.kwargs,
123
+ )
124
+ elif self.typ == ContractFunctionType.Transaction:
125
+ raise TransactionTypeNotSupportedInMultiCall