xenith_layerzero/
transport.rs1use std::collections::HashMap;
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::sync::Arc;
4
5use async_trait::async_trait;
6use bytes::Bytes;
7use xenith_core::{
8 ChainId, KeyMetadata, MessageId, MessageStatus, MessagingTransport, Result, SendOptions,
9 StateKey, StateValue, XenithError,
10};
11
12pub struct LayerZeroTransport {
29 pub endpoint_address: [u8; 20],
31 pub supported_chains: HashMap<ChainId, u32>,
33 next_message_id: Arc<AtomicU64>,
34}
35
36impl LayerZeroTransport {
37 pub fn new(endpoint_address: [u8; 20], chain_mappings: Vec<(ChainId, u32)>) -> Self {
42 Self {
43 endpoint_address,
44 supported_chains: chain_mappings.into_iter().collect(),
45 next_message_id: Arc::new(AtomicU64::new(1)),
46 }
47 }
48}
49
50#[async_trait]
51impl MessagingTransport for LayerZeroTransport {
52 async fn send_message(
53 &self,
54 destination: ChainId,
55 _payload: Bytes,
56 _options: SendOptions,
57 ) -> Result<MessageId> {
58 if !self.supported_chains.contains_key(&destination) {
59 return Err(XenithError::UnsupportedChain(destination));
60 }
61
62 let id = self.next_message_id.fetch_add(1, Ordering::Relaxed);
70 Ok(MessageId::from(id))
71 }
72
73 async fn estimate_fee(&self, _destination: ChainId, _payload: Bytes) -> Result<u128> {
74 Ok(100_000u128)
82 }
83
84 async fn message_status(&self, _id: MessageId) -> Result<MessageStatus> {
85 Ok(MessageStatus::Delivered)
93 }
94
95 fn sender_address(&self) -> Option<[u8; 20]> {
96 None
98 }
99
100 async fn poll_incoming(&self) -> Result<Vec<(StateKey, StateValue, Option<KeyMetadata>)>> {
101 Ok(vec![])
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 xenith_core::transport_compliance_tests!(LayerZeroTransport::new(
111 [0u8; 20],
112 vec![
113 (xenith_core::ChainId(1), 101u32),
114 (xenith_core::ChainId(42161), 110u32)
115 ]
116 ));
117
118 fn transport_with(chains: &[(u64, u32)]) -> LayerZeroTransport {
119 LayerZeroTransport::new(
120 [0u8; 20],
121 chains
122 .iter()
123 .map(|&(c, eid)| (ChainId::from(c), eid))
124 .collect(),
125 )
126 }
127
128 #[tokio::test]
129 async fn send_to_supported_chain_succeeds() {
130 let t = transport_with(&[(42161, 30110)]);
131 let id = t
132 .send_message(ChainId::from(42161), Bytes::new(), Default::default())
133 .await
134 .unwrap();
135 assert_eq!(id, MessageId::from(1));
136 }
137
138 #[tokio::test]
139 async fn message_ids_increment_per_send() {
140 let t = transport_with(&[(42161, 30110)]);
141 let a = t
142 .send_message(ChainId::from(42161), Bytes::new(), Default::default())
143 .await
144 .unwrap();
145 let b = t
146 .send_message(ChainId::from(42161), Bytes::new(), Default::default())
147 .await
148 .unwrap();
149 assert_eq!(a, MessageId::from(1));
150 assert_eq!(b, MessageId::from(2));
151 }
152
153 #[tokio::test]
154 async fn send_to_unsupported_chain_returns_error() {
155 let t = transport_with(&[(42161, 30110)]);
156 let err = t
157 .send_message(ChainId::from(1), Bytes::new(), Default::default())
158 .await
159 .unwrap_err();
160 assert!(matches!(err, XenithError::UnsupportedChain(ChainId(1))));
161 }
162
163 #[tokio::test]
164 async fn estimate_fee_returns_stub_value() {
165 let t = transport_with(&[]);
166 assert_eq!(
167 t.estimate_fee(ChainId::from(1), Bytes::new())
168 .await
169 .unwrap(),
170 100_000u128
171 );
172 }
173
174 #[tokio::test]
175 async fn message_status_returns_delivered() {
176 let t = transport_with(&[]);
177 assert!(matches!(
178 t.message_status(MessageId::from(99)).await.unwrap(),
179 MessageStatus::Delivered
180 ));
181 }
182}