1
1
//! A generic Flashbots bundle API wrapper.
2
+ use std:: borrow:: Cow ;
3
+
2
4
use crate :: config:: BuilderConfig ;
3
5
use alloy:: {
4
6
primitives:: { BlockNumber , keccak256} ,
5
- rpc:: types:: mev:: { EthBundleHash , MevSendBundle , SimBundleResponse } ,
7
+ rpc:: {
8
+ json_rpc:: { Id , Response , ResponsePayload , RpcRecv , RpcSend } ,
9
+ types:: mev:: { EthBundleHash , MevSendBundle , SimBundleResponse } ,
10
+ } ,
6
11
signers:: Signer ,
7
12
} ;
8
- use eyre:: Context as _;
9
13
use init4_bin_base:: utils:: signer:: LocalOrAws ;
10
14
use reqwest:: header:: CONTENT_TYPE ;
11
15
use serde_json:: json;
12
16
13
- /// A wrapper over a `Provider` that adds Flashbots MEV bundle helpers .
17
+ /// An RPC connection to relevant Flashbots endpoints .
14
18
#[ derive( Debug ) ]
15
19
pub struct Flashbots {
16
20
/// The base URL for the Flashbots API.
@@ -34,48 +38,43 @@ impl Flashbots {
34
38
}
35
39
36
40
/// Sends a bundle via `mev_sendBundle`.
37
- pub async fn send_bundle ( & self , bundle : MevSendBundle ) -> eyre:: Result < EthBundleHash > {
38
- let params = serde_json:: to_value ( bundle) ?;
39
- let v = self . raw_call ( "mev_sendBundle" , params) . await ?;
40
- let hash: EthBundleHash =
41
- serde_json:: from_value ( v. get ( "result" ) . cloned ( ) . unwrap_or ( serde_json:: Value :: Null ) ) ?;
42
- Ok ( hash)
41
+ pub async fn send_bundle ( & self , bundle : & MevSendBundle ) -> eyre:: Result < EthBundleHash > {
42
+ self . raw_call ( "mev_sendBundle" , & [ bundle] ) . await
43
43
}
44
44
45
45
/// Simulate a bundle via `mev_simBundle`.
46
- pub async fn simulate_bundle ( & self , bundle : MevSendBundle ) -> eyre:: Result < ( ) > {
47
- let params = serde_json:: to_value ( bundle) ?;
48
- let v = self . raw_call ( "mev_simBundle" , params) . await ?;
49
- let resp: SimBundleResponse =
50
- serde_json:: from_value ( v. get ( "result" ) . cloned ( ) . unwrap_or ( serde_json:: Value :: Null ) ) ?;
46
+ pub async fn simulate_bundle ( & self , bundle : & MevSendBundle ) -> eyre:: Result < ( ) > {
47
+ let resp: SimBundleResponse = self . raw_call ( "mev_simBundle" , & [ bundle] ) . await ?;
51
48
dbg ! ( "successfully simulated bundle" , & resp) ;
52
49
Ok ( ( ) )
53
50
}
54
51
55
52
/// Fetches the bundle status by hash
56
53
pub async fn bundle_status (
57
54
& self ,
58
- _hash : EthBundleHash ,
55
+ hash : EthBundleHash ,
59
56
block_number : BlockNumber ,
60
57
) -> eyre:: Result < ( ) > {
61
- let params = json ! ( { "bundleHash" : _hash, "blockNumber" : block_number } ) ;
62
- let _ = self . raw_call ( "flashbots_getBundleStatsV2" , params) . await ?;
58
+ let params = json ! ( { "bundleHash" : hash, "blockNumber" : block_number } ) ;
59
+ let _resp: serde_json:: Value =
60
+ self . raw_call ( "flashbots_getBundleStatsV2" , & [ params] ) . await ?;
61
+
63
62
Ok ( ( ) )
64
63
}
65
64
66
65
/// Makes a raw JSON-RPC call with the Flashbots signature header to the method with the given params.
67
- async fn raw_call (
66
+ async fn raw_call < Params : RpcSend , Payload : RpcRecv > (
68
67
& self ,
69
68
method : & str ,
70
- params : serde_json :: Value ,
71
- ) -> eyre:: Result < serde_json :: Value > {
72
- let params = match params {
73
- serde_json :: Value :: Array ( _ ) => params ,
74
- other => serde_json :: Value :: Array ( vec ! [ other ] ) ,
75
- } ;
76
-
77
- let body = json ! ( { "jsonrpc" : "2.0" , "id" : 1 , "method" : method , "params" : params } ) ;
78
- let body_bz = serde_json :: to_vec ( & body ) ? ;
69
+ params : & Params ,
70
+ ) -> eyre:: Result < Payload > {
71
+ let req = alloy :: rpc :: json_rpc :: Request :: new (
72
+ Cow :: Owned ( method . to_string ( ) ) ,
73
+ Id :: Number ( 1 ) ,
74
+ params ,
75
+ ) ;
76
+ let body_bz = serde_json :: to_vec ( & req ) ? ;
77
+ drop ( req ) ;
79
78
80
79
let value = self . compute_signature ( & body_bz) . await ?;
81
80
@@ -88,18 +87,19 @@ impl Flashbots {
88
87
. send ( )
89
88
. await ?;
90
89
91
- let text = resp. text ( ) . await ?;
92
- let v: serde_json:: Value =
93
- serde_json:: from_str ( & text) . wrap_err ( "failed to parse flashbots JSON" ) ?;
94
- if let Some ( err) = v. get ( "error" ) {
95
- eyre:: bail!( "flashbots error: {err}" ) ;
90
+ let resp: Response < Payload > = resp. json ( ) . await ?;
91
+
92
+ match resp. payload {
93
+ ResponsePayload :: Success ( payload) => Ok ( payload) ,
94
+ ResponsePayload :: Failure ( err) => {
95
+ eyre:: bail!( "flashbots error: {err}" ) ;
96
+ }
96
97
}
97
- Ok ( v)
98
98
}
99
99
100
100
/// Builds an EIP-191 signature for the given body bytes.
101
101
async fn compute_signature ( & self , body_bz : & [ u8 ] ) -> Result < String , eyre:: Error > {
102
- let payload = format ! ( "0x{:x}" , keccak256( body_bz) ) ;
102
+ let payload = keccak256 ( body_bz) . to_string ( ) ;
103
103
let signature = self . signer . sign_message ( payload. as_ref ( ) ) . await ?;
104
104
dbg ! ( signature. to_string( ) ) ;
105
105
let address = self . signer . address ( ) ;
0 commit comments