apex_sdk_types/lib.rs
1//! # Apex SDK Types
2//!
3//! Common types and data structures used across the Apex SDK.
4//!
5//! This crate provides fundamental types for representing blockchain entities
6//! across different chain types (Substrate, EVM, Hybrid).
7//!
8//! ## Core Types
9//!
10//! - **Chain**: Enumeration of supported blockchain networks
11//! - **ChainType**: Classification of chains (Substrate, EVM, Hybrid)
12//! - **Address**: Generic address type supporting multiple formats
13//! - **TransactionStatus**: Unified transaction status representation
14//! - **CrossChainTransaction**: Cross-chain transaction information
15//!
16//! ## Example
17//!
18//! ```rust
19//! use apex_sdk_types::{Chain, ChainType, Address};
20//!
21//! // Create addresses for different chains
22//! let eth_addr = Address::evm("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb7");
23//! let dot_addr = Address::substrate("15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5");
24//!
25//! // Check chain types
26//! assert_eq!(Chain::Ethereum.chain_type(), ChainType::Evm);
27//! assert_eq!(Chain::Polkadot.chain_type(), ChainType::Substrate);
28//! assert_eq!(Chain::Moonbeam.chain_type(), ChainType::Hybrid);
29//! ```
30
31use serde::{Deserialize, Serialize};
32
33/// Blockchain types
34#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
35pub enum ChainType {
36 /// Substrate-based chain
37 Substrate,
38 /// EVM-based chain
39 Evm,
40 /// Hybrid chain (both Substrate and EVM)
41 Hybrid,
42}
43
44/// Supported blockchain networks
45#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
46pub enum Chain {
47 // Substrate Relay Chains
48 /// Polkadot relay chain
49 Polkadot,
50 /// Kusama relay chain
51 Kusama,
52
53 // Substrate Parachains
54 /// Moonbeam (Polkadot parachain with EVM)
55 Moonbeam,
56 /// Astar (Polkadot parachain with EVM)
57 Astar,
58 /// Acala DeFi Hub
59 Acala,
60 /// Phala Privacy Cloud
61 Phala,
62 /// Bifrost Liquid Staking
63 Bifrost,
64 /// Westend testnet
65 Westend,
66
67 // EVM Layer 1
68 /// Ethereum mainnet
69 Ethereum,
70 /// Binance Smart Chain
71 BinanceSmartChain,
72 /// Polygon
73 Polygon,
74 /// Avalanche C-Chain
75 Avalanche,
76
77 // EVM Layer 2
78 /// Arbitrum One
79 Arbitrum,
80 /// Optimism
81 Optimism,
82 /// zkSync Era
83 ZkSync,
84 /// Base (Coinbase L2)
85 Base,
86}
87
88impl Chain {
89 /// Get the chain type
90 pub fn chain_type(&self) -> ChainType {
91 match self {
92 // Pure Substrate chains
93 Chain::Polkadot
94 | Chain::Kusama
95 | Chain::Acala
96 | Chain::Phala
97 | Chain::Bifrost
98 | Chain::Westend => ChainType::Substrate,
99
100 // Pure EVM chains
101 Chain::Ethereum
102 | Chain::BinanceSmartChain
103 | Chain::Polygon
104 | Chain::Avalanche
105 | Chain::Arbitrum
106 | Chain::Optimism
107 | Chain::ZkSync
108 | Chain::Base => ChainType::Evm,
109
110 // Hybrid chains (Substrate + EVM)
111 Chain::Moonbeam | Chain::Astar => ChainType::Hybrid,
112 }
113 }
114
115 /// Get the chain name
116 pub fn name(&self) -> &str {
117 match self {
118 // Substrate
119 Chain::Polkadot => "Polkadot",
120 Chain::Kusama => "Kusama",
121 Chain::Acala => "Acala",
122 Chain::Phala => "Phala",
123 Chain::Bifrost => "Bifrost",
124 Chain::Westend => "Westend",
125
126 // EVM L1
127 Chain::Ethereum => "Ethereum",
128 Chain::BinanceSmartChain => "Binance Smart Chain",
129 Chain::Polygon => "Polygon",
130 Chain::Avalanche => "Avalanche",
131
132 // EVM L2
133 Chain::Arbitrum => "Arbitrum",
134 Chain::Optimism => "Optimism",
135 Chain::ZkSync => "zkSync",
136 Chain::Base => "Base",
137
138 // Hybrid
139 Chain::Moonbeam => "Moonbeam",
140 Chain::Astar => "Astar",
141 }
142 }
143
144 /// Get default RPC endpoint for the chain
145 pub fn default_endpoint(&self) -> &str {
146 match self {
147 // Substrate
148 Chain::Polkadot => "wss://polkadot.api.onfinality.io/public-ws",
149 Chain::Kusama => "wss://kusama.api.onfinality.io/public-ws",
150 Chain::Acala => "wss://acala.api.onfinality.io/public-ws",
151 Chain::Phala => "wss://phala.api.onfinality.io/public-ws",
152 Chain::Bifrost => "wss://bifrost-polkadot.api.onfinality.io/public-ws",
153 Chain::Westend => "wss://westend-rpc.polkadot.io",
154
155 // EVM L1
156 Chain::Ethereum => "https://eth.llamarpc.com",
157 Chain::BinanceSmartChain => "https://bsc.publicnode.com",
158 Chain::Polygon => "https://polygon-rpc.com",
159 Chain::Avalanche => "https://api.avax.network/ext/bc/C/rpc",
160
161 // EVM L2
162 Chain::Arbitrum => "https://arb1.arbitrum.io/rpc",
163 Chain::Optimism => "https://mainnet.optimism.io",
164 Chain::ZkSync => "https://mainnet.era.zksync.io",
165 Chain::Base => "https://mainnet.base.org",
166
167 // Hybrid
168 Chain::Moonbeam => "wss://moonbeam.api.onfinality.io/public-ws",
169 Chain::Astar => "wss://astar.api.onfinality.io/public-ws",
170 }
171 }
172
173 /// Get multiple RPC endpoints for reliability and failover
174 pub fn rpc_endpoints(&self) -> Vec<&str> {
175 match self {
176 // Substrate
177 Chain::Polkadot => vec![
178 "wss://polkadot.api.onfinality.io/public-ws",
179 "wss://rpc.ibp.network/polkadot",
180 "wss://polkadot.dotters.network",
181 ],
182 Chain::Kusama => vec![
183 "wss://kusama.api.onfinality.io/public-ws",
184 "wss://rpc.ibp.network/kusama",
185 "wss://kusama.dotters.network",
186 ],
187 Chain::Westend => vec![
188 "wss://westend-rpc.polkadot.io",
189 "wss://rpc.ibp.network/westend",
190 "wss://westend.dotters.network",
191 ],
192 // For other chains, return the single default endpoint
193 _ => vec![self.default_endpoint()],
194 }
195 }
196
197 /// Check if chain is a Layer 2 solution
198 pub fn is_layer2(&self) -> bool {
199 matches!(
200 self,
201 Chain::Arbitrum | Chain::Optimism | Chain::ZkSync | Chain::Base
202 )
203 }
204
205 /// Check if chain supports smart contracts
206 pub fn supports_smart_contracts(&self) -> bool {
207 match self.chain_type() {
208 ChainType::Evm => true,
209 ChainType::Hybrid => true,
210 ChainType::Substrate => matches!(
211 self,
212 Chain::Acala | Chain::Phala | Chain::Moonbeam | Chain::Astar
213 ),
214 }
215 }
216}
217
218/// Generic address type for different chains
219#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
220pub enum Address {
221 /// Substrate SS58 address
222 Substrate(String),
223 /// EVM hex address (0x...)
224 Evm(String),
225}
226
227impl Address {
228 /// Create a Substrate address
229 pub fn substrate(addr: impl Into<String>) -> Self {
230 Address::Substrate(addr.into())
231 }
232
233 /// Create an EVM address
234 pub fn evm(addr: impl Into<String>) -> Self {
235 Address::Evm(addr.into())
236 }
237
238 /// Get the address as a string
239 pub fn as_str(&self) -> &str {
240 match self {
241 Address::Substrate(s) | Address::Evm(s) => s,
242 }
243 }
244}
245
246/// Transaction status
247#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
248pub enum TransactionStatus {
249 /// Transaction is pending.
250 ///
251 /// The transaction has been created but has not yet been broadcasted to the network.
252 /// This status typically indicates that the transaction is awaiting submission or signing.
253 Pending,
254 /// Transaction is in memory pool (mempool).
255 ///
256 /// The transaction has been broadcasted to the network and is waiting to be included in a block.
257 /// This status indicates that the transaction is known to the network but not yet confirmed.
258 InMempool,
259 /// Transaction is confirmed
260 Confirmed {
261 /// Block hash
262 block_hash: String,
263 /// Block number where transaction was included
264 block_number: Option<u64>,
265 },
266 /// Transaction is finalized (for Substrate chains)
267 Finalized {
268 /// Block hash
269 block_hash: String,
270 /// Block number
271 block_number: u64,
272 },
273 /// Transaction failed
274 Failed {
275 /// Error message
276 error: String,
277 },
278 /// Transaction status unknown
279 Unknown,
280}
281
282/// Represents a blockchain event emitted by a smart contract or runtime.
283///
284/// The `Event` struct captures details about an event, including its name, associated data,
285/// the block and transaction in which it occurred, and its index within the block.
286///
287/// # Fields
288/// - `name`: The name of the event (e.g., `"Transfer"`, `"Approval"`).
289/// - `data`: The event payload as a JSON value. This typically contains event parameters.
290/// - `block_number`: The block number in which the event was emitted, if available.
291/// - `tx_hash`: The transaction hash associated with the event, if available.
292/// - `index`: The index of the event within the block, if available.
293///
294/// # Example
295/// ```
296/// use apex_sdk_types::Event;
297/// use serde_json::json;
298///
299/// let event = Event {
300/// name: "Transfer".to_string(),
301/// data: json!({
302/// "from": "0x123...",
303/// "to": "0x456...",
304/// "value": 1000
305/// }),
306/// block_number: Some(123456),
307/// tx_hash: Some("0xabc...".to_string()),
308/// index: Some(0),
309/// };
310/// assert_eq!(event.name, "Transfer");
311/// ```
312#[derive(Debug, Clone, Serialize, Deserialize)]
313pub struct Event {
314 /// The name of the event (e.g., "Transfer", "Approval").
315 pub name: String,
316 /// The event payload as a JSON value, typically containing event parameters.
317 pub data: serde_json::Value,
318 /// The block number in which the event was emitted, if available.
319 pub block_number: Option<u64>,
320 /// The transaction hash associated with the event, if available.
321 pub tx_hash: Option<String>,
322 /// The index of the event within the block, if available.
323 pub index: Option<u32>,
324}
325
326/// Filter criteria for subscribing to blockchain events.
327///
328/// This struct allows you to specify which events to receive by name, contract address,
329/// and block range. All fields are optional; if a field is `None`, it will not be used
330/// as a filter criterion.
331#[derive(Debug, Clone, Serialize, Deserialize)]
332pub struct EventFilter {
333 /// List of event names to filter for.
334 ///
335 /// If specified, only events with names matching one of the strings in this list
336 /// will be included. If `None`, all event names are included.
337 pub event_names: Option<Vec<String>>,
338 /// List of contract addresses to filter for.
339 ///
340 /// If specified, only events emitted by contracts with addresses in this list
341 /// will be included. If `None`, events from all addresses are included.
342 pub addresses: Option<Vec<Address>>,
343 /// The starting block number (inclusive) for filtering events.
344 ///
345 /// If specified, only events from blocks with number greater than or equal to this
346 /// value will be included. If `None`, events from all blocks are included.
347 pub from_block: Option<u64>,
348 /// The ending block number (inclusive) for filtering events.
349 ///
350 /// If specified, only events from blocks with number less than or equal to this
351 /// value will be included. If `None`, events up to the latest block are included.
352 pub to_block: Option<u64>,
353}
354
355/// Cross-chain transaction info
356#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct CrossChainTransaction {
358 /// Transaction ID
359 pub id: String,
360 /// Source chain
361 pub source_chain: Chain,
362 /// Destination chain
363 pub destination_chain: Chain,
364 /// Source transaction hash
365 pub source_tx_hash: Option<String>,
366 /// Destination transaction hash
367 pub destination_tx_hash: Option<String>,
368 /// Transaction status
369 pub status: TransactionStatus,
370 /// Timestamp
371 pub timestamp: u64,
372}
373
374#[cfg(test)]
375mod tests {
376 use super::*;
377
378 #[test]
379 fn test_chain_type() {
380 assert_eq!(Chain::Polkadot.chain_type(), ChainType::Substrate);
381 assert_eq!(Chain::Ethereum.chain_type(), ChainType::Evm);
382 assert_eq!(Chain::Moonbeam.chain_type(), ChainType::Hybrid);
383 }
384
385 #[test]
386 fn test_address_creation() {
387 let sub_addr = Address::substrate("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY");
388 assert!(matches!(sub_addr, Address::Substrate(_)));
389
390 let evm_addr = Address::evm("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb7");
391 assert!(matches!(evm_addr, Address::Evm(_)));
392 }
393}