xenith_core/transport.rs
1use crate::{ChainId, KeyMetadata, MessageId, MessageStatus, Result, StateKey, StateValue};
2use async_trait::async_trait;
3use bytes::Bytes;
4
5/// Options that fine-tune how a message is sent over the transport.
6///
7/// All fields are optional; unset values let the transport pick sensible defaults.
8///
9/// # Example
10///
11/// ```
12/// use xenith_core::SendOptions;
13/// let opts = SendOptions { gas_limit: Some(200_000), max_fee_per_gas: Some(50_000_000_000), ..Default::default() };
14/// ```
15#[derive(Debug, Clone, Default)]
16pub struct SendOptions {
17 /// Override the destination gas limit for message execution.
18 pub gas_limit: Option<u64>,
19 /// Override the nonce used by the sending contract.
20 pub nonce: Option<u64>,
21 /// Address to receive any fee refund on the source chain.
22 pub refund_address: Option<[u8; 20]>,
23 /// EIP-1559 maximum fee per gas in wei.
24 pub max_fee_per_gas: Option<u128>,
25 /// EIP-1559 maximum priority fee per gas in wei.
26 pub max_priority_fee_per_gas: Option<u128>,
27 /// Native token value (in wei) to attach to the transaction.
28 pub value: Option<u128>,
29}
30
31/// Abstraction over a cross-chain messaging protocol.
32///
33/// All implementations must be `Send + Sync` so they can be shared across async
34/// tasks and stored behind `Arc<dyn MessagingTransport>`.
35///
36/// # Example
37///
38/// ```rust,no_run
39/// use xenith_core::{MessagingTransport, ChainId, SendOptions};
40/// use bytes::Bytes;
41/// use std::sync::Arc;
42///
43/// async fn send_to_arbitrum(transport: Arc<dyn MessagingTransport>) {
44/// let id = transport
45/// .send_message(ChainId::from(42161), Bytes::from("payload"), Default::default())
46/// .await
47/// .unwrap();
48/// }
49/// ```
50#[async_trait]
51pub trait MessagingTransport: Send + Sync {
52 /// Submit a message to the destination chain and return its tracking ID.
53 async fn send_message(
54 &self,
55 destination: ChainId,
56 payload: Bytes,
57 options: SendOptions,
58 ) -> Result<MessageId>;
59
60 /// Estimate the native-token fee for sending `payload` to `destination`.
61 async fn estimate_fee(&self, destination: ChainId, payload: Bytes) -> Result<u128>;
62
63 /// Poll the current delivery status of a previously sent message.
64 async fn message_status(&self, id: MessageId) -> Result<MessageStatus>;
65
66 /// Returns the address this transport will submit transactions from, if applicable.
67 ///
68 /// Stub transports that do not submit on-chain transactions return `None`.
69 /// Live transports backed by a [`crate::TransactionSigner`] return `Some(address)`.
70 fn sender_address(&self) -> Option<[u8; 20]>;
71
72 /// Poll for messages received by this transport since the last call.
73 ///
74 /// Returns a vec of `(StateKey, StateValue, Option<KeyMetadata>)` decoded from
75 /// incoming wire-format payloads. Implementations should track a cursor (block
76 /// number or nonce) so repeated calls return new messages only, not all
77 /// historical messages.
78 ///
79 /// Returns an empty vec if no new messages are available.
80 async fn poll_incoming(&self) -> Result<Vec<(StateKey, StateValue, Option<KeyMetadata>)>>;
81}