22
33use 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 ;
2126use 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" ]
7378async 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