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} ;
8- use eyre:: Context as _;
913use init4_bin_base:: utils:: signer:: LocalOrAws ;
1014use reqwest:: header:: CONTENT_TYPE ;
1115use serde_json:: json;
1216
13- /// A wrapper over a `Provider` that adds Flashbots MEV bundle helpers .
17+ /// An RPC connection to relevant Flashbots endpoints .
1418#[ derive( Debug ) ]
1519pub struct Flashbots {
1620 /// The base URL for the Flashbots API.
@@ -34,48 +38,43 @@ impl Flashbots {
3438 }
3539
3640 /// 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
4343 }
4444
4545 /// 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 ?;
5148 dbg ! ( "successfully simulated bundle" , & resp) ;
5249 Ok ( ( ) )
5350 }
5451
5552 /// Fetches the bundle status by hash
5653 pub async fn bundle_status (
5754 & self ,
58- _hash : EthBundleHash ,
55+ hash : EthBundleHash ,
5956 block_number : BlockNumber ,
6057 ) -> 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+
6362 Ok ( ( ) )
6463 }
6564
6665 /// 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 > (
6867 & self ,
6968 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 ) ;
7978
8079 let value = self . compute_signature ( & body_bz) . await ?;
8180
@@ -88,18 +87,19 @@ impl Flashbots {
8887 . send ( )
8988 . await ?;
9089
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+ }
9697 }
97- Ok ( v)
9898 }
9999
100100 /// Builds an EIP-191 signature for the given body bytes.
101101 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 ( ) ;
103103 let signature = self . signer . sign_message ( payload. as_ref ( ) ) . await ?;
104104 dbg ! ( signature. to_string( ) ) ;
105105 let address = self . signer . address ( ) ;
0 commit comments