signet_tx_cache/
client.rs1use crate::types::{
2 TxCacheBundle, TxCacheBundleResponse, TxCacheBundlesResponse, TxCacheOrdersResponse,
3 TxCacheSendBundleResponse, TxCacheSendTransactionResponse, TxCacheTransactionsResponse,
4};
5use alloy::consensus::TxEnvelope;
6use eyre::Error;
7use serde::{de::DeserializeOwned, Serialize};
8use signet_bundle::SignetEthBundle;
9use signet_constants::pecorino;
10use signet_types::SignedOrder;
11use tracing::{instrument, warn};
12
13const TRANSACTIONS: &str = "transactions";
15const BUNDLES: &str = "bundles";
16const ORDERS: &str = "orders";
17
18#[derive(Debug, Clone)]
21pub struct TxCache {
22 url: reqwest::Url,
24 client: reqwest::Client,
26}
27
28impl TxCache {
29 pub const fn new_with_client(url: reqwest::Url, client: reqwest::Client) -> Self {
31 Self { url, client }
32 }
33
34 pub fn new(url: reqwest::Url) -> Self {
36 Self { url, client: reqwest::Client::new() }
37 }
38
39 pub fn new_from_string(url: &str) -> Result<Self, Error> {
41 let url = reqwest::Url::parse(url)?;
42 Ok(Self::new(url))
43 }
44
45 pub fn pecorino() -> Self {
47 Self::new_from_string(pecorino::TX_CACHE_URL).expect("pecorino tx cache URL invalid")
48 }
49
50 pub fn pecorino_with_client(client: reqwest::Client) -> Self {
52 let url =
53 reqwest::Url::parse(pecorino::TX_CACHE_URL).expect("pecorino tx cache URL invalid");
54 Self::new_with_client(url, client)
55 }
56
57 async fn forward_inner<T: Serialize + Send, R: DeserializeOwned>(
58 &self,
59 join: &'static str,
60 obj: T,
61 ) -> Result<R, Error> {
62 let url = self
64 .url
65 .join(join)
66 .inspect_err(|e| warn!(%e, "Failed to join URL. Not forwarding transaction."))?;
67
68 self.client
70 .post(url)
71 .json(&obj)
72 .send()
73 .await
74 .inspect_err(|e| warn!(%e, "Failed to forward object"))?
75 .json::<R>()
76 .await
77 .map_err(Into::into)
78 .inspect_err(|e| warn!(%e, "Failed to parse response from transaction cache"))
79 }
80
81 async fn get_inner<T>(&self, join: &'static str) -> Result<T, Error>
82 where
83 T: DeserializeOwned,
84 {
85 let url = self
87 .url
88 .join(join)
89 .inspect_err(|e| warn!(%e, "Failed to join URL. Not querying transaction cache."))?;
90
91 self.client
93 .get(url)
94 .send()
95 .await
96 .inspect_err(|e| warn!(%e, "Failed to get object from transaction cache"))?
97 .json::<T>()
98 .await
99 .map_err(Into::into)
100 }
101
102 #[instrument(skip_all)]
104 pub async fn forward_raw_transaction(
105 &self,
106 tx: TxEnvelope,
107 ) -> Result<TxCacheSendTransactionResponse, Error> {
108 self.forward_inner(TRANSACTIONS, tx).await
109 }
110
111 #[instrument(skip_all)]
113 pub async fn forward_bundle(
114 &self,
115 bundle: SignetEthBundle,
116 ) -> Result<TxCacheSendBundleResponse, Error> {
117 self.forward_inner(BUNDLES, bundle).await
118 }
119
120 #[instrument(skip_all)]
122 pub async fn forward_order(&self, order: SignedOrder) -> Result<(), Error> {
123 self.forward_inner(ORDERS, order).await
124 }
125
126 #[instrument(skip_all)]
128 pub async fn get_transactions(&self) -> Result<Vec<TxEnvelope>, Error> {
129 let response: TxCacheTransactionsResponse =
130 self.get_inner::<TxCacheTransactionsResponse>(TRANSACTIONS).await?;
131 Ok(response.transactions)
132 }
133
134 #[instrument(skip_all)]
136 pub async fn get_bundles(&self) -> Result<Vec<TxCacheBundle>, Error> {
137 let response: TxCacheBundlesResponse =
138 self.get_inner::<TxCacheBundlesResponse>(BUNDLES).await?;
139 Ok(response.bundles)
140 }
141
142 #[instrument(skip_all)]
144 pub async fn get_bundle(&self) -> Result<TxCacheBundle, Error> {
145 let response: TxCacheBundleResponse =
146 self.get_inner::<TxCacheBundleResponse>(BUNDLES).await?;
147 Ok(response.bundle)
148 }
149
150 #[instrument(skip_all)]
152 pub async fn get_orders(&self) -> Result<Vec<SignedOrder>, Error> {
153 let response: TxCacheOrdersResponse =
154 self.get_inner::<TxCacheOrdersResponse>(ORDERS).await?;
155 Ok(response.orders)
156 }
157}