synor/sdk/rust/examples/ibc_example.rs
Gulshan Yadav 9416d76108 Add IBC and ZK SDK examples for Rust
- Introduced `ibc_example.rs` demonstrating Inter-Blockchain Communication operations including cross-chain transfers, channel management, packet handling, and relayer operations.
- Introduced `zk_example.rs` showcasing Zero-Knowledge proof operations such as circuit compilation, proof generation and verification, and on-chain verification with multiple proving systems.
2026-01-28 14:15:51 +05:30

407 lines
14 KiB
Rust

//! 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<dyn std::error::Error>> {
// 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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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(())
}