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