@@ -16,8 +16,8 @@ use init4_bin_base::{deps::metrics::counter, utils::signer::LocalOrAws};
1616use tokio:: { sync:: mpsc, task:: JoinHandle } ;
1717use tracing:: { Instrument , debug, debug_span} ;
1818
19- /// Handles construction, simulation, and submission of rollup blocks to the
20- /// Flashbots network .
19+ /// Handles preparation and submission of simulated rollup blocks to the
20+ /// Flashbots relay as MEV bundles .
2121#[ derive( Debug ) ]
2222pub struct FlashbotsTask {
2323 /// Builder configuration for the task.
@@ -31,12 +31,14 @@ pub struct FlashbotsTask {
3131 /// The key used to sign requests to the Flashbots relay.
3232 signer : LocalOrAws ,
3333 /// Channel for sending hashes of outbound transactions.
34- _outbound : mpsc:: UnboundedSender < TxHash > ,
34+ outbound : mpsc:: UnboundedSender < TxHash > ,
3535}
3636
3737impl FlashbotsTask {
38- /// Returns a new `FlashbotsTask` instance that receives `SimResult` types from the given
39- /// channel and handles their preparation, submission to the Flashbots network.
38+ /// Creates a new `FlashbotsTask` instance with initialized providers and connections.
39+ ///
40+ /// Sets up Quincey for block signing, host provider for transaction submission,
41+ /// Flashbots provider for bundle submission, and Zenith instance for contract interactions.
4042 pub async fn new (
4143 config : BuilderConfig ,
4244 outbound : mpsc:: UnboundedSender < TxHash > ,
@@ -50,28 +52,56 @@ impl FlashbotsTask {
5052
5153 let zenith = config. connect_zenith ( host_provider) ;
5254
53- Ok ( Self { config, quincey, zenith, flashbots, signer : builder_key, _outbound : outbound } )
55+ Ok ( Self { config, quincey, zenith, flashbots, signer : builder_key, outbound } )
5456 }
5557
56- /// Returns a reference to the inner `HostProvider`
57- pub fn host_provider ( & self ) -> HostProvider {
58- self . zenith . provider ( ) . clone ( )
59- }
60-
61- /// Returns a reference to the inner `FlashbotsProvider`
62- pub const fn flashbots ( & self ) -> & FlashbotsProvider {
63- & self . flashbots
64- }
65-
66- /// Prepares a MEV bundle with the configured submit call
58+ /// Prepares a MEV bundle from a simulation result.
59+ ///
60+ /// This function serves as an entry point for bundle preparation and is left
61+ /// for forward compatibility when adding different bundle preparation methods.
6762 pub async fn prepare ( & self , sim_result : & SimResult ) -> eyre:: Result < MevSendBundle > {
6863 // This function is left for forwards compatibility when we want to add
6964 // different bundle preparation methods in the future.
7065 self . prepare_bundle_helper ( sim_result) . await
7166 }
7267
73- /// Prepares a BundleHelper call containing the rollup block and corresponding fills into a MEV bundle.
68+ /// Prepares a MEV bundle containing the host transactions and the rollup block.
69+ ///
70+ /// This method orchestrates the bundle preparation by:
71+ /// 1. Preparing and signing the submission transaction
72+ /// 2. Tracking the transaction hash for monitoring
73+ /// 3. Encoding the transaction for bundle inclusion
74+ /// 4. Constructing the complete bundle body
7475 async fn prepare_bundle_helper ( & self , sim_result : & SimResult ) -> eyre:: Result < MevSendBundle > {
76+ // Prepare and sign the transaction
77+ let block_tx = self . prepare_signed_transaction ( sim_result) . await ?;
78+
79+ // Track the outbound transaction
80+ self . track_outbound_tx ( & block_tx) ;
81+
82+ // Encode the transaction
83+ let tx_bytes = block_tx. encoded_2718 ( ) . into ( ) ;
84+
85+ // Build the bundle body with the block_tx bytes as the last transaction in the bundle.
86+ let bundle_body = self . build_bundle_body ( sim_result, tx_bytes) ;
87+
88+ // Create the MEV bundle (valid only in the specific host block)
89+ Ok ( MevSendBundle :: new (
90+ sim_result. host_block_number ( ) ,
91+ Some ( sim_result. host_block_number ( ) ) ,
92+ ProtocolVersion :: V0_1 ,
93+ bundle_body,
94+ ) )
95+ }
96+
97+ /// Prepares and signs the submission transaction for the rollup block.
98+ ///
99+ /// Creates a `SubmitPrep` instance to build the transaction, then fills
100+ /// and signs it using the host provider.
101+ async fn prepare_signed_transaction (
102+ & self ,
103+ sim_result : & SimResult ,
104+ ) -> eyre:: Result < alloy:: consensus:: TxEnvelope > {
75105 let prep = SubmitPrep :: new (
76106 & sim_result. block ,
77107 self . host_provider ( ) ,
@@ -80,34 +110,48 @@ impl FlashbotsTask {
80110 ) ;
81111
82112 let tx = prep. prep_transaction ( sim_result. prev_host ( ) ) . await ?;
83-
84113 let sendable = self . host_provider ( ) . fill ( tx. into_request ( ) ) . await ?;
85114
86- let tx_bytes = sendable
87- . as_envelope ( )
88- . ok_or_eyre ( "failed to get envelope from filled tx" ) ?
89- . encoded_2718 ( )
90- . into ( ) ;
115+ sendable. as_envelope ( ) . ok_or_eyre ( "failed to get envelope from filled tx" ) . cloned ( )
116+ }
117+
118+ /// Tracks the outbound transaction hash and increments submission metrics.
119+ ///
120+ /// Sends the transaction hash to the outbound channel for monitoring.
121+ /// Logs a debug message if the channel is closed.
122+ fn track_outbound_tx ( & self , envelope : & alloy:: consensus:: TxEnvelope ) {
123+ counter ! ( "signet.builder.flashbots." ) . increment ( 1 ) ;
124+ let hash = * envelope. tx_hash ( ) ;
125+ if self . outbound . send ( hash) . is_err ( ) {
126+ debug ! ( "outbound channel closed, could not track tx hash" ) ;
127+ }
128+ }
91129
92- let bundle_body = sim_result
130+ /// Constructs the MEV bundle body from host transactions and the submission transaction.
131+ ///
132+ /// Combines all host transactions from the rollup block with the prepared rollup block
133+ /// submission transaction, wrapping each as a non-revertible bundle item.
134+ ///
135+ /// The rollup block transaction is placed last in the bundle.
136+ fn build_bundle_body (
137+ & self ,
138+ sim_result : & SimResult ,
139+ tx_bytes : alloy:: primitives:: Bytes ,
140+ ) -> Vec < BundleItem > {
141+ sim_result
93142 . block
94143 . host_transactions ( )
95144 . iter ( )
96145 . cloned ( )
97146 . chain ( std:: iter:: once ( tx_bytes) )
98147 . map ( |tx| BundleItem :: Tx { tx, can_revert : false } )
99- . collect :: < Vec < _ > > ( ) ;
100-
101- // Only valid in the specific host block
102- Ok ( MevSendBundle :: new (
103- sim_result. host_block_number ( ) ,
104- Some ( sim_result. host_block_number ( ) ) ,
105- ProtocolVersion :: V0_1 ,
106- bundle_body,
107- ) )
148+ . collect ( )
108149 }
109150
110- /// Task future that runs the Flashbots submission loop.
151+ /// Main task loop that processes simulation results and submits bundles to Flashbots.
152+ ///
153+ /// Receives `SimResult`s from the inbound channel, prepares MEV bundles, and submits
154+ /// them to the Flashbots relay. Skips empty blocks and continues processing on errors.
111155 async fn task_future ( self , mut inbound : mpsc:: UnboundedReceiver < SimResult > ) {
112156 debug ! ( "starting flashbots task" ) ;
113157
@@ -172,7 +216,19 @@ impl FlashbotsTask {
172216 }
173217 }
174218
175- /// Spawns the Flashbots task that handles incoming `SimResult`s.
219+ /// Returns a clone of the host provider for transaction operations.
220+ fn host_provider ( & self ) -> HostProvider {
221+ self . zenith . provider ( ) . clone ( )
222+ }
223+
224+ /// Returns a reference to the Flashbots provider.
225+ const fn flashbots ( & self ) -> & FlashbotsProvider {
226+ & self . flashbots
227+ }
228+
229+ /// Spawns the Flashbots task in a new Tokio task.
230+ ///
231+ /// Returns a channel sender for submitting `SimResult`s and a join handle for the task.
176232 pub fn spawn ( self ) -> ( mpsc:: UnboundedSender < SimResult > , JoinHandle < ( ) > ) {
177233 let ( sender, inbound) = mpsc:: unbounded_channel :: < SimResult > ( ) ;
178234 let handle = tokio:: spawn ( self . task_future ( inbound) ) ;
0 commit comments