diff --git a/Cargo.lock b/Cargo.lock index 0f9f693..f67e045 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1492,6 +1492,7 @@ dependencies = [ name = "mev-share-rpc-api" version = "0.1.0" dependencies = [ + "async-trait", "ethers-core", "ethers-signers", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index 1736c9d..7093bb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ hyper = "0.14" ## async futures-util = "0.3" +async-trait = "0.1" ## misc serde_json = "1.0" diff --git a/crates/mev-share-rpc-api/Cargo.toml b/crates/mev-share-rpc-api/Cargo.toml index cf4b9ae..6de7124 100644 --- a/crates/mev-share-rpc-api/Cargo.toml +++ b/crates/mev-share-rpc-api/Cargo.toml @@ -23,6 +23,7 @@ http.workspace = true hyper = { workspace = true, features = ["stream"] } tower.workspace = true futures-util.workspace = true +async-trait.workspace = true [dev-dependencies] diff --git a/crates/mev-share-rpc-api/src/mev.rs b/crates/mev-share-rpc-api/src/mev.rs index 598d3df..f9467ab 100644 --- a/crates/mev-share-rpc-api/src/mev.rs +++ b/crates/mev-share-rpc-api/src/mev.rs @@ -1,6 +1,5 @@ -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; - use crate::{SendBundleRequest, SendBundleResponse, SimBundleOverrides, SimBundleResponse}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; /// Mev rpc interface. #[cfg_attr(not(feature = "client"), rpc(server, namespace = "mev"))] @@ -22,3 +21,81 @@ pub trait MevApi { sim_overrides: SimBundleOverrides, ) -> RpcResult; } + +/// An object safe version of the `MevApiClient` trait. +#[async_trait::async_trait] +pub(crate) trait MevApiExt { + /// Submitting bundles to the relay. It takes in a bundle and provides a bundle hash as a return + /// value. + async fn send_bundle( + &self, + request: SendBundleRequest, + ) -> Result; + + /// Similar to `mev_sendBundle` but instead of submitting a bundle to the relay, it returns a + /// simulation result. Only fully matched bundles can be simulated. + async fn sim_bundle( + &self, + bundle: SendBundleRequest, + sim_overrides: SimBundleOverrides, + ) -> Result; +} + +#[async_trait::async_trait] +impl MevApiExt for T +where + T: MevApiClient + Sync, +{ + async fn send_bundle( + &self, + request: SendBundleRequest, + ) -> Result { + MevApiClient::send_bundle(self, request).await + } + + async fn sim_bundle( + &self, + bundle: SendBundleRequest, + sim_overrides: SimBundleOverrides, + ) -> Result { + MevApiClient::sim_bundle(self, bundle, sim_overrides).await + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::FlashbotsSignerLayer; + use ethers_core::rand::thread_rng; + use ethers_signers::LocalWallet; + use jsonrpsee::http_client::{transport, HttpClientBuilder}; + + struct Client { + inner: Box, + } + + #[allow(dead_code)] + async fn assert_mev_api_box() { + let fb_signer = LocalWallet::new(&mut thread_rng()); + let http = HttpClientBuilder::default() + .set_middleware( + tower::ServiceBuilder::new() + .map_err(transport::Error::Http) + .layer(FlashbotsSignerLayer::new(fb_signer.clone())), + ) + .build("http://localhost:3030") + .unwrap(); + let client = Client { inner: Box::new(http) }; + client + .inner + .send_bundle(SendBundleRequest { + protocol_version: Default::default(), + inclusion: Default::default(), + bundle_body: vec![], + validity: None, + privacy: None, + }) + .await + .unwrap(); + } +} diff --git a/crates/mev-share-rpc-api/src/types.rs b/crates/mev-share-rpc-api/src/types.rs index 22d716e..a32cc5b 100644 --- a/crates/mev-share-rpc-api/src/types.rs +++ b/crates/mev-share-rpc-api/src/types.rs @@ -511,6 +511,6 @@ mod tests { } "#; let actual: SimBundleResponse = serde_json::from_str(expected).unwrap(); - assert_eq!(actual.success, true); + assert!(actual.success); } }