22Minimal viable example of flashbots usage with dynamic fee transactions.
33Sends a bundle of two transactions which transfer some ETH into a random account.
44
5+ "eth_sendBundle" is a generic method that can be used to send a bundle to any relay.
6+ For instance, you can use the following relay URLs:
7+ titan: 'https://rpc.titanbuilder.xyz/'
8+ beaver: 'https://rpc.beaverbuild.org/'
9+ builder69: 'https://builder0x69.io/'
10+ rsync: 'https://rsync-builder.xyz/'
11+ flashbots: 'https://relay.flashbots.net'
12+
13+ You can simply replace the URL in the flashbot method to use a different relay like:
14+ flashbot(w3, signer, YOUR_CHOSEN_RELAY_URL)
15+
516Environment Variables:
617- ETH_SENDER_KEY: Private key of account which will send the ETH.
718- ETH_SIGNER_KEY: Private key of account which will sign the bundle.
819 - This account is only used for reputation on flashbots and should be empty.
9- - PROVIDER_URL: HTTP JSON-RPC Ethereum provider URL.
20+ - PROVIDER_URL: (Optional) HTTP JSON-RPC Ethereum provider URL. If not set, Flashbots Protect RPC will be used .
1021"""
1122
1223import os
1324import secrets
1425from uuid import uuid4
26+
1527from eth_account .account import Account
1628from eth_account .signers .local import LocalAccount
17- from flashbots import flashbot
18- from web3 import Web3 , HTTPProvider
29+ from web3 import HTTPProvider , Web3
1930from web3 .exceptions import TransactionNotFound
2031from web3 .types import TxParams
2132
22- # change this to `False` if you want to use mainnet
23- USE_GOERLI = True
24- CHAIN_ID = 5 if USE_GOERLI else 1
33+ from flashbots import flashbot
34+
35+ # Define the network to use
36+ NETWORK = "holesky" # Options: "sepolia", "holesky", "mainnet"
37+
38+ # Define chain IDs and Flashbots Protect RPC URLs
39+ NETWORK_CONFIG = {
40+ "sepolia" : {
41+ "chain_id" : 11155111 ,
42+ "provider_url" : "https://rpc-sepolia.flashbots.net" ,
43+ "relay_url" : "https://relay-sepolia.flashbots.net" ,
44+ },
45+ "holesky" : {
46+ "chain_id" : 17000 ,
47+ "provider_url" : "https://rpc-holesky.flashbots.net" ,
48+ "relay_url" : "https://relay-holesky.flashbots.net" ,
49+ },
50+ "mainnet" : {
51+ "chain_id" : 1 ,
52+ "provider_url" : "https://rpc.flashbots.net" ,
53+ "relay_url" : None , # Mainnet uses default Flashbots relay
54+ },
55+ }
2556
2657
2758def env (key : str ) -> str :
@@ -42,9 +73,20 @@ def main() -> None:
4273 # NOTE: this account should not store funds
4374 signer : LocalAccount = Account .from_key (env ("ETH_SIGNER_KEY" ))
4475
45- w3 = Web3 (HTTPProvider (env ("PROVIDER_URL" )))
46- if USE_GOERLI :
47- flashbot (w3 , signer , "https://relay-goerli.flashbots.net" )
76+ # Use user-provided RPC URL if available, otherwise use Flashbots Protect RPC
77+ user_provider_url = env ("PROVIDER_URL" )
78+ if user_provider_url :
79+ provider_url = user_provider_url
80+ print (f"Using user-provided RPC: { provider_url } " )
81+ else :
82+ provider_url = NETWORK_CONFIG [NETWORK ]["provider_url" ]
83+ print (f"Using Flashbots Protect RPC: { provider_url } " )
84+
85+ w3 = Web3 (HTTPProvider (provider_url ))
86+
87+ relay_url = NETWORK_CONFIG [NETWORK ]["relay_url" ]
88+ if relay_url :
89+ flashbot (w3 , signer , relay_url )
4890 else :
4991 flashbot (w3 , signer )
5092
@@ -69,7 +111,7 @@ def main() -> None:
69111 "maxFeePerGas" : Web3 .toWei (200 , "gwei" ),
70112 "maxPriorityFeePerGas" : Web3 .toWei (50 , "gwei" ),
71113 "nonce" : nonce ,
72- "chainId" : CHAIN_ID ,
114+ "chainId" : NETWORK_CONFIG [ NETWORK ][ "chain_id" ] ,
73115 "type" : 2 ,
74116 }
75117 tx1_signed = sender .sign_transaction (tx1 )
@@ -81,7 +123,7 @@ def main() -> None:
81123 "maxFeePerGas" : Web3 .toWei (200 , "gwei" ),
82124 "maxPriorityFeePerGas" : Web3 .toWei (50 , "gwei" ),
83125 "nonce" : nonce + 1 ,
84- "chainId" : CHAIN_ID ,
126+ "chainId" : NETWORK_CONFIG [ NETWORK ][ "chain_id" ] ,
85127 "type" : 2 ,
86128 }
87129
@@ -93,14 +135,19 @@ def main() -> None:
93135 # keep trying to send bundle until it gets mined
94136 while True :
95137 block = w3 .eth .block_number
96- print (f"Simulating on block { block } " )
97- # simulate bundle on current block
98- try :
99- w3 .flashbots .simulate (bundle , block )
100- print ("Simulation successful." )
101- except Exception as e :
102- print ("Simulation error" , e )
103- return
138+
139+ # Simulation is only supported on mainnet
140+ if NETWORK == "mainnet" :
141+ print (f"Simulating on block { block } " )
142+ # Simulate bundle on current block.
143+ # If your RPC provider is not fast enough, you may get "block extrapolation negative"
144+ # error message triggered by "extrapolate_timestamp" function in "flashbots.py".
145+ try :
146+ w3 .flashbots .simulate (bundle , block )
147+ print ("Simulation successful." )
148+ except Exception as e :
149+ print ("Simulation error" , e )
150+ return
104151
105152 # send bundle targeting next block
106153 print (f"Sending bundle targeting block { block + 1 } " )
0 commit comments