From 1e8ca15ef73a19381d3481288da30310a72ac5b2 Mon Sep 17 00:00:00 2001 From: Leviathan1993 Date: Wed, 27 Sep 2023 00:47:15 +0200 Subject: [PATCH] Updated README.md with new client initialization process. --- README.md | 247 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 148 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index b527662..37b6ad9 100644 --- a/README.md +++ b/README.md @@ -36,32 +36,51 @@ poetry install ## Usage +There are two ways to initalize the client: + +#### 1) Using the constructor: +(throws an error if any keyword argument is missing): +```bash +from client import MevShareClient +client = MevShareClient(api_url='https://relay.flashbots.net/', + sign_key='', + node_url='https://goerli.infura.io/v3/', + stream_url='https://mev-share.flashbots.net/') + ) +``` + +#### 2) Using the classmethod ```from_config``` which reads from the head dir config.json file: +For this to work, you need to pass the network string (currently either 'goerli' or 'mainnet') and config.json file path to the classmethod. +The ```private_key``` and ```to``` fields are optional, used for easy access by accessing the client.config parameter. +The private_key is only used in the example files. +### It is NOT advisable to store your PROD private key in the config file. Add the necessary variables to the config.json file. ```bash { - "relay_url_mainnet": "https://relay.flashbots.net", - "sse_url_mainnet": "https://mev-share.flashbots.net/", - "relay_url_goerli": "https://relay-goerli.flashbots.net/", - "sse_url_goerli": "https://mev-share-goerli.flashbots.net/", + "mainnet": { + "relay_url": "https://relay.flashbots.net", + "sse_url": "https://mev-share.flashbots.net/", + "infura_url": "https://mainnet.infura.io/v3/{}" + }, + "goerli": { + "relay_url": "https://relay-goerli.flashbots.net/", + "sse_url": "https://mev-share-goerli.flashbots.net/", + "infura_url": "https://goerli.infura.io/v3/{}" + }, "infura_key": "", "private_key": "", "sign_key": "", "to": "", } ``` - Import the client and create an instance of the client with the desired network. -```python +```bash from client import MevShareClient - -api_url = "https://relay-goerli.flashbots.net/" -stream_url = "https://mev-share-goerli.flashbots.net/" -client = MevShareClient(api_url=api_url, stream_url=stream_url) +client = MevShareClient.from_config('goerli', '../config.json') ``` -## Usage Client library uses python typeddict to define the types of the data for static analysis. Those are not enforced at runtime. So make sure to check the types of parameters and return values. @@ -83,15 +102,15 @@ received. ```python import asyncio -from client import MevShareClient -from api.events import PendingBundle, PendingTransaction +from mev_share_py.client import MevShareClient +from api.events import PendingTransaction def callback_function(event: PendingTransaction): print(event) -client = MevShareClient() +client = MevShareClient.from_config('goerli', '../config.json') res = asyncio.run( client.listen_for_events('transaction', callback_function), ) @@ -104,31 +123,26 @@ Send a private transaction to the MEV-Share node. Hints and options are passed a ```python import asyncio -import json -from client import MevShareClient -from web3 import Web3 - -config = json.load(open('config.json')) +from mev_share_py.client import MevShareClient -infura_http_url = "https://goerli.infura.io/v3/{}".format(config['infura_key']) -web3 = Web3(Web3.HTTPProvider(infura_http_url)) raw_tx = '' # Add raw tx here async def send_tx(tx: str): - client = MevShareClient() + client = MevShareClient.from_config(network='goerli', config_dir='../config.json') print(tx) - return await client.send_transaction(tx.rawTransaction.hex(), - {'max_block_number': web3.eth.block_number + 10, - 'hints': { - 'calldata': True, - 'logs': True, - 'function_selector': True, - 'hash': True, - 'tx_hash': True - } - } - ) + return await client.send_transaction( + tx.rawTransaction.hex(), + { + 'max_block_number': await client.w3_async.eth.block_number + 10, + 'hints': { + 'calldata': True, + 'contract_address': True, + 'function_selector': True, + 'logs': True + } + } + ) if __name__ == "__main__": @@ -145,47 +159,45 @@ we can share hints by uncommenting the privacy section. ```python import asyncio -import json -from web3 import Web3 -from api.types import BundleParams -from client import MevShareClient -from api.events import PendingTransaction - -config = json.load(open('config.json')) - -infura_ws_url = "wss://goerli.infura.io/ws/v3/{}".format(config['infura_key']) -infura_http_url = "https://goerli.infura.io/v3/{}".format(config['infura_key']) -web3 = Web3(Web3.HTTPProvider(infura_http_url)) - - -async def build_and_send(tx1: PendingTransaction): - tx2 = '0x' # Add raw tx here +from mev_share_py.client import MevShareClient +from mev_share_py.api.types import BundleParams + + + +async def build_and_send(): + """ + Generate a bundle with two private transactions and send it. + :return: + """ + tx1 = '' + tx2 = '' + client = MevShareClient.from_config(network='goerli', config_dir='../config.json') + tx1 = tx1 + tx2 = tx2 + block_number = await client.w3_async.eth.block_number params = { 'inclusion': { - 'block': web3.eth.block_number + 1, - # 'max_block': web3.eth.block_number+10, + 'block': block_number + 1, + 'max_block': block_number + 10, }, - 'body': [{'hash': tx1.hash}, - {'tx': tx2}], - # 'privacy': { - # 'hints': { - # 'tx_hash': True, - # 'calldata': True, - # 'logs': True, - # 'function_selector': True, - # }, - # # 'builders': ['flashbots'] - # } + 'body': [ + {'tx': tx1.rawTransaction.hex()}, + {'tx': tx2.rawTransaction.hex()}], + 'privacy': { + 'hints': { + 'tx_hash': True, + 'calldata': True, + 'logs': True, + 'function_selector': True, + }, + # 'builders': ['flashbots'] + } } params = BundleParams(**params) - return await client.send_bundle(params) - - -client = MevShareClient() -res = asyncio.run( - client.listen_for_events('transaction', build_and_send) -) + print(await client.send_bundle(params)) +if __name__ == "__main__": + asyncio.run(build_and_send()) ``` ### simulate_bundle @@ -193,36 +205,50 @@ res = asyncio.run( Similar to send_bundle, but also accepts options to modify block header. ```python - -TARGET_BLOCK = web3.eth.block_number + 1 -params = { - 'inclusion': { - 'block': TARGET_BLOCK, - 'max_block': TARGET_BLOCK + 10, - }, - 'body': [{'hash': txHash, 'canRevert': True}, - {'tx': tx2.rawTransaction.hex(), 'canRevert': True}], - 'privacy': { - 'hints': { - 'tx_hash': True, - 'calldata': True, - 'logs': True, - 'function_selector': True, +import asyncio +from mev_share_py.api.types import BundleParams +from mev_share_py.client import MevShareClient + + +async def sim_private_tx_backrun(): + """ + Generate a bundle with two private transactions and simulate it. + The "to" address and "private_key" are read from the config.json file. + :return: + """ + tx1 = '' + tx2 = '' + client = MevShareClient.from_config(network='goerli', config_dir='../config.json') + tx1 = tx1 + tx2 = tx2 + block_number = await client.w3_async.eth.block_number + params = { + 'inclusion': { + 'block': block_number + 1, + 'max_block': block_number + 10 }, - # 'builders': ['flashbots'] + 'body': [{'tx': tx1.rawTransaction.hex(), 'canRevert': True}, + {'tx': tx2.rawTransaction.hex(), 'canRevert': True}], + 'privacy': { + 'hints': { + 'tx_hash': True, + 'calldata': True, + 'logs': True, + 'function_selector': True, + }, + # 'builders': ['flashbots'] + } } -} -sim_options = { - 'parent_block': TARGET_BLOCK - 1, - # 'block_number': Optional[int], - # 'coinbase': Optional[str], - # 'timestamp': Optional[int], - # 'gas_limit': Optional[int], - # 'base_fee': Optional[int], - # 'timeout': Optional[int], -} -params = BundleParams(**params) -await client.simulate_bundle(params, sim_options) + sim_options = { + 'parent_block': block_number, + } + params = BundleParams(**params) + return await client.simulate_bundle(params, sim_options) + +if __name__ == "__main__": + res = asyncio.run(sim_private_tx_backrun()) + print(res) + ``` @@ -230,7 +256,9 @@ await client.simulate_bundle(params, sim_options) Get information about the event history endpoint for use in get_event_history. ```python -client = MevShareClient(stream_url=STREAM_URL) +import asyncio +from mev_share_py.client import MevShareClient +client = MevShareClient.from_config('goerli', '../config.json') his_info = asyncio.run(client.get_event_history_info()) ``` Returns a dictionary: @@ -249,7 +277,7 @@ Returns a dictionary: Get historical event stream data for last 100 blocks. ```python -params = {"blockStart": his_info['maxBlock'] - 100, "blockEnd": his_info['maxBlock']} +params = {"blockStart": his_info['maxBlock'] - 1, "blockEnd": his_info['maxBlock']} his = asyncio.run(client.get_event_history(params=params)) ``` @@ -259,7 +287,28 @@ All examples are located in the [```examples```](#/examples) directory. ## License -This project is licensed under the MIT License. +MIT License + +Copyright (c) 2023 Žiga Mrzljak / Flashbots + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ## Acknowledgments