kabu_rpc_handler/handler/
flashbots.rs1use crate::dto::flashbots::{BundleRequest, BundleResponse, SendBundleResponse};
2use axum::Json;
3use axum::extract::State;
4use axum::http::StatusCode;
5use kabu_rpc_state::AppState;
6use kabu_types_blockchain::ChainParameters;
7use revm::{DatabaseCommit, DatabaseRef};
8use std::fmt::Debug;
9use tracing::info;
10
11pub async fn flashbots<DB>(
12 State(app_state): State<AppState<DB>>,
13 Json(bundle_request): Json<BundleRequest>,
14) -> Result<Json<SendBundleResponse>, (StatusCode, String)>
15where
16 DB: DatabaseRef + DatabaseCommit + Send + Sync + Clone + 'static,
17 <DB as DatabaseRef>::Error: Debug,
18{
19 for (bundle_idx, bundle_param) in bundle_request.params.iter().enumerate() {
20 info!(
21 "Flashbots bundle({bundle_idx}): target_block={:?}, transactions_len={:?}",
22 bundle_param.target_block,
23 bundle_param.transactions.len()
24 );
25 let block_history_guard = app_state.state.block_history();
27 let block_history = block_history_guard.read().await;
28 let latest_block_number = block_history.latest_block_number;
29
30 let last_block_header = if let Some(block_hash) = block_history.get_block_hash_for_block_number(latest_block_number) {
31 if let Some(entry) = block_history.get_block_history_entry(&block_hash) {
32 entry.header.clone()
33 } else {
34 return Err((StatusCode::INTERNAL_SERVER_ERROR, "No block header found".to_string()));
35 }
36 } else {
37 return Err((StatusCode::INTERNAL_SERVER_ERROR, "No block header found".to_string()));
38 };
39
40 let target_block = bundle_param.target_block.unwrap_or_default().to::<u64>();
41 if target_block <= last_block_header.number {
42 return Err((
43 StatusCode::BAD_REQUEST,
44 format!("Target block is target_block={} <= last_block={}", target_block, last_block_header.number),
45 ));
46 }
47 let _next_block_timestamp = last_block_header.timestamp + 12 * (target_block - last_block_header.number);
48 let _next_block_base_fee = ChainParameters::ethereum().calc_next_block_base_fee(
49 last_block_header.gas_used,
50 last_block_header.gas_limit,
51 last_block_header.base_fee_per_gas.unwrap_or_default(),
52 );
53 }
85
86 Ok(Json(SendBundleResponse { jsonrpc: "2.0".to_string(), id: 1, result: BundleResponse { bundle_hash: None } }))
87}