# solver-MultiRpc: Reliable Ethereum Interactions with Multiple RPCs
`solver-MultiRpc` is a robust library designed to interact with Ethereum smart contracts
using multiple RPC endpoints. This ensures reliability and availability
by distributing the load across various endpoints and retrying operations on failure.
The library provides both asynchronous (`AsyncMultiRpc`) and
synchronous (`MultiRpc`) interfaces to suit different use cases.
## Features
- **Multiple RPC Support**: Seamlessly switch between different RPCs to ensure uninterrupted interactions.
- **Gas Management**: Fetch gas prices from multiple sources to ensure transactions are sent with an appropriate fee.
- **Robust Error Handling**: Designed to handle failures gracefully, increasing the reliability of your applications.
- **Easy-to-use API**: Interact with Ethereum smart contracts using a simple and intuitive API.
## Installation
Install `solver-MultiRpc` using pip:
```bash
pip install solver-multiRPC
```
## Quick Start
Here's a quick example to get you started:
### Asynchronous Usage
Below is an example of how to use the AsyncMultiRpc class for asynchronous operations:
```python
import asyncio
import json
from src.multirpc.utils import NestedDict
from multirpc import AsyncMultiRpc
async def main():
rpcs = NestedDict({
"view": {
1: ['https://1rpc.io/ftm', 'https://rpcapi.fantom.network', 'https://rpc3.fantom.network'],
2: ['https://rpc.fantom.network', 'https://rpc2.fantom.network', ],
3: ['https://rpc.ankr.com/fantom'],
},
"transaction": {
1: ['https://1rpc.io/ftm', 'https://rpcapi.fantom.network', 'https://rpc3.fantom.network'],
2: ['https://rpc.fantom.network', 'https://rpc2.fantom.network', ],
3: ['https://rpc.ankr.com/fantom'],
}
})
with open("abi.json", "r") as f:
abi = json.load(f)
multi_rpc = AsyncMultiRpc(rpcs, 'YOUR_CONTRACT_ADDRESS', contract_abi=abi, enable_estimate_gas_limit=True)
multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
result = await multi_rpc.functions.YOUR_FUNCTION().call()
print(result)
asyncio.run(main())
```
### Synchronous Usage
Below is an example of how to use the MultiRpc class for synchronous operations:
```python
from multirpc import MultiRpc
def main():
multi_rpc = MultiRpc(rpcs, 'YOUR_CONTRACT_ADDRESS', contract_abi=abi, enable_estimate_gas_limit=True)
multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
result = multi_rpc.functions.YOUR_FUNCTION().call()
print(result)
main()
```
Replace placeholders like `YOUR_CONTRACT_ADDRESS`, `YOUR_PUBLIC_ADDRESS`, `YOUR_PRIVATE_KEY`, and `YOUR_FUNCTION` with
appropriate values.
## Documentation
### Initialization
Initialize the `MultiRpc` class with your RPC URLs, contract address, and contract ABI:
```python
multi_rpc = MultiRpc(rpcs, contract_address='YOUR_CONTRACT_ADDRESS', contract_abi=abi)
```
- `enable_estimate_gas_limit=True` will check if tx can be done successfully without paying fee,
and also calculate gas limit for tx
### Setting Account
Set the Ethereum account details (address and private key) for sending transactions:
```python
multi_rpc.set_account("YOUR_PUBLIC_ADDRESS", "YOUR_PRIVATE_KEY")
```
### Calling Contract Functions
Call a function from your contract:
```python
result = await multi_rpc.functions.YOUR_FUNCTION().call()
```
By default we return tx_receipt(wait for 90 second).
if you don't want to return tx_receipt, pass `wait_for_receipt=0` to `call()`
### Calling Contract with another Private Key
You can call a transaction function with a different private key by passing the
`private_key`, `address` parameter to the `call()` method. Here’s an example:
```python
result = await multi_rpc.functions.YOUR_FUNCTION().call(address=PublicKey, private_key=PrivateKey)
```
### Using Block Identifier in Calls
You can specify a block identifier when calling view functions to get the state of the
contract at a specific block. Here's an example:
_Note that the majority of free RPCs only support querying blocks up to 10 minutes earlier._
```python
# You can use 'latest', 'earliest', or a specific block number
result = multi_rpc.functions.yourViewFunction().call(block_identifier='latest')
```
### Using multicall for view function Calls
you can also use `mutlicall()` for calling a view function multiple time with different parameters. Here's an example:
```python
results = multi_rpc.functions.yourViewFunction([(param1, params2), (param1, params2)]).multicall()
```
### Passing View Policy
You can specify a view policy to determine how view function calls are handled.
The available view policies are `MostUpdated` and `FirstSuccess`. Here’s an example:
```python
multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, view_policy=ViewPolicy.FirstSuccess)
```
### Passing Gas Estimation to MultiRpc
You can pass a `GasEstimation` object to the `MultiRpc` or `AsyncMultiRpc` class
to configure how gas prices are estimated. Here is an example of how to do this:
```python
from multirpc import MultiRpc, GasEstimation, GasEstimationMethod
gas_estimation = GasEstimation(
chain_id=1, # Mainnet
providers=[], # List of AsyncWeb3 providers
default_method=GasEstimationMethod.GAS_API_PROVIDER,
gas_api_provider='https://gasstation-mainnet.matic.network' # Replace with your API provider
)
# Pass the GasEstimation object to MultiRpc
multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, gas_estimation=gas_estimation)
```
The `GasEstimation` class allows you to implement a custom gas estimation method.
You need to extend the `GasEstimation` class and override the _`custom_gas_estimation` method with your custom logic.
Here is an example:
```python
from multirpc import GasEstimation, TxPriority, GasEstimationMethod
from web3 import Web3
from web3.types import Wei
class CustomGasEstimation(GasEstimation):
async def _custom_gas_estimation(self, priority: TxPriority, gas_upper_bound: float) -> dict:
# Your custom gas estimation logic here
custom_gas_price = 50 # Replace with your custom logic
if custom_gas_price > gas_upper_bound:
raise OutOfRangeTransactionFee(f"Custom gas price {custom_gas_price} exceeds upper bound {gas_upper_bound}")
return {
"gasPrice": Web3.to_wei(custom_gas_price, 'gwei')
}
# Create an instance of your custom gas estimation
custom_gas_estimation = CustomGasEstimation(
chain_id=1,
providers=[],
default_method=GasEstimationMethod.CUSTOM,
)
# Use it with MultiRpc
multi_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, gas_estimation=custom_gas_estimation)
```
You can specify which gas estimation method in `call()` method. Here's an example:
```python
tx_hash = multi_rpc.functions.yourTransactionFunction().call(
gas_estimation_method=GasEstimationMethod.RPC, # Specify the gas estimation method
)
```
By default, we check all possible ways(api, rpc, fixed, custom) to get `gasPrice`.
but, if you pass method we only use passed method
## Contributing
Contributions are welcome! Please open an issue or submit a pull request on our GitHub repository.
Raw data
{
"_id": null,
"home_page": "https://github.com/SYMM-IO/solver-multiRPC.git",
"name": "solver-multiRPC",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7.2",
"maintainer_email": null,
"keywords": "multiRPC solver",
"author": "rorschach",
"author_email": "rorschach45001@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/fd/93/40b629bae1dd8ac5f99f4cea2b95828c1fd36c166685bff413a0de8632f4/solver_multirpc-3.0.8.tar.gz",
"platform": null,
"description": "# solver-MultiRpc: Reliable Ethereum Interactions with Multiple RPCs\n\n`solver-MultiRpc` is a robust library designed to interact with Ethereum smart contracts\nusing multiple RPC endpoints. This ensures reliability and availability\nby distributing the load across various endpoints and retrying operations on failure.\nThe library provides both asynchronous (`AsyncMultiRpc`) and\nsynchronous (`MultiRpc`) interfaces to suit different use cases.\n\n## Features\n\n- **Multiple RPC Support**: Seamlessly switch between different RPCs to ensure uninterrupted interactions.\n- **Gas Management**: Fetch gas prices from multiple sources to ensure transactions are sent with an appropriate fee.\n- **Robust Error Handling**: Designed to handle failures gracefully, increasing the reliability of your applications.\n- **Easy-to-use API**: Interact with Ethereum smart contracts using a simple and intuitive API.\n\n## Installation\n\nInstall `solver-MultiRpc` using pip:\n\n```bash\npip install solver-multiRPC\n```\n\n## Quick Start\n\nHere's a quick example to get you started:\n\n### Asynchronous Usage\n\nBelow is an example of how to use the AsyncMultiRpc class for asynchronous operations:\n\n```python\nimport asyncio\nimport json\nfrom src.multirpc.utils import NestedDict\nfrom multirpc import AsyncMultiRpc\n\n\nasync def main():\n rpcs = NestedDict({\n \"view\": {\n 1: ['https://1rpc.io/ftm', 'https://rpcapi.fantom.network', 'https://rpc3.fantom.network'],\n 2: ['https://rpc.fantom.network', 'https://rpc2.fantom.network', ],\n 3: ['https://rpc.ankr.com/fantom'],\n },\n \"transaction\": {\n 1: ['https://1rpc.io/ftm', 'https://rpcapi.fantom.network', 'https://rpc3.fantom.network'],\n 2: ['https://rpc.fantom.network', 'https://rpc2.fantom.network', ],\n 3: ['https://rpc.ankr.com/fantom'],\n }\n })\n with open(\"abi.json\", \"r\") as f:\n abi = json.load(f)\n multi_rpc = AsyncMultiRpc(rpcs, 'YOUR_CONTRACT_ADDRESS', contract_abi=abi, enable_estimate_gas_limit=True)\n multi_rpc.set_account(\"YOUR_PUBLIC_ADDRESS\", \"YOUR_PRIVATE_KEY\")\n\n result = await multi_rpc.functions.YOUR_FUNCTION().call()\n print(result)\n\n\nasyncio.run(main())\n```\n\n### Synchronous Usage\n\nBelow is an example of how to use the MultiRpc class for synchronous operations:\n\n```python\nfrom multirpc import MultiRpc\n\n\ndef main():\n multi_rpc = MultiRpc(rpcs, 'YOUR_CONTRACT_ADDRESS', contract_abi=abi, enable_estimate_gas_limit=True)\n multi_rpc.set_account(\"YOUR_PUBLIC_ADDRESS\", \"YOUR_PRIVATE_KEY\")\n\n result = multi_rpc.functions.YOUR_FUNCTION().call()\n print(result)\n\n\nmain()\n```\n\nReplace placeholders like `YOUR_CONTRACT_ADDRESS`, `YOUR_PUBLIC_ADDRESS`, `YOUR_PRIVATE_KEY`, and `YOUR_FUNCTION` with\nappropriate values.\n\n## Documentation\n\n### Initialization\n\nInitialize the `MultiRpc` class with your RPC URLs, contract address, and contract ABI:\n\n```python\nmulti_rpc = MultiRpc(rpcs, contract_address='YOUR_CONTRACT_ADDRESS', contract_abi=abi)\n```\n- `enable_estimate_gas_limit=True` will check if tx can be done successfully without paying fee, \nand also calculate gas limit for tx\n\n### Setting Account\n\nSet the Ethereum account details (address and private key) for sending transactions:\n\n```python\nmulti_rpc.set_account(\"YOUR_PUBLIC_ADDRESS\", \"YOUR_PRIVATE_KEY\")\n```\n\n### Calling Contract Functions\n\nCall a function from your contract:\n\n```python\nresult = await multi_rpc.functions.YOUR_FUNCTION().call()\n```\nBy default we return tx_receipt(wait for 90 second).\nif you don't want to return tx_receipt, pass `wait_for_receipt=0` to `call()` \n\n### Calling Contract with another Private Key\n\nYou can call a transaction function with a different private key by passing the\n`private_key`, `address` parameter to the `call()` method. Here\u2019s an example:\n\n```python\nresult = await multi_rpc.functions.YOUR_FUNCTION().call(address=PublicKey, private_key=PrivateKey)\n```\n\n### Using Block Identifier in Calls\n\nYou can specify a block identifier when calling view functions to get the state of the\ncontract at a specific block. Here's an example:\n\n_Note that the majority of free RPCs only support querying blocks up to 10 minutes earlier._\n\n```python\n# You can use 'latest', 'earliest', or a specific block number\nresult = multi_rpc.functions.yourViewFunction().call(block_identifier='latest') \n```\n\n### Using multicall for view function Calls\n\nyou can also use `mutlicall()` for calling a view function multiple time with different parameters. Here's an example:\n\n```python\nresults = multi_rpc.functions.yourViewFunction([(param1, params2), (param1, params2)]).multicall() \n```\n\n### Passing View Policy\n\nYou can specify a view policy to determine how view function calls are handled.\nThe available view policies are `MostUpdated` and `FirstSuccess`. Here\u2019s an example:\n\n```python\nmulti_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, view_policy=ViewPolicy.FirstSuccess)\n```\n\n### Passing Gas Estimation to MultiRpc\n\nYou can pass a `GasEstimation` object to the `MultiRpc` or `AsyncMultiRpc` class\nto configure how gas prices are estimated. Here is an example of how to do this:\n\n```python\nfrom multirpc import MultiRpc, GasEstimation, GasEstimationMethod\n\ngas_estimation = GasEstimation(\n chain_id=1, # Mainnet\n providers=[], # List of AsyncWeb3 providers\n default_method=GasEstimationMethod.GAS_API_PROVIDER,\n gas_api_provider='https://gasstation-mainnet.matic.network' # Replace with your API provider\n)\n\n# Pass the GasEstimation object to MultiRpc\nmulti_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, gas_estimation=gas_estimation)\n```\n\nThe `GasEstimation` class allows you to implement a custom gas estimation method.\nYou need to extend the `GasEstimation` class and override the _`custom_gas_estimation` method with your custom logic.\nHere is an example:\n\n```python\nfrom multirpc import GasEstimation, TxPriority, GasEstimationMethod\nfrom web3 import Web3\nfrom web3.types import Wei\n\n\nclass CustomGasEstimation(GasEstimation):\n\n async def _custom_gas_estimation(self, priority: TxPriority, gas_upper_bound: float) -> dict:\n # Your custom gas estimation logic here\n custom_gas_price = 50 # Replace with your custom logic\n if custom_gas_price > gas_upper_bound:\n raise OutOfRangeTransactionFee(f\"Custom gas price {custom_gas_price} exceeds upper bound {gas_upper_bound}\")\n return {\n \"gasPrice\": Web3.to_wei(custom_gas_price, 'gwei')\n }\n\n\n# Create an instance of your custom gas estimation\ncustom_gas_estimation = CustomGasEstimation(\n chain_id=1,\n providers=[],\n default_method=GasEstimationMethod.CUSTOM,\n)\n\n# Use it with MultiRpc\nmulti_rpc = MultiRpc(rpc_urls, contract_address, contract_abi, gas_estimation=custom_gas_estimation)\n```\n\nYou can specify which gas estimation method in `call()` method. Here's an example:\n\n```python\ntx_hash = multi_rpc.functions.yourTransactionFunction().call(\n gas_estimation_method=GasEstimationMethod.RPC, # Specify the gas estimation method\n)\n```\n\nBy default, we check all possible ways(api, rpc, fixed, custom) to get `gasPrice`.\nbut, if you pass method we only use passed method\n\n## Contributing\n\nContributions are welcome! Please open an issue or submit a pull request on our GitHub repository.\n",
"bugtrack_url": null,
"license": null,
"summary": "Use multiple rpc for reliability",
"version": "3.0.8",
"project_urls": {
"Bug Tracker": "https://github.com/SYMM-IO/solver-multiRPC",
"Homepage": "https://github.com/SYMM-IO/solver-multiRPC.git"
},
"split_keywords": [
"multirpc",
"solver"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "fd9340b629bae1dd8ac5f99f4cea2b95828c1fd36c166685bff413a0de8632f4",
"md5": "e1aca5e87a37668c3bfbd4f607c6418b",
"sha256": "6d842a982276e4598cc7be0655a457573dd06da12fbb6ef8b9968759bfa4ba71"
},
"downloads": -1,
"filename": "solver_multirpc-3.0.8.tar.gz",
"has_sig": false,
"md5_digest": "e1aca5e87a37668c3bfbd4f607c6418b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7.2",
"size": 22493,
"upload_time": "2024-12-15T07:14:01",
"upload_time_iso_8601": "2024-12-15T07:14:01.497289Z",
"url": "https://files.pythonhosted.org/packages/fd/93/40b629bae1dd8ac5f99f4cea2b95828c1fd36c166685bff413a0de8632f4/solver_multirpc-3.0.8.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-15 07:14:01",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "SYMM-IO",
"github_project": "solver-multiRPC",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "web3",
"specs": [
[
">=",
"6.0.0"
]
]
},
{
"name": "multicallable",
"specs": [
[
">=",
"6.0.0"
]
]
},
{
"name": "eth-account",
"specs": [
[
">=",
"0.12.2"
]
]
},
{
"name": "logmon",
"specs": []
}
],
"lcname": "solver-multirpc"
}