kabu_rpc_handler/handler/
flashbots.rs

1use 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        // Get latest block from block history
26        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        //TODO : rewrite
54        /*
55        let evm_env = Env {
56            block: BlockEnv {
57                number: U256::from(target_block),
58                timestamp: U256::from(next_block_timestamp),
59                basefee: U256::from(next_block_base_fee),
60                blob_excess_gas_and_price: Some(BlobExcessGasAndPrice { excess_blob_gas: 0, blob_gasprice: 0 }),
61                ..BlockEnv::default()
62            },
63            ..Env::default()
64        };
65        let db = app_state.state.market_state().read().await.state_db.clone();
66        let mut evm = Evm::builder().with_spec_id(CANCUN).with_ref_db(db).with_env(Box::new(evm_env)).build();
67        for (tx_idx, tx) in bundle_param.transactions.iter().enumerate() {
68            let tx_hash = keccak256(tx);
69
70            let tx_env = env_from_signed_tx(tx.clone()).map_err(|e| (StatusCode::BAD_REQUEST, format!("Error: {}", e)))?;
71            info!("Flashbots bundle({bundle_idx}) -> tx({tx_idx}): caller={:?}, transact_to={:?}, data={:?}, value={:?}, gas_price={:?}, gas_limit={:?}, nonce={:?}, chain_id={:?}, access_list_len={}",
72               tx_env.caller, tx_env.transact_to, tx_env.data, tx_env.value, tx_env.gas_price, tx_env.gas_limit, tx_env.nonce, tx_env.chain_id, tx_env.access_list.len());
73
74            evm.context.evm.env.tx = tx_env;
75
76            let (result, gas_used) = evm_transact(&mut evm).map_err(|e| {
77                error!("Flashbot tx error latest_block={}, tx_hash={}, err={}/{:?}", last_block_header.number, tx_hash, e, e);
78                (StatusCode::BAD_REQUEST, format!("Error: {}", e))
79            })?;
80            info!("result={}, gas_used={}", hex::encode_prefixed(result), gas_used);
81        }
82
83         */
84    }
85
86    Ok(Json(SendBundleResponse { jsonrpc: "2.0".to_string(), id: 1, result: BundleResponse { bundle_hash: None } }))
87}