11//! A generic Flashbots bundle API wrapper.
2- use crate :: config:: { BuilderConfig , HostProvider } ;
2+ use crate :: config:: BuilderConfig ;
33use alloy:: {
44 primitives:: BlockNumber ,
5- providers:: Provider ,
65 rpc:: types:: mev:: { EthBundleHash , MevSendBundle } ,
76} ;
87use eyre:: Context as _;
8+ use eyre:: eyre;
99use init4_bin_base:: deps:: tracing:: debug;
10+ use reqwest:: Client as HttpClient ;
1011use serde_json:: json;
11- use signet_zenith:: Zenith :: ZenithInstance ;
1212
1313/// A wrapper over a `Provider` that adds Flashbots MEV bundle helpers.
1414#[ derive( Debug ) ]
1515pub struct FlashbotsProvider {
1616 /// The base URL for the Flashbots API.
1717 pub relay_url : url:: Url ,
18- /// Zenith instance for constructing Signet blocks .
19- pub zenith : ZenithInstance < HostProvider > ,
18+ /// Inner HTTP client used for JSON-RPC requests to the relay .
19+ pub inner : HttpClient ,
2020 /// Builder configuration for the task.
2121 pub config : BuilderConfig ,
2222}
2323
2424impl FlashbotsProvider {
2525 /// Wraps a provider with the URL and returns a new `FlashbotsProvider`.
26- pub fn new (
27- relay_url : url:: Url ,
28- zenith : ZenithInstance < HostProvider > ,
29- config : & BuilderConfig ,
30- ) -> Self {
31- Self { relay_url, zenith, config : config. clone ( ) }
26+ pub fn new ( config : & BuilderConfig ) -> Self {
27+ let relay_url =
28+ config. flashbots_endpoint . as_ref ( ) . expect ( "Flashbots endpoint must be set" ) . clone ( ) ;
29+ Self { relay_url, inner : HttpClient :: new ( ) , config : config. clone ( ) }
3230 }
3331
3432 /// Submit the prepared Flashbots bundle to the relay via `mev_sendBundle`.
3533 pub async fn send_bundle ( & self , bundle : MevSendBundle ) -> eyre:: Result < EthBundleHash > {
3634 // NB: The Flashbots relay expects a single parameter which is the bundle object.
3735 // Alloy's `raw_request` accepts any serializable params; wrapping in a 1-tuple is fine.
38- let hash: EthBundleHash = self
39- . zenith
40- . provider ( )
41- . raw_request ( "mev_sendBundle" . into ( ) , ( bundle, ) )
36+ // We POST a JSON-RPC request to the relay URL using our inner HTTP client.
37+ let body =
38+ json ! ( { "jsonrpc" : "2.0" , "id" : 1 , "method" : "mev_sendBundle" , "params" : [ bundle] } ) ;
39+ let resp = self
40+ . inner
41+ . post ( self . relay_url . as_str ( ) )
42+ . json ( & body)
43+ . send ( )
4244 . await
43- . wrap_err ( "mev_sendBundle RPC failed" ) ?;
45+ . wrap_err ( "mev_sendBundle HTTP request failed" ) ?;
46+
47+ let v: serde_json:: Value =
48+ resp. json ( ) . await . wrap_err ( "failed to parse mev_sendBundle response" ) ?;
49+ if let Some ( err) = v. get ( "error" ) {
50+ return Err ( eyre ! ( "mev_sendBundle error: {}" , err) ) ;
51+ }
52+ let result = v. get ( "result" ) . ok_or_else ( || eyre ! ( "mev_sendBundle missing result" ) ) ?;
53+ let hash: EthBundleHash = serde_json:: from_value ( result. clone ( ) )
54+ . wrap_err ( "failed to deserialize mev_sendBundle result" ) ?;
4455 debug ! ( ?hash, "mev_sendBundle response" ) ;
4556 Ok ( hash)
4657 }
4758
4859 /// Simulate a bundle via `mev_simBundle`.
4960 pub async fn simulate_bundle ( & self , bundle : MevSendBundle ) -> eyre:: Result < ( ) > {
50- let resp: serde_json:: Value = self
51- . zenith
52- . provider ( )
53- . raw_request ( "mev_simBundle" . into ( ) , ( bundle. clone ( ) , ) )
61+ let body =
62+ json ! ( { "jsonrpc" : "2.0" , "id" : 1 , "method" : "mev_simBundle" , "params" : [ bundle] } ) ;
63+ let resp = self
64+ . inner
65+ . post ( self . relay_url . as_str ( ) )
66+ . json ( & body)
67+ . send ( )
5468 . await
55- . wrap_err ( "mev_simBundle RPC failed" ) ?;
56- debug ! ( ?resp, "mev_simBundle response" ) ;
69+ . wrap_err ( "mev_simBundle HTTP request failed" ) ?;
70+
71+ let v: serde_json:: Value =
72+ resp. json ( ) . await . wrap_err ( "failed to parse mev_simBundle response" ) ?;
73+ if let Some ( err) = v. get ( "error" ) {
74+ return Err ( eyre ! ( "mev_simBundle error: {}" , err) ) ;
75+ }
76+ debug ! ( ?v, "mev_simBundle response" ) ;
5777 Ok ( ( ) )
5878 }
5979
@@ -64,13 +84,23 @@ impl FlashbotsProvider {
6484 block_number : BlockNumber ,
6585 ) -> eyre:: Result < ( ) > {
6686 let params = json ! ( { "bundleHash" : _hash, "blockNumber" : block_number } ) ;
67- let resp: serde_json:: Value = self
68- . zenith
69- . provider ( )
70- . raw_request ( "flashbots_getBundleStatsV2" . into ( ) , ( params, ) )
87+ let body = json ! ( { "jsonrpc" : "2.0" , "id" : 1 , "method" : "flashbots_getBundleStatsV2" , "params" : [ params] } ) ;
88+ let resp = self
89+ . inner
90+ . post ( self . relay_url . as_str ( ) )
91+ . json ( & body)
92+ . send ( )
7193 . await
72- . wrap_err ( "flashbots_getBundleStatsV2 RPC failed" ) ?;
73- debug ! ( ?resp, "flashbots_getBundleStatsV2 response" ) ;
94+ . wrap_err ( "flashbots_getBundleStatsV2 HTTP request failed" ) ?;
95+
96+ let v: serde_json:: Value =
97+ resp. json ( ) . await . wrap_err ( "failed to parse flashbots_getBundleStatsV2 response" ) ?;
98+ if let Some ( err) = v. get ( "error" ) {
99+ return Err ( eyre ! ( "flashbots_getBundleStatsV2 error: {}" , err) ) ;
100+ }
101+ debug ! ( ?v, "flashbots_getBundleStatsV2 response" ) ;
74102 Ok ( ( ) )
75103 }
76104}
105+
106+ // (no additional helpers)
0 commit comments