2
2
3
3
use alloy:: {
4
4
consensus:: constants:: GWEI_TO_WEI ,
5
- eips:: Encodable2718 ,
5
+ eips:: { BlockId , Encodable2718 } ,
6
6
network:: EthereumWallet ,
7
7
primitives:: { B256 , U256 } ,
8
8
providers:: {
9
+ ext:: MevApi ,
9
10
fillers:: {
10
11
BlobGasFiller , ChainIdFiller , FillProvider , GasFiller , JoinFill , NonceFiller ,
11
12
WalletFiller ,
12
13
} ,
13
14
Identity , Provider , ProviderBuilder , SendableTx ,
14
15
} ,
15
16
rpc:: types:: {
16
- mev:: { BundleItem , Inclusion , MevSendBundle , Privacy , ProtocolVersion } ,
17
+ mev:: {
18
+ BundleItem , EthCallBundle , EthSendBundle , EthSendPrivateTransaction , Inclusion ,
19
+ MevSendBundle , Privacy , PrivateTransactionPreferences , ProtocolVersion ,
20
+ } ,
17
21
TransactionRequest ,
18
22
} ,
19
23
signers:: { local:: PrivateKeySigner , Signer } ,
20
24
} ;
25
+ use eyre:: Context ;
21
26
use init4_bin_base:: {
22
27
deps:: tracing:: debug,
23
28
deps:: tracing_subscriber:: {
@@ -58,7 +63,7 @@ type SepoliaProvider = FillProvider<
58
63
> ;
59
64
60
65
#[ allow( clippy:: type_complexity) ]
61
- fn get_sepolia ( builder_key : LocalOrAws ) -> SepoliaProvider {
66
+ fn get_sepolia_host ( builder_key : LocalOrAws ) -> SepoliaProvider {
62
67
ProviderBuilder :: new ( )
63
68
. wallet ( builder_key. clone ( ) )
64
69
. connect_http (
@@ -72,7 +77,7 @@ fn get_sepolia(builder_key: LocalOrAws) -> SepoliaProvider {
72
77
#[ ignore = "integration test" ]
73
78
async fn test_simulate_valid_bundle_sepolia ( ) {
74
79
let flashbots = & * TEST_PROVIDER ;
75
- let sepolia = get_sepolia ( DEFAULT_BUILDER_KEY . clone ( ) ) ;
80
+ let sepolia = get_sepolia_host ( DEFAULT_BUILDER_KEY . clone ( ) ) ;
76
81
77
82
let req = TransactionRequest :: default ( )
78
83
. to ( DEFAULT_BUILDER_KEY . address ( ) )
@@ -121,7 +126,7 @@ async fn test_send_valid_bundle_sepolia() {
121
126
. expect ( "failed to load builder key" ) ;
122
127
123
128
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 ( ) ) ;
125
130
126
131
let req = TransactionRequest :: default ( )
127
132
. to ( builder_key. address ( ) )
@@ -159,6 +164,7 @@ async fn test_send_valid_bundle_sepolia() {
159
164
bundle_body,
160
165
) ;
161
166
bundle. inclusion = Inclusion :: at_block ( target_block) ;
167
+
162
168
// bundle.privacy = Some(Privacy::default().with_builders(Some(vec![
163
169
// "flashbots".to_string(),
164
170
// "rsync".to_string(),
@@ -167,7 +173,10 @@ async fn test_send_valid_bundle_sepolia() {
167
173
// ])));
168
174
169
175
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
+ ) ;
171
180
172
181
flashbots. simulate_bundle ( & bundle) . await . unwrap ( ) ;
173
182
@@ -294,3 +303,238 @@ pub fn setup_logging() {
294
303
let registry = registry ( ) . with ( fmt) ;
295
304
let _ = registry. try_init ( ) ;
296
305
}
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