Skip to content

Commit 53f9152

Browse files
committed
wip: flashbots still not landing txs or bundles :(
1 parent 7941951 commit 53f9152

File tree

3 files changed

+255
-9
lines changed

3 files changed

+255
-9
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ signet-constants = { version = "0.10.0" }
2020
signet-tx-cache = { version = "0.10.0", optional = true }
2121

2222
# alloy
23-
alloy = { version = "1.0.25", optional = true, default-features = false, features = ["std", "signer-local", "consensus", "network"] }
23+
alloy = { version = "1.0.25", optional = true, default-features = false, features = ["std", "signer-local", "consensus", "network", "provider-mev-api"] }
2424

2525
# Tracing
2626
tracing = "0.1.40"

src/utils/flashbots.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,15 @@ impl Flashbots {
7373

7474
/// Sends a bundle via `mev_sendBundle`.
7575
pub async fn send_bundle(&self, bundle: &MevSendBundle) -> eyre::Result<EthBundleHash> {
76-
self.raw_call("mev_sendBundle", &[bundle]).await
76+
let resp = self.raw_call("mev_sendBundle", &[bundle]).await?;
77+
dbg!("sim bundle response", &resp);
78+
Ok(resp)
7779
}
7880

7981
/// Simulate a bundle via `mev_simBundle`.
8082
pub async fn simulate_bundle(&self, bundle: &MevSendBundle) -> eyre::Result<()> {
8183
let resp: SimBundleResponse = self.raw_call("mev_simBundle", &[bundle]).await?;
82-
dbg!("sim bundle response ###", resp);
84+
dbg!("send bundle response ###", resp);
8385
Ok(())
8486
}
8587

tests/flashbots.rs

Lines changed: 250 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,27 @@
22

33
use alloy::{
44
consensus::constants::GWEI_TO_WEI,
5-
eips::Encodable2718,
5+
eips::{BlockId, Encodable2718},
66
network::EthereumWallet,
77
primitives::{B256, U256},
88
providers::{
9+
ext::MevApi,
910
fillers::{
1011
BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller,
1112
WalletFiller,
1213
},
1314
Identity, Provider, ProviderBuilder, SendableTx,
1415
},
1516
rpc::types::{
16-
mev::{BundleItem, Inclusion, MevSendBundle, Privacy, ProtocolVersion},
17+
mev::{
18+
BundleItem, EthCallBundle, EthSendBundle, EthSendPrivateTransaction, Inclusion,
19+
MevSendBundle, Privacy, PrivateTransactionPreferences, ProtocolVersion,
20+
},
1721
TransactionRequest,
1822
},
1923
signers::{local::PrivateKeySigner, Signer},
2024
};
25+
use eyre::Context;
2126
use init4_bin_base::{
2227
deps::tracing::debug,
2328
deps::tracing_subscriber::{
@@ -58,7 +63,7 @@ type SepoliaProvider = FillProvider<
5863
>;
5964

6065
#[allow(clippy::type_complexity)]
61-
fn get_sepolia(builder_key: LocalOrAws) -> SepoliaProvider {
66+
fn get_sepolia_host(builder_key: LocalOrAws) -> SepoliaProvider {
6267
ProviderBuilder::new()
6368
.wallet(builder_key.clone())
6469
.connect_http(
@@ -72,7 +77,7 @@ fn get_sepolia(builder_key: LocalOrAws) -> SepoliaProvider {
7277
#[ignore = "integration test"]
7378
async fn test_simulate_valid_bundle_sepolia() {
7479
let flashbots = &*TEST_PROVIDER;
75-
let sepolia = get_sepolia(DEFAULT_BUILDER_KEY.clone());
80+
let sepolia = get_sepolia_host(DEFAULT_BUILDER_KEY.clone());
7681

7782
let req = TransactionRequest::default()
7883
.to(DEFAULT_BUILDER_KEY.address())
@@ -121,7 +126,7 @@ async fn test_send_valid_bundle_sepolia() {
121126
.expect("failed to load builder key");
122127

123128
let flashbots = Flashbots::new(FLASHBOTS_URL.clone(), builder_key.clone());
124-
let sepolia = get_sepolia(builder_key.clone());
129+
let sepolia = get_sepolia_host(builder_key.clone());
125130

126131
let req = TransactionRequest::default()
127132
.to(builder_key.address())
@@ -159,6 +164,7 @@ async fn test_send_valid_bundle_sepolia() {
159164
bundle_body,
160165
);
161166
bundle.inclusion = Inclusion::at_block(target_block);
167+
162168
// bundle.privacy = Some(Privacy::default().with_builders(Some(vec![
163169
// "flashbots".to_string(),
164170
// "rsync".to_string(),
@@ -167,7 +173,10 @@ async fn test_send_valid_bundle_sepolia() {
167173
// ])));
168174

169175
dbg!(latest_block);
170-
dbg!(&bundle.inclusion.block_number(), &bundle.inclusion.max_block_number());
176+
dbg!(
177+
&bundle.inclusion.block_number(),
178+
&bundle.inclusion.max_block_number()
179+
);
171180

172181
flashbots.simulate_bundle(&bundle).await.unwrap();
173182

@@ -294,3 +303,238 @@ pub fn setup_logging() {
294303
let registry = registry().with(fmt);
295304
let _ = registry.try_init();
296305
}
306+
307+
#[tokio::test]
308+
#[ignore = "integration test"]
309+
async fn test_alloy_flashbots_sepolia() {
310+
setup_logging();
311+
312+
let raw_key = env::var("BUILDER_KEY").expect("BUILDER_KEY must be set");
313+
let builder_key = LocalOrAws::load(&raw_key, Some(11155111))
314+
.await
315+
.expect("failed to load builder key");
316+
317+
let flashbots = ProviderBuilder::new()
318+
.wallet(builder_key.clone())
319+
.connect_http("https://relay-sepolia.flashbots.net".parse().unwrap());
320+
321+
let sepolia_host = get_sepolia_host(builder_key.clone());
322+
323+
let req = TransactionRequest::default()
324+
.to(builder_key.address())
325+
.value(U256::from(0u64))
326+
.gas_limit(21_000)
327+
.max_fee_per_gas((50 * GWEI_TO_WEI).into())
328+
.max_priority_fee_per_gas((2 * GWEI_TO_WEI).into())
329+
.from(builder_key.address());
330+
331+
let block = sepolia_host
332+
.get_block(BlockId::latest())
333+
.await
334+
.unwrap()
335+
.unwrap();
336+
let target_block = block.number() + 1;
337+
dbg!("preparing bundle for", target_block);
338+
339+
let SendableTx::Envelope(tx) = sepolia_host.fill(req.clone()).await.unwrap() else {
340+
panic!("expected filled tx");
341+
};
342+
dbg!("prepared transaction request", tx.clone());
343+
let tx_bytes = tx.encoded_2718();
344+
345+
let bundle = EthSendBundle {
346+
txs: vec![tx_bytes.clone().into()],
347+
block_number: target_block,
348+
min_timestamp: None,
349+
max_timestamp: None,
350+
reverting_tx_hashes: vec![],
351+
replacement_uuid: None,
352+
dropping_tx_hashes: vec![],
353+
refund_percent: None,
354+
refund_recipient: None,
355+
refund_tx_hashes: vec![],
356+
..Default::default()
357+
};
358+
359+
let call_bundle = EthCallBundle {
360+
txs: vec![tx_bytes.clone().into()],
361+
block_number: target_block,
362+
..Default::default()
363+
};
364+
let sim = flashbots
365+
.call_bundle(call_bundle)
366+
.with_auth(builder_key.clone());
367+
dbg!(sim.await.unwrap());
368+
369+
let result = flashbots.send_bundle(bundle).with_auth(builder_key.clone());
370+
dbg!(result.await.unwrap());
371+
}
372+
373+
#[tokio::test]
374+
#[ignore = "integration test"]
375+
async fn test_mev_endpoints() {
376+
setup_logging();
377+
378+
let raw_key = env::var("BUILDER_KEY").expect("BUILDER_KEY must be set");
379+
let builder_key = LocalOrAws::load(&raw_key, Some(11155111))
380+
.await
381+
.expect("failed to load builder key");
382+
383+
let flashbots = ProviderBuilder::new()
384+
.wallet(builder_key.clone())
385+
.connect_http("https://relay-sepolia.flashbots.net".parse().unwrap());
386+
387+
let old_flashbots = Flashbots::new(
388+
"https://relay-sepolia.flashbots.net".parse().unwrap(),
389+
builder_key.clone(),
390+
);
391+
392+
let sepolia_host = get_sepolia_host(builder_key.clone());
393+
394+
let block = sepolia_host
395+
.get_block(BlockId::latest())
396+
.await
397+
.unwrap()
398+
.unwrap();
399+
let target_block = block.number() + 1;
400+
dbg!("preparing bundle for", target_block);
401+
402+
let req = TransactionRequest::default()
403+
.to(builder_key.address())
404+
.value(U256::from(0u64))
405+
.gas_limit(21_000)
406+
.max_fee_per_gas((50 * GWEI_TO_WEI).into())
407+
.max_priority_fee_per_gas((2 * GWEI_TO_WEI).into())
408+
.from(builder_key.address());
409+
410+
let SendableTx::Envelope(tx) = sepolia_host.fill(req.clone()).await.unwrap() else {
411+
panic!("expected filled tx");
412+
};
413+
dbg!("prepared transaction request", tx.clone());
414+
let tx_bytes = tx.encoded_2718();
415+
416+
let bundle = MevSendBundle::new(
417+
target_block,
418+
None,
419+
ProtocolVersion::V0_1,
420+
vec![BundleItem::Tx {
421+
tx: tx_bytes.clone().into(),
422+
can_revert: false,
423+
}],
424+
);
425+
dbg!("bundle contents", &bundle);
426+
427+
let _ = old_flashbots.simulate_bundle(&bundle).await.unwrap();
428+
429+
let result = flashbots
430+
.send_mev_bundle(bundle)
431+
.with_auth(builder_key.clone());
432+
dbg!("send mev bundle:", result.await.unwrap());
433+
434+
let result = flashbots
435+
.send_private_transaction(EthSendPrivateTransaction {
436+
tx: tx_bytes.into(),
437+
max_block_number: Some(target_block + 5),
438+
preferences: PrivateTransactionPreferences::default(),
439+
})
440+
.with_auth(builder_key.clone());
441+
dbg!("send private transaction", result.await.unwrap());
442+
}
443+
444+
#[tokio::test]
445+
#[ignore = "integration test"]
446+
async fn test_alloy_flashbots_mainnet() {
447+
setup_logging();
448+
449+
let raw_key = env::var("BUILDER_KEY").expect("BUILDER_KEY must be set");
450+
let builder_key = LocalOrAws::load(&raw_key, Some(11155111))
451+
.await
452+
.expect("failed to load builder key");
453+
454+
let flashbots = ProviderBuilder::new()
455+
.wallet(builder_key.clone())
456+
.connect_http("https://relay-sepolia.flashbots.net".parse().unwrap());
457+
458+
let sepolia_host = get_sepolia_host(builder_key.clone());
459+
460+
let req = TransactionRequest::default()
461+
.to(builder_key.address())
462+
.value(U256::from(0u64))
463+
.gas_limit(21_000)
464+
.max_fee_per_gas((50 * GWEI_TO_WEI).into())
465+
.max_priority_fee_per_gas((2 * GWEI_TO_WEI).into())
466+
.from(builder_key.address());
467+
468+
let block = sepolia_host
469+
.get_block(BlockId::latest())
470+
.await
471+
.unwrap()
472+
.unwrap();
473+
let target_block = block.number() + 1;
474+
dbg!("preparing bundle for", target_block);
475+
476+
let target_block = block.number() + 1;
477+
dbg!("preparing bundle for", target_block);
478+
479+
let SendableTx::Envelope(tx) = sepolia_host.fill(req.clone()).await.unwrap() else {
480+
panic!("expected filled tx");
481+
};
482+
dbg!("prepared transaction request", tx.clone());
483+
let tx_bytes = tx.encoded_2718();
484+
485+
let bundle = EthSendBundle {
486+
txs: vec![tx_bytes.clone().into()],
487+
block_number: target_block,
488+
..Default::default()
489+
};
490+
491+
let call_bundle = EthCallBundle {
492+
txs: vec![tx_bytes.clone().into()],
493+
block_number: target_block,
494+
..Default::default()
495+
};
496+
497+
let sim = flashbots
498+
.call_bundle(call_bundle)
499+
.with_auth(builder_key.clone());
500+
dbg!(sim.await.unwrap());
501+
502+
let result = flashbots.send_bundle(bundle).with_auth(builder_key.clone());
503+
dbg!(result.await.unwrap());
504+
}
505+
506+
#[tokio::test]
507+
#[ignore = "integration test"]
508+
pub async fn test_send_single_tx_sepolia() {
509+
setup_logging();
510+
511+
let raw_key = env::var("BUILDER_KEY").expect("BUILDER_KEY must be set");
512+
let builder_key = LocalOrAws::load(&raw_key, Some(11155111))
513+
.await
514+
.expect("failed to load builder key");
515+
516+
let sepolia_host = get_sepolia_host(builder_key.clone());
517+
518+
let req = TransactionRequest::default()
519+
.to(builder_key.address())
520+
.value(U256::from(0u64))
521+
.gas_limit(21_000)
522+
.max_fee_per_gas((50 * GWEI_TO_WEI).into())
523+
.max_priority_fee_per_gas((2 * GWEI_TO_WEI).into())
524+
.from(builder_key.address());
525+
526+
let SendableTx::Envelope(tx) = sepolia_host.fill(req.clone()).await.unwrap() else {
527+
panic!("expected filled tx");
528+
};
529+
dbg!("prepared transaction request", tx.clone());
530+
let tx_bytes = tx.encoded_2718();
531+
532+
let pending_tx = sepolia_host
533+
.send_raw_transaction(&tx_bytes)
534+
.await
535+
.expect("should send tx")
536+
.watch()
537+
.await
538+
.unwrap();
539+
dbg!(pending_tx);
540+
}

0 commit comments

Comments
 (0)