xenith-core 0.1.0

Transport-agnostic traits, types, and errors for xenith cross-chain state sync
Documentation
use crate::{ChainId, KeyMetadata, MessageId, MessageStatus, Result, StateKey, StateValue};
use async_trait::async_trait;
use bytes::Bytes;

/// Options that fine-tune how a message is sent over the transport.
///
/// All fields are optional; unset values let the transport pick sensible defaults.
///
/// # Example
///
/// ```
/// use xenith_core::SendOptions;
/// let opts = SendOptions { gas_limit: Some(200_000), max_fee_per_gas: Some(50_000_000_000), ..Default::default() };
/// ```
#[derive(Debug, Clone, Default)]
pub struct SendOptions {
    /// Override the destination gas limit for message execution.
    pub gas_limit: Option<u64>,
    /// Override the nonce used by the sending contract.
    pub nonce: Option<u64>,
    /// Address to receive any fee refund on the source chain.
    pub refund_address: Option<[u8; 20]>,
    /// EIP-1559 maximum fee per gas in wei.
    pub max_fee_per_gas: Option<u128>,
    /// EIP-1559 maximum priority fee per gas in wei.
    pub max_priority_fee_per_gas: Option<u128>,
    /// Native token value (in wei) to attach to the transaction.
    pub value: Option<u128>,
}

/// Abstraction over a cross-chain messaging protocol.
///
/// All implementations must be `Send + Sync` so they can be shared across async
/// tasks and stored behind `Arc<dyn MessagingTransport>`.
///
/// # Example
///
/// ```rust,no_run
/// use xenith_core::{MessagingTransport, ChainId, SendOptions};
/// use bytes::Bytes;
/// use std::sync::Arc;
///
/// async fn send_to_arbitrum(transport: Arc<dyn MessagingTransport>) {
///     let id = transport
///         .send_message(ChainId::from(42161), Bytes::from("payload"), Default::default())
///         .await
///         .unwrap();
/// }
/// ```
#[async_trait]
pub trait MessagingTransport: Send + Sync {
    /// Submit a message to the destination chain and return its tracking ID.
    async fn send_message(
        &self,
        destination: ChainId,
        payload: Bytes,
        options: SendOptions,
    ) -> Result<MessageId>;

    /// Estimate the native-token fee for sending `payload` to `destination`.
    async fn estimate_fee(&self, destination: ChainId, payload: Bytes) -> Result<u128>;

    /// Poll the current delivery status of a previously sent message.
    async fn message_status(&self, id: MessageId) -> Result<MessageStatus>;

    /// Returns the address this transport will submit transactions from, if applicable.
    ///
    /// Stub transports that do not submit on-chain transactions return `None`.
    /// Live transports backed by a [`crate::TransactionSigner`] return `Some(address)`.
    fn sender_address(&self) -> Option<[u8; 20]>;

    /// Poll for messages received by this transport since the last call.
    ///
    /// Returns a vec of `(StateKey, StateValue, Option<KeyMetadata>)` decoded from
    /// incoming wire-format payloads. Implementations should track a cursor (block
    /// number or nonce) so repeated calls return new messages only, not all
    /// historical messages.
    ///
    /// Returns an empty vec if no new messages are available.
    async fn poll_incoming(&self) -> Result<Vec<(StateKey, StateValue, Option<KeyMetadata>)>>;
}