Skip to content

Commit e4a1adb

Browse files
authored
Introduce a way for callers to get CCIP requests (#7)
1 parent 62688ad commit e4a1adb

File tree

3 files changed

+42
-11
lines changed

3 files changed

+42
-11
lines changed

src/ccip.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use serde::Deserialize;
1111
use crate::errors::{CCIPFetchError, CCIPRequestError};
1212
use crate::utils::truncate_str;
1313
use crate::CCIPReadMiddlewareError;
14+
use crate::CCIPRequest;
1415

1516
#[derive(Debug, Clone, Deserialize)]
1617
pub struct CCIPResponse {
@@ -98,22 +99,29 @@ pub async fn handle_ccip<M: Middleware>(
9899
tx: &TypedTransaction,
99100
calldata: &[u8],
100101
urls: Vec<String>,
101-
) -> Result<Bytes, CCIPReadMiddlewareError<M>> {
102+
) -> Result<(Bytes, Vec<CCIPRequest>), CCIPReadMiddlewareError<M>> {
102103
// If there are no URLs or the transaction's destination is empty, return an empty result
103104
if urls.is_empty() || tx.to().is_none() {
104-
return Ok(Bytes::new());
105+
return Ok((Bytes::new(), Vec::new()));
105106
}
106107

107108
let urls = dedup_ord(&urls);
108109

109110
// url —> [error_message]
110111
let mut errors: HashMap<String, Vec<String>> = HashMap::new();
111112

113+
let mut requests = Vec::new();
114+
112115
for url in urls {
113116
let result = handle_ccip_raw(client, &url, sender, calldata).await;
117+
requests.push(CCIPRequest {
118+
url: url.clone(),
119+
sender: *sender,
120+
calldata: calldata.to_vec().into(),
121+
});
114122

115123
match result {
116-
Ok(result) => return Ok(result),
124+
Ok(result) => return Ok((result, requests)),
117125
Err(err) => {
118126
errors.entry(url).or_default().push(err.to_string());
119127
}

src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,17 @@
22
//!
33
//! Provides an [ethers](https://docs.rs/ethers) compatible middleware for submitting
44
pub use errors::CCIPReadMiddlewareError;
5+
use ethers_core::types::{Address, Bytes};
56
pub use middleware::CCIPReadMiddleware;
67

78
mod ccip;
89
mod errors;
910
mod middleware;
1011
pub mod utils;
12+
13+
#[derive(Debug, Clone)]
14+
pub struct CCIPRequest {
15+
pub url: String,
16+
pub sender: Address,
17+
pub calldata: Bytes,
18+
}

src/middleware.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use serde_json::Value;
1919

2020
use crate::ccip::handle_ccip;
2121
use crate::utils::{build_reqwest, decode_bytes, dns_encode};
22-
use crate::CCIPReadMiddlewareError;
22+
use crate::{CCIPReadMiddlewareError, CCIPRequest};
2323

2424
#[derive(Debug, Clone)]
2525
pub struct CCIPReadMiddleware<M> {
@@ -229,7 +229,8 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
229229
transaction: &TypedTransaction,
230230
block_id: Option<BlockId>,
231231
attempt: u8,
232-
) -> Result<Bytes, CCIPReadMiddlewareError<M>> {
232+
requests_buffer: &mut Vec<CCIPRequest>,
233+
) -> Result<(Bytes, Vec<CCIPRequest>), CCIPReadMiddlewareError<M>> {
233234
if attempt >= self.max_redirect_attempt {
234235
// may need more info
235236
return Err(CCIPReadMiddlewareError::MaxRedirectionError);
@@ -258,14 +259,14 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
258259

259260
if !matches!(block_id.unwrap_or(BlockId::Number(BlockNumber::Latest)), BlockId::Number(block) if block.is_latest())
260261
{
261-
return Ok(result);
262+
return Ok((result, requests_buffer.to_vec()));
262263
}
263264

264265
if tx_sender.is_zero()
265266
|| !result.starts_with(OFFCHAIN_LOOKUP_SELECTOR)
266267
|| result.len() % 32 != 4
267268
{
268-
return Ok(result);
269+
return Ok((result, requests_buffer.to_vec()));
269270
}
270271

271272
let output_types = vec![
@@ -292,7 +293,7 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
292293
decoded_data.get(4),
293294
)
294295
else {
295-
return Ok(result);
296+
return Ok((result, requests_buffer.to_vec()));
296297
};
297298

298299
let urls: Vec<String> = urls
@@ -310,9 +311,11 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
310311
});
311312
}
312313

313-
let ccip_result =
314+
let (ccip_result, requests) =
314315
handle_ccip(&self.reqwest_client, sender, transaction, calldata, urls).await?;
315316

317+
requests_buffer.extend(requests);
318+
316319
if ccip_result.is_empty() {
317320
return Err(CCIPReadMiddlewareError::GatewayNotFoundError);
318321
}
@@ -327,7 +330,19 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
327330
[callback_selector.clone(), encoded_data.clone()].concat(),
328331
));
329332

330-
self._call(&callback_tx, block_id, attempt + 1).await
333+
self._call(&callback_tx, block_id, attempt + 1, requests_buffer)
334+
.await
335+
}
336+
337+
/// Call the underlying middleware with the provided transaction and block,
338+
/// returning both the result of the call and the CCIP requests made during the call
339+
pub async fn call_ccip(
340+
&self,
341+
tx: &TypedTransaction,
342+
block: Option<BlockId>,
343+
) -> Result<(Bytes, Vec<CCIPRequest>), CCIPReadMiddlewareError<M>> {
344+
let mut requests = Vec::new();
345+
self._call(tx, block, 0, &mut requests).await
331346
}
332347
}
333348

@@ -353,7 +368,7 @@ where
353368
tx: &TypedTransaction,
354369
block: Option<BlockId>,
355370
) -> Result<Bytes, Self::Error> {
356-
return self._call(tx, block, 0).await;
371+
Ok(self.call_ccip(tx, block).await?.0)
357372
}
358373

359374
/**

0 commit comments

Comments
 (0)