import Foundation import SynorIbc /// Synor IBC SDK Examples for Swift /// /// Demonstrates Inter-Blockchain Communication operations: /// - Cross-chain transfers and messages /// - Channel lifecycle management /// - Packet handling and acknowledgments /// - Relayer operations /// - Connection monitoring @main struct IbcExample { static func main() async throws { // Initialize client let config = IbcConfig( apiKey: ProcessInfo.processInfo.environment["SYNOR_API_KEY"] ?? "your-api-key", endpoint: "https://ibc.synor.io/v1", timeout: 30, retries: 3, debug: false, defaultChain: "synor-mainnet-1", confirmations: 1 ) let ibc = SynorIbc(config: config) do { // Check service health let healthy = try await ibc.healthCheck() print("Service healthy: \(healthy)\n") // Run examples try await chainsExample(ibc: ibc) try await channelsExample(ibc: ibc) try await transferExample(ibc: ibc) try await packetExample(ibc: ibc) try await relayerExample(ibc: ibc) try await monitoringExample(ibc: ibc) } catch { print("Error: \(error)") } await ibc.close() } static func chainsExample(ibc: SynorIbc) async throws { print("=== Chain Discovery ===") // Get all connected chains let chains = try await ibc.chains.list() print("Connected chains: \(chains.count)") for chain in chains.prefix(5) { print("\n \(chain.chainId):") print(" Name: \(chain.name)") print(" Type: \(chain.chainType)") print(" Status: \(chain.status)") print(" Block height: \(chain.latestHeight)") print(" Light client: \(chain.lightClient)") } // Get specific chain info let synorChain = try await ibc.chains.get(chainId: "synor-mainnet-1") print("\nSynor chain details:") print(" Bech32 prefix: \(synorChain.bech32Prefix)") print(" Gas price: \(synorChain.gasPrice)") print(" Supported features: \(synorChain.features.joined(separator: ", "))") // Get chain connections let connections = try await ibc.chains.getConnections(chainId: "synor-mainnet-1") print("\nChain connections: \(connections.count)") for conn in connections.prefix(3) { print(" \(conn.connectionId) -> \(conn.counterpartyChainId)") } print() } static func channelsExample(ibc: SynorIbc) async throws { print("=== Channel Management ===") // List existing channels let channels = try await ibc.channels.list() print("Active channels: \(channels.count)") for channel in channels.prefix(3) { print("\n Channel \(channel.channelId):") print(" Port: \(channel.portId)") print(" State: \(channel.state)") print(" Order: \(channel.ordering)") print(" Counterparty: \(channel.counterpartyChannelId) on \(channel.counterpartyChainId)") print(" Version: \(channel.version)") } // Create a new channel (4-step handshake) print("\nInitiating channel creation...") // Step 1: ChanOpenInit let initResult = try await ibc.channels.openInit( ChannelInitRequest( portId: "transfer", counterpartyChainId: "cosmos-hub-4", counterpartyPortId: "transfer", version: "ics20-1", ordering: .unordered ) ) print("Channel init:") print(" Channel ID: \(initResult.channelId)") print(" State: \(initResult.state)") print(" TX hash: \(initResult.txHash)") // Step 2: Wait for ChanOpenTry (counterparty) print("\nWaiting for counterparty ChanOpenTry...") let tryState = try await ibc.channels.waitForState( channelId: initResult.channelId, state: .tryopen, timeout: 300 // 5 minutes ) print("Channel state: \(tryState)") // Step 3: ChanOpenAck print("\nSending ChanOpenAck...") let ackResult = try await ibc.channels.openAck( ChannelAckRequest( channelId: initResult.channelId, counterpartyChannelId: "channel-0", counterpartyVersion: "ics20-1" ) ) print("Ack TX: \(ackResult.txHash)") // Step 4: Wait for ChanOpenConfirm (counterparty) print("\nWaiting for channel to open...") let openState = try await ibc.channels.waitForState( channelId: initResult.channelId, state: .open, timeout: 300 ) print("Channel is now: \(openState)") // Get channel details let channel = try await ibc.channels.get(channelId: initResult.channelId) print("\nChannel details:") print(" Sequences - Send: \(channel.nextSequenceSend), Recv: \(channel.nextSequenceRecv), Ack: \(channel.nextSequenceAck)") print() } static func transferExample(ibc: SynorIbc) async throws { print("=== Cross-Chain Transfers ===") // Get supported tokens for transfer let tokens = try await ibc.transfers.getSupportedTokens(targetChain: "cosmos-hub-4") print("Transferable tokens to Cosmos Hub:") for token in tokens.prefix(5) { print(" \(token.symbol) (\(token.denom))") } // Initiate a cross-chain transfer print("\nInitiating transfer...") let transfer = try await ibc.transfers.send( TransferRequest( sourceChannel: "channel-0", denom: "usynor", amount: "1000000", receiver: "cosmos1...", timeoutHeight: 0, // Use timestamp instead timeoutTimestamp: UInt64(Date().timeIntervalSince1970 + 600) * 1_000_000_000, memo: "IBC transfer from Synor" ) ) print("Transfer initiated:") print(" TX hash: \(transfer.txHash)") print(" Sequence: \(transfer.sequence)") print(" Packet ID: \(transfer.packetId)") print(" Status: \(transfer.status)") // Track transfer progress print("\nTracking transfer...") let status = try await ibc.transfers.track(packetId: transfer.packetId) print("Current status: \(status.state)") print("Source TX: \(status.sourceTxHash)") if let destTx = status.destTxHash { print("Dest TX: \(destTx)") } // Wait for completion print("\nWaiting for transfer completion...") let finalStatus = try await ibc.transfers.waitForCompletion( packetId: transfer.packetId, timeout: 600 // 10 minutes ) print("Transfer completed:") print(" Final status: \(finalStatus.state)") print(" Acknowledgment: \(finalStatus.acknowledgment)") // Get transfer history let history = try await ibc.transfers.getHistory(limit: 10) print("\nRecent transfers: \(history.count)") for t in history.prefix(3) { print(" \(t.amount) \(t.denom) -> \(t.destChain) (\(t.status))") } print() } static func packetExample(ibc: SynorIbc) async throws { print("=== Packet Operations ===") // List pending packets let pending = try await ibc.packets.listPending(channelId: "channel-0") print("Pending packets on channel-0: \(pending.count)") for packet in pending.prefix(3) { print("\n Packet #\(packet.sequence):") print(" Source: \(packet.sourcePort)/\(packet.sourceChannel)") print(" Dest: \(packet.destPort)/\(packet.destChannel)") print(" State: \(packet.state)") print(" Timeout: \(packet.timeoutTimestamp)") } // Get specific packet let packet = try await ibc.packets.get(channelId: "channel-0", sequence: 1) print("\nPacket details:") print(" Data (hex): \(packet.dataHex.prefix(40))...") print(" Created: \(packet.createdAt)") // Get packet commitment proof let proof = try await ibc.packets.getCommitmentProof(channelId: "channel-0", sequence: 1) print("\nCommitment proof:") print(" Height: \(proof.proofHeight)") print(" Proof size: \(proof.proof.count) bytes") // Get acknowledgment let ack = try await ibc.packets.getAcknowledgment(channelId: "channel-0", sequence: 1) print("\nAcknowledgment:") print(" Result: \(ack.success ? "Success" : "Error: \(ack.error ?? "unknown")")") print(" TX hash: \(ack.txHash)") // List timed-out packets let timedOut = try await ibc.packets.listTimedOut() print("\nTimed-out packets: \(timedOut.count)") // Timeout a packet manually if let toTimeout = timedOut.first { print("\nProcessing timeout for packet #\(toTimeout.sequence)") let timeout = try await ibc.packets.timeout( channelId: toTimeout.sourceChannel, sequence: toTimeout.sequence ) print("Timeout TX: \(timeout.txHash)") } print() } static func relayerExample(ibc: SynorIbc) async throws { print("=== Relayer Operations ===") // Get relayer status let status = try await ibc.relayer.getStatus() print("Relayer status:") print(" Running: \(status.running)") print(" Uptime: \(status.uptime)") print(" Packets relayed: \(status.packetsRelayed)") print(" Errors: \(status.errorCount)") // List active paths let paths = try await ibc.relayer.listPaths() print("\nActive relay paths: \(paths.count)") for path in paths { print("\n \(path.pathId):") print(" \(path.sourceChain) <-> \(path.destChain)") print(" Channel: \(path.sourceChannel) <-> \(path.destChannel)") print(" Status: \(path.status)") print(" Pending packets: \(path.pendingPackets)") } // Configure a new path print("\nConfiguring new relay path...") let newPath = try await ibc.relayer.addPath( PathConfig( sourceChain: "synor-mainnet-1", destChain: "osmosis-1", sourceChannel: "channel-1", destChannel: "channel-100", filterDenoms: ["usynor", "uosmo"], minRelayAmount: "1000", maxRelayAmount: "1000000000" ) ) print("Path created: \(newPath.pathId)") // Start relaying on path print("\nStarting relayer on path...") try await ibc.relayer.startPath(pathId: newPath.pathId) print("Relayer started") // Manually relay pending packets print("\nRelaying pending packets...") let relayResult = try await ibc.relayer.relayPending(pathId: newPath.pathId) print("Relayed \(relayResult.packetCount) packets") print("TX hashes: \(relayResult.txHashes.count)") // Get relay history let history = try await ibc.relayer.getHistory(pathId: newPath.pathId, limit: 10) print("\nRelay history:") for event in history.prefix(3) { print(" \(event.timestamp): \(event.eventType) - \(event.packetCount) packets") } print() } static func monitoringExample(ibc: SynorIbc) async throws { print("=== IBC Monitoring ===") // Get IBC metrics let metrics = try await ibc.monitoring.getMetrics() print("IBC metrics:") print(" Total channels: \(metrics.totalChannels)") print(" Active channels: \(metrics.activeChannels)") print(" Total packets: \(metrics.totalPackets)") print(" Pending packets: \(metrics.pendingPackets)") print(" Failed packets: \(metrics.failedPackets)") print(" Avg relay time: \(metrics.avgRelayTime)ms") // Get chain health let chainHealth = try await ibc.monitoring.getChainHealth() print("\nChain health:") for health in chainHealth.prefix(3) { print(" \(health.chainId):") print(" Status: \(health.status)") print(" Block lag: \(health.blockLag)") print(" Last update: \(health.lastUpdate)") } // Get channel statistics let stats = try await ibc.monitoring.getChannelStats(channelId: "channel-0") print("\nChannel-0 statistics:") print(" Packets sent: \(stats.packetsSent)") print(" Packets received: \(stats.packetsReceived)") print(" Success rate: \(stats.successRate)%") print(" Avg confirmation time: \(stats.avgConfirmationTime)ms") // Subscribe to IBC events print("\nSubscribing to IBC events...") try await ibc.monitoring.subscribe { event in print("Event: \(event.type) on \(event.channelId)") } // Get alerts let alerts = try await ibc.monitoring.getAlerts() print("\nActive alerts: \(alerts.count)") for alert in alerts { print(" [\(alert.severity)] \(alert.message)") } print() } }