Skip to content

Commit c00711a

Browse files
Add new simple examples for Sepolia testnet (#89)
* Only execute "eth_callBundle" when in mainnet as the sunset of Goerli. * Implement new simple example based on "simple.py". * 1. Change testnet as sepolia; 2. Provide extra builder RPCs compatible with flashbots. * Update simple_new.py example for multi-network support - Add support for Sepolia, Holesky, and Mainnet networks - Introduce NETWORK_CONFIG for network-specific settings - Update provider and relay URL handling - Improve comments and documentation - Enhance error handling and logging * Replace simple.py with simple_new.py * Update .gitignore * Resolve black formatter issue --------- Co-authored-by: George Zhang <georgezhangtj97@gmail.com>
1 parent c3a1216 commit c00711a

3 files changed

Lines changed: 80 additions & 28 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ __pycache__
44
build/
55
dist/
66
flashbots.egg-info/
7+
.venv/
8+
.mise.toml

examples/simple.py

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,57 @@
22
Minimal viable example of flashbots usage with dynamic fee transactions.
33
Sends 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+
516
Environment 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

1223
import os
1324
import secrets
1425
from uuid import uuid4
26+
1527
from eth_account.account import Account
1628
from eth_account.signers.local import LocalAccount
17-
from flashbots import flashbot
18-
from web3 import Web3, HTTPProvider
29+
from web3 import HTTPProvider, Web3
1930
from web3.exceptions import TransactionNotFound
2031
from 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

2758
def 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}")

flashbots/flashbots.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ def __init__(self, w3: Web3, signed_tx: HexBytes, max_block_number: int):
101101
def wait(self) -> bool:
102102
"""Waits up to max block number, returns `True` if/when tx has been mined.
103103
104-
If tx has not been mined by the time the current block > max_block_number, returns `False`."""
104+
If tx has not been mined by the time the current block > max_block_number, returns `False`.
105+
"""
105106
while True:
106107
try:
107108
self.w3.eth.get_transaction(self.tx["hash"])
@@ -220,12 +221,12 @@ def send_raw_bundle_munger(
220221
"blockNumber": hex(target_block_number),
221222
"minTimestamp": opts["minTimestamp"] if "minTimestamp" in opts else 0,
222223
"maxTimestamp": opts["maxTimestamp"] if "maxTimestamp" in opts else 0,
223-
"revertingTxHashes": opts["revertingTxHashes"]
224-
if "revertingTxHashes" in opts
225-
else [],
226-
"replacementUuid": opts["replacementUuid"]
227-
if "replacementUuid" in opts
228-
else None,
224+
"revertingTxHashes": (
225+
opts["revertingTxHashes"] if "revertingTxHashes" in opts else []
226+
),
227+
"replacementUuid": (
228+
opts["replacementUuid"] if "replacementUuid" in opts else None
229+
),
229230
}
230231
]
231232

@@ -400,7 +401,8 @@ def send_private_transaction_munger(
400401
) -> Any:
401402
"""Sends a single transaction to Flashbots.
402403
403-
If `max_block_number` is set, Flashbots will try to submit the transaction in every block <= that block (max 25 blocks from present)."""
404+
If `max_block_number` is set, Flashbots will try to submit the transaction in every block <= that block (max 25 blocks from present).
405+
"""
404406
signed_transaction: str
405407
if "signed_transaction" in transaction:
406408
signed_transaction = transaction["signed_transaction"]
@@ -438,7 +440,8 @@ def cancel_private_transaction_munger(
438440
) -> bool:
439441
"""Stops a private transaction from being sent to miners by Flashbots.
440442
441-
Note: if a transaction has already been received by a miner, it may still be mined. This simply stops further submissions."""
443+
Note: if a transaction has already been received by a miner, it may still be mined. This simply stops further submissions.
444+
"""
442445
params = {
443446
"txHash": tx_hash,
444447
}

0 commit comments

Comments
 (0)