aztec_ethereum/
cross_chain.rs

1//! Cross-chain utilities for L1↔L2 message readiness checking.
2//!
3//! Mirrors upstream `aztec.js/src/utils/cross_chain.ts`.
4
5use aztec_core::types::Fr;
6use aztec_node_client::node::AztecNode;
7use std::time::{Duration, Instant};
8
9/// Check whether an L1-to-L2 message is ready for consumption on L2.
10///
11/// A message is ready when its checkpoint number is ≤ the latest block's
12/// checkpoint number.
13///
14/// Mirrors TS `isL1ToL2MessageReady(node, l1ToL2MessageHash)`.
15pub async fn is_l1_to_l2_message_ready<N: AztecNode>(
16    node: &N,
17    l1_to_l2_message_hash: &Fr,
18) -> Result<bool, aztec_core::Error> {
19    let checkpoint = node
20        .get_l1_to_l2_message_checkpoint(l1_to_l2_message_hash)
21        .await?;
22    let Some(msg_checkpoint) = checkpoint else {
23        return Ok(false);
24    };
25
26    let block_number = node.get_block_number().await?;
27    if block_number == 0 {
28        return Ok(false);
29    }
30    let block = node.get_block(block_number).await?;
31    let Some(block_json) = block else {
32        return Ok(false);
33    };
34
35    // Extract checkpoint number from block header
36    let block_checkpoint = block_json
37        .pointer("/header/globalVariables/blockNumber")
38        .and_then(|v| v.as_u64())
39        .unwrap_or(0);
40
41    Ok(msg_checkpoint <= block_checkpoint)
42}
43
44/// Wait until an L1-to-L2 message is ready for consumption, with a timeout.
45///
46/// Polls every second until the message is ready or the timeout expires.
47///
48/// Mirrors TS `waitForL1ToL2MessageReady(node, hash, opts)`.
49pub async fn wait_for_l1_to_l2_message_ready<N: AztecNode>(
50    node: &N,
51    l1_to_l2_message_hash: &Fr,
52    timeout: Duration,
53) -> Result<(), aztec_core::Error> {
54    let start = Instant::now();
55    loop {
56        if is_l1_to_l2_message_ready(node, l1_to_l2_message_hash).await? {
57            return Ok(());
58        }
59        if start.elapsed() >= timeout {
60            return Err(aztec_core::Error::Timeout(format!(
61                "L1-to-L2 message {} not ready within {:?}",
62                l1_to_l2_message_hash, timeout
63            )));
64        }
65        tokio::time::sleep(Duration::from_secs(1)).await;
66    }
67}