Skip to content

Commit a9dae61

Browse files
committed
refactors and cleanup
- refactors the smoke tests - cleans up the flashbots provider struct - tighten up pubs and exports
1 parent 6fc18f7 commit a9dae61

File tree

3 files changed

+81
-58
lines changed

3 files changed

+81
-58
lines changed
Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,79 @@
11
//! A generic Flashbots bundle API wrapper.
2-
use crate::config::{BuilderConfig, HostProvider};
2+
use crate::config::BuilderConfig;
33
use alloy::{
44
primitives::BlockNumber,
5-
providers::Provider,
65
rpc::types::mev::{EthBundleHash, MevSendBundle},
76
};
87
use eyre::Context as _;
8+
use eyre::eyre;
99
use init4_bin_base::deps::tracing::debug;
10+
use reqwest::Client as HttpClient;
1011
use 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)]
1515
pub 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

2424
impl 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)

src/test_utils.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ pub fn setup_test_config() -> Result<BuilderConfig> {
2222
let config = BuilderConfig {
2323
host_chain_id: signet_constants::pecorino::HOST_CHAIN_ID,
2424
ru_chain_id: signet_constants::pecorino::RU_CHAIN_ID,
25-
host_rpc: "https://host-rpc.pecorino.signet.sh"
25+
host_rpc: "ws://host-rpc.pecorino.signet.sh"
2626
.parse::<BuiltInConnectionString>()
2727
.map(ProviderConfig::new)
2828
.unwrap(),
29-
ru_rpc: "https://rpc.pecorino.signet.sh"
29+
ru_rpc: "ws://rpc.pecorino.signet.sh"
3030
.parse::<BuiltInConnectionString>()
3131
.unwrap()
3232
.try_into()
3333
.unwrap(),
3434
tx_broadcast_urls: vec!["http://localhost:9000".into()],
35-
flashbots_endpoint: "http://localhost:9062".parse().unwrap(), // NB: Flashbots API default
35+
flashbots_endpoint: Some("http://localhost:9062".parse().unwrap()), // NB: Flashbots API default
3636
zenith_address: Address::default(),
3737
quincey_url: "http://localhost:8080".into(),
3838
builder_port: 8080,

tests/flashbots_provider_test.rs

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,30 @@ mod tests {
77
#[cfg(test)]
88
mod tests {
99
use super::*;
10-
use alloy::{providers::Provider, rpc::types::mev::MevSendBundle};
11-
use builder::{config::BuilderConfig, test_utils::setup_logging};
12-
use init4_bin_base::utils::from_env::FromEnv;
10+
use alloy::{
11+
primitives::FixedBytes,
12+
rpc::types::mev::{EthBundleHash, MevSendBundle},
13+
};
14+
use builder::{
15+
config::BuilderConfig,
16+
test_utils::{setup_logging, setup_test_config},
17+
};
18+
use init4_bin_base::{
19+
deps::tracing::{error, info},
20+
utils::from_env::FromEnv,
21+
};
1322

1423
#[tokio::test]
1524
#[ignore = "integration test"]
1625
async fn smoke_root_provider() {
1726
setup_logging();
18-
let config = BuilderConfig::from_env().unwrap();
19-
20-
let host_provider = config.connect_host_provider().await.unwrap();
21-
let zenith = config.connect_zenith(host_provider.clone());
22-
let flashbots =
23-
FlashbotsProvider::new(config.clone().flashbots_endpoint, zenith.clone(), &config);
24-
FlashbotsProvider::new(config.clone().flashbots_endpoint, zenith.clone(), &config);
25-
27+
let flashbots = get_test_provider().await;
2628
assert_eq!(flashbots.relay_url.as_str(), "http://localhost:9062/");
2729

28-
let provider = flashbots.zenith.provider();
29-
let block_number = provider.get_block_number().await.unwrap();
30-
assert!(block_number > 0);
30+
let status = flashbots
31+
.bundle_status(EthBundleHash { bundle_hash: FixedBytes::default() }, 0)
32+
.await;
33+
assert!(status.is_err());
3134
}
3235

3336
#[tokio::test]
@@ -37,16 +40,12 @@ mod tests {
3740

3841
let res = flashbots.simulate_bundle(MevSendBundle::default()).await;
3942

40-
if let Err(err) = &res {
41-
eprintln!("simulate error (expected for empty bundle): {err}");
42-
}
43-
4443
if let Err(err) = &res {
4544
let msg = format!("{err}");
4645
assert!(msg.contains("mev_simBundle"));
4746
}
4847

49-
assert!(res.is_ok() || res.is_err());
48+
assert!(res.is_err());
5049
}
5150

5251
#[tokio::test]
@@ -64,14 +63,8 @@ mod tests {
6463
}
6564

6665
async fn get_test_provider() -> FlashbotsProvider {
67-
let config = BuilderConfig::from_env().unwrap();
68-
69-
let host_provider = config.connect_host_provider().await.unwrap();
70-
let zenith = config.connect_zenith(host_provider.clone());
71-
72-
let flashbots =
73-
FlashbotsProvider::new(config.flashbots_endpoint.clone(), zenith, &config.clone());
74-
flashbots
66+
let config = setup_test_config().unwrap();
67+
FlashbotsProvider::new(&config.clone())
7568
}
7669
}
7770
}

0 commit comments

Comments
 (0)