11//! A generic Flashbots bundle API wrapper.
2+ use std:: borrow:: Cow ;
3+
24use crate :: config:: BuilderConfig ;
35use alloy:: {
46 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+ } ,
611 signers:: Signer ,
712} ;
813use eyre:: Context as _;
914use init4_bin_base:: utils:: signer:: LocalOrAws ;
1015use reqwest:: header:: CONTENT_TYPE ;
1116use serde_json:: json;
1217
13- /// A wrapper over a `Provider` that adds Flashbots MEV bundle helpers .
18+ /// An RPC connection to relevant Flashbots endpoints .
1419#[ derive( Debug ) ]
1520pub struct Flashbots {
1621 /// The base URL for the Flashbots API.
@@ -34,48 +39,43 @@ impl Flashbots {
3439 }
3540
3641 /// 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)
42+ pub async fn send_bundle ( & self , bundle : & MevSendBundle ) -> eyre:: Result < EthBundleHash > {
43+ self . raw_call ( "mev_sendBundle" , & [ bundle] ) . await
4344 }
4445
4546 /// 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 ) ) ?;
47+ pub async fn simulate_bundle ( & self , bundle : & MevSendBundle ) -> eyre:: Result < ( ) > {
48+ let resp: SimBundleResponse = self . raw_call ( "mev_simBundle" , & [ bundle] ) . await ?;
5149 dbg ! ( "successfully simulated bundle" , & resp) ;
5250 Ok ( ( ) )
5351 }
5452
5553 /// Fetches the bundle status by hash
5654 pub async fn bundle_status (
5755 & self ,
58- _hash : EthBundleHash ,
56+ hash : EthBundleHash ,
5957 block_number : BlockNumber ,
6058 ) -> eyre:: Result < ( ) > {
61- let params = json ! ( { "bundleHash" : _hash, "blockNumber" : block_number } ) ;
62- let _ = self . raw_call ( "flashbots_getBundleStatsV2" , params) . await ?;
59+ let params = json ! ( { "bundleHash" : hash, "blockNumber" : block_number } ) ;
60+ let _resp: serde_json:: Value =
61+ self . raw_call ( "flashbots_getBundleStatsV2" , & [ params] ) . await ?;
62+
6363 Ok ( ( ) )
6464 }
6565
6666 /// Makes a raw JSON-RPC call with the Flashbots signature header to the method with the given params.
67- async fn raw_call (
67+ async fn raw_call < Params : RpcSend , Payload : RpcRecv > (
6868 & self ,
6969 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 ) ? ;
70+ params : & Params ,
71+ ) -> eyre:: Result < Payload > {
72+ let req = alloy :: rpc :: json_rpc :: Request :: new (
73+ Cow :: Owned ( method . to_string ( ) ) ,
74+ Id :: Number ( 1 ) ,
75+ params ,
76+ ) ;
77+ let body_bz = serde_json :: to_vec ( & req ) ? ;
78+ drop ( req ) ;
7979
8080 let value = self . compute_signature ( & body_bz) . await ?;
8181
@@ -89,17 +89,21 @@ impl Flashbots {
8989 . await ?;
9090
9191 let text = resp. text ( ) . await ?;
92- let v: serde_json:: Value =
92+
93+ let resp: Response < Payload > =
9394 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}" ) ;
95+
96+ match resp. payload {
97+ ResponsePayload :: Success ( payload) => Ok ( payload) ,
98+ ResponsePayload :: Failure ( err) => {
99+ eyre:: bail!( "flashbots error: {err}" ) ;
100+ }
96101 }
97- Ok ( v)
98102 }
99103
100104 /// Builds an EIP-191 signature for the given body bytes.
101105 async fn compute_signature ( & self , body_bz : & [ u8 ] ) -> Result < String , eyre:: Error > {
102- let payload = format ! ( "0x{:x}" , keccak256( body_bz) ) ;
106+ let payload = keccak256 ( body_bz) . to_string ( ) ;
103107 let signature = self . signer . sign_message ( payload. as_ref ( ) ) . await ?;
104108 dbg ! ( signature. to_string( ) ) ;
105109 let address = self . signer . address ( ) ;
0 commit comments