//! Synor IBC SDK Examples for Rust //! //! Demonstrates Inter-Blockchain Communication operations: //! - Cross-chain token transfers //! - Channel management //! - Packet handling //! - Relayer operations use std::env; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use synor_ibc::{ ChannelState, FeeEstimateRequest, IbcConfig, Network, RelayConfig, RelayerRegistration, SynorIbc, TransferRequest, }; #[tokio::main] async fn main() -> Result<(), Box> { // Initialize client let config = IbcConfig { api_key: env::var("SYNOR_API_KEY").unwrap_or_else(|_| "your-api-key".to_string()), endpoint: "https://ibc.synor.io/v1".to_string(), timeout: 30000, retries: 3, debug: false, default_network: Network::Mainnet, }; let ibc = SynorIbc::new(config)?; // Check service health let healthy = ibc.health_check().await?; println!("Service healthy: {}\n", healthy); // Run examples chains_example(&ibc).await?; channels_example(&ibc).await?; transfer_example(&ibc).await?; packet_example(&ibc).await?; relayer_example(&ibc).await?; connection_example(&ibc).await?; ibc.close().await?; Ok(()) } async fn chains_example(ibc: &SynorIbc) -> Result<(), Box> { println!("=== Connected Chains ==="); // Get all connected chains let chains = ibc.chains.list().await?; println!("Connected chains: {}", chains.len()); for chain in &chains { println!(" {}:", chain.chain_id); println!(" Name: {}", chain.name); println!(" Status: {}", chain.status); println!(" Block height: {}", chain.latest_height); println!(" Channels: {}", chain.channel_count); } // Get specific chain info let cosmos = ibc.chains.get("cosmoshub-4").await?; println!("\nCosmos Hub details:"); println!(" RPC: {}", cosmos.rpc_endpoint); println!(" Rest: {}", cosmos.rest_endpoint); println!(" Native denom: {}", cosmos.native_denom); println!(" Prefix: {}", cosmos.bech32_prefix); // Get supported assets on a chain let assets = ibc.chains.get_assets("cosmoshub-4").await?; println!("\nSupported assets on Cosmos Hub:"); for asset in assets.iter().take(5) { println!(" {}: {}", asset.symbol, asset.denom); println!(" Origin: {}", asset.origin_chain); println!(" Decimals: {}", asset.decimals); } // Get chain paths (routes) let paths = ibc.chains.get_paths("synor-1", "cosmoshub-4").await?; println!("\nPaths from Synor to Cosmos Hub:"); for path in &paths { println!(" {} -> {}", path.source_channel, path.dest_channel); println!(" Hops: {}", path.hops); println!(" Avg time: {}s", path.avg_transfer_time); } println!(); Ok(()) } async fn channels_example(ibc: &SynorIbc) -> Result<(), Box> { println!("=== Channel Management ==="); // List all channels let channels = ibc.channels.list().await?; println!("Total channels: {}", channels.len()); // Filter by state let open_channels: Vec<_> = channels .iter() .filter(|c| c.state == ChannelState::Open) .collect(); println!("Open channels: {}", open_channels.len()); for channel in open_channels.iter().take(3) { println!("\n Channel {}:", channel.channel_id); println!(" Port: {}", channel.port_id); println!( " Counterparty: {} on {}", channel.counterparty_channel_id, channel.counterparty_chain_id ); println!(" Ordering: {}", channel.ordering); println!(" Version: {}", channel.version); println!(" State: {:?}", channel.state); } // Get specific channel let channel = ibc.channels.get("channel-0").await?; println!("\nChannel-0 details:"); println!(" Connection: {}", channel.connection_id); println!(" Counterparty port: {}", channel.counterparty_port_id); // Get channel statistics let stats = ibc.channels.get_stats("channel-0").await?; println!("\nChannel-0 statistics:"); println!(" Total packets sent: {}", stats.packets_sent); println!(" Total packets received: {}", stats.packets_received); println!(" Pending packets: {}", stats.pending_packets); println!(" Success rate: {:.1}%", stats.success_rate); println!(" Avg relay time: {}s", stats.avg_relay_time); // Get channel capacity let capacity = ibc.channels.get_capacity("channel-0").await?; println!("\nChannel-0 capacity:"); println!(" Max throughput: {} packets/block", capacity.max_packets_per_block); println!(" Current utilization: {:.1}%", capacity.utilization); println!(); Ok(()) } async fn transfer_example(ibc: &SynorIbc) -> Result<(), Box> { println!("=== Cross-Chain Transfers ==="); // Estimate transfer fee let estimate = ibc .transfers .estimate_fee(FeeEstimateRequest { source_chain: "synor-1".to_string(), dest_chain: "cosmoshub-4".to_string(), denom: "usyn".to_string(), amount: "1000000".to_string(), // 1 SYN (6 decimals) }) .await?; println!("Transfer fee estimate:"); println!(" Gas: {}", estimate.gas); println!(" Fee: {} {}", estimate.fee, estimate.fee_denom); println!(" Timeout: {}s", estimate.timeout); // Calculate timeout timestamp (10 minutes from now) let timeout_timestamp = SystemTime::now() .duration_since(UNIX_EPOCH)? .as_millis() as u64 + 600000; // Initiate a transfer println!("\nInitiating transfer..."); let transfer = ibc .transfers .send(TransferRequest { source_chain: "synor-1".to_string(), dest_chain: "cosmoshub-4".to_string(), channel: "channel-0".to_string(), sender: "synor1abc...".to_string(), // Your address receiver: "cosmos1xyz...".to_string(), // Recipient address denom: "usyn".to_string(), amount: "1000000".to_string(), // 1 SYN memo: Some("Cross-chain transfer example".to_string()), timeout_height: 0, // Use timestamp instead timeout_timestamp, }) .await?; println!("Transfer initiated:"); println!(" TX Hash: {}", transfer.tx_hash); println!(" Sequence: {}", transfer.sequence); println!(" Status: {}", transfer.status); // Track transfer status println!("\nTracking transfer..."); let status = ibc.transfers.get_status(&transfer.tx_hash).await?; println!("Current status: {}", status.state); println!(" Source confirmed: {}", status.source_confirmed); println!(" Relayed: {}", status.relayed); println!(" Dest confirmed: {}", status.dest_confirmed); // Get transfer history let history = ibc.transfers.get_history("synor1abc...", 5).await?; println!("\nTransfer history (last 5):"); for tx in &history { let direction = if tx.sender == "synor1abc..." { "OUT" } else { "IN" }; println!(" {} {} {} ({})", direction, tx.amount, tx.denom, tx.status); } // Get pending transfers let pending = ibc.transfers.get_pending("synor1abc...").await?; println!("\nPending transfers: {}", pending.len()); println!(); Ok(()) } async fn packet_example(ibc: &SynorIbc) -> Result<(), Box> { println!("=== Packet Handling ==="); // Get pending packets let packets = ibc.packets.get_pending("channel-0").await?; println!("Pending packets on channel-0: {}", packets.len()); for packet in packets.iter().take(3) { println!("\n Packet {}:", packet.sequence); println!(" Source: {}/{}", packet.source_port, packet.source_channel); println!(" Dest: {}/{}", packet.dest_port, packet.dest_channel); println!(" State: {}", packet.state); println!(" Data size: {} bytes", packet.data.len()); println!(" Timeout height: {}", packet.timeout_height); println!(" Timeout timestamp: {}", packet.timeout_timestamp); } // Get packet by sequence let packet = ibc.packets.get("channel-0", 1).await?; println!("\nPacket details:"); println!(" Commitment: {}", packet.commitment); println!(" Receipt: {}", packet.receipt.unwrap_or_default()); println!(" Acknowledgement: {}", packet.acknowledgement.unwrap_or_default()); // Get packet receipts let receipts = ibc.packets.get_receipts("channel-0", &[1, 2, 3]).await?; println!("\nPacket receipts:"); for (seq, receipt) in &receipts { let status = if *receipt { "received" } else { "not received" }; println!(" Sequence {}: {}", seq, status); } // Get timed out packets let timed_out = ibc.packets.get_timed_out("channel-0").await?; println!("\nTimed out packets: {}", timed_out.len()); for p in &timed_out { println!(" Sequence {}: timeout at {}", p.sequence, p.timeout_timestamp); } // Get unreceived packets let unreceived = ibc.packets.get_unreceived("channel-0").await?; let unreceived_str = if unreceived.is_empty() { "none".to_string() } else { format!("{:?}", unreceived) }; println!("\nUnreceived packet sequences: {}", unreceived_str); // Get unacknowledged packets let unacked = ibc.packets.get_unacknowledged("channel-0").await?; let unacked_str = if unacked.is_empty() { "none".to_string() } else { format!("{:?}", unacked) }; println!("Unacknowledged packet sequences: {}", unacked_str); println!(); Ok(()) } async fn relayer_example(ibc: &SynorIbc) -> Result<(), Box> { println!("=== Relayer Operations ==="); // Get active relayers let relayers = ibc.relayers.list().await?; println!("Active relayers: {}", relayers.len()); for relayer in relayers.iter().take(3) { println!("\n {}:", relayer.address); println!(" Chains: {:?}", relayer.chains); println!(" Packets relayed: {}", relayer.packets_relayed); println!(" Success rate: {:.1}%", relayer.success_rate); println!(" Avg latency: {}ms", relayer.avg_latency); println!(" Fee rate: {:.2}%", relayer.fee_rate); } // Get relayer statistics let stats = ibc.relayers.get_stats().await?; println!("\nGlobal relayer statistics:"); println!(" Total relayers: {}", stats.total_relayers); println!(" Active relayers: {}", stats.active_relayers); println!(" Packets relayed (24h): {}", stats.packets_relayed_24h); println!(" Total fees earned: {}", stats.total_fees_earned); // Register as a relayer println!("\nRegistering as relayer..."); let registration = ibc .relayers .register(RelayerRegistration { chains: vec!["synor-1".to_string(), "cosmoshub-4".to_string()], fee_rate: 0.1, // 0.1% fee min_packet_size: 0, max_packet_size: 1000000, }) .await?; println!("Registered with address: {}", registration.relayer_address); // Start relaying (in background) println!("\nStarting relay service..."); let relay_session = ibc .relayers .start_relay(RelayConfig { channels: vec!["channel-0".to_string()], auto_ack: true, batch_size: 10, poll_interval: 5000, }) .await?; println!("Relay session started: {}", relay_session.session_id); // Get relay queue let queue = ibc.relayers.get_queue("channel-0").await?; println!("\nRelay queue for channel-0: {} packets", queue.len()); // Manually relay a packet if let Some(first_packet) = queue.first() { println!("\nRelaying packet..."); let relay_result = ibc .relayers .relay_packet(first_packet.sequence, "channel-0") .await?; println!("Relay result: {}", relay_result.status); println!(" TX Hash: {}", relay_result.tx_hash); println!(" Fee earned: {}", relay_result.fee_earned); } // Stop relay session ibc.relayers.stop_relay(&relay_session.session_id).await?; println!("\nRelay session stopped"); println!(); Ok(()) } async fn connection_example(ibc: &SynorIbc) -> Result<(), Box> { println!("=== Connection Information ==="); // List connections let connections = ibc.connections.list().await?; println!("Total connections: {}", connections.len()); for conn in connections.iter().take(3) { println!("\n {}:", conn.connection_id); println!(" Client: {}", conn.client_id); println!(" Counterparty: {}", conn.counterparty_connection_id); println!(" State: {}", conn.state); println!(" Versions: {:?}", conn.versions); } // Get connection details let connection = ibc.connections.get("connection-0").await?; println!("\nConnection-0 details:"); println!(" Delay period: {}ns", connection.delay_period); println!(" Counterparty client: {}", connection.counterparty_client_id); println!(" Counterparty prefix: {}", connection.counterparty_prefix); // Get client state let client = ibc.clients.get(&connection.client_id).await?; println!("\nClient state:"); println!(" Chain ID: {}", client.chain_id); println!(" Trust level: {}", client.trust_level); println!(" Trusting period: {}", client.trusting_period); println!(" Unbonding period: {}", client.unbonding_period); println!(" Latest height: {}", client.latest_height); println!(" Frozen: {}", client.frozen); // Get consensus state let consensus = ibc .clients .get_consensus_state(&connection.client_id, client.latest_height) .await?; println!("\nConsensus state at height {}:", client.latest_height); println!(" Timestamp: {}", consensus.timestamp); let root_preview = if consensus.root.len() > 20 { &consensus.root[..20] } else { &consensus.root }; println!(" Root: {}...", root_preview); let validators_preview = if consensus.next_validators_hash.len() > 20 { &consensus.next_validators_hash[..20] } else { &consensus.next_validators_hash }; println!(" Next validators hash: {}...", validators_preview); println!(); Ok(()) }