package io.synor.examples; import io.synor.ibc.*; import io.synor.ibc.types.*; import java.time.Duration; import java.time.Instant; import java.util.List; import java.util.concurrent.CompletableFuture; /** * Synor IBC SDK Examples for Java * * Demonstrates Inter-Blockchain Communication operations: * - Cross-chain transfers and messages * - Channel lifecycle management * - Packet handling and acknowledgments * - Relayer operations * - Connection monitoring */ public class IbcExample { public static void main(String[] args) throws Exception { // Initialize client IbcConfig config = IbcConfig.builder() .apiKey(System.getenv("SYNOR_API_KEY") != null ? System.getenv("SYNOR_API_KEY") : "your-api-key") .endpoint("https://ibc.synor.io/v1") .timeout(30000) .retries(3) .debug(false) .defaultChain("synor-mainnet-1") .confirmations(1) .build(); SynorIbc ibc = new SynorIbc(config); try { // Check service health boolean healthy = ibc.healthCheck().get(); System.out.println("Service healthy: " + healthy + "\n"); // Run examples chainsExample(ibc); channelsExample(ibc); transferExample(ibc); packetExample(ibc); relayerExample(ibc); monitoringExample(ibc); } finally { ibc.close(); } } static void chainsExample(SynorIbc ibc) throws Exception { System.out.println("=== Chain Discovery ==="); // Get all connected chains List chains = ibc.chains().list().get(); System.out.println("Connected chains: " + chains.size()); for (Chain chain : chains.subList(0, Math.min(5, chains.size()))) { System.out.println("\n " + chain.getChainId() + ":"); System.out.println(" Name: " + chain.getName()); System.out.println(" Type: " + chain.getChainType()); System.out.println(" Status: " + chain.getStatus()); System.out.println(" Block height: " + chain.getLatestHeight()); System.out.println(" Light client: " + chain.getLightClient()); } // Get specific chain info Chain synorChain = ibc.chains().get("synor-mainnet-1").get(); System.out.println("\nSynor chain details:"); System.out.println(" Bech32 prefix: " + synorChain.getBech32Prefix()); System.out.println(" Gas price: " + synorChain.getGasPrice()); System.out.println(" Supported features: " + String.join(", ", synorChain.getFeatures())); // Get chain connections List connections = ibc.chains().getConnections("synor-mainnet-1").get(); System.out.println("\nChain connections: " + connections.size()); for (Connection conn : connections.subList(0, Math.min(3, connections.size()))) { System.out.println(" " + conn.getConnectionId() + " -> " + conn.getCounterpartyChainId()); } System.out.println(); } static void channelsExample(SynorIbc ibc) throws Exception { System.out.println("=== Channel Management ==="); // List existing channels List channels = ibc.channels().list().get(); System.out.println("Active channels: " + channels.size()); for (Channel channel : channels.subList(0, Math.min(3, channels.size()))) { System.out.println("\n Channel " + channel.getChannelId() + ":"); System.out.println(" Port: " + channel.getPortId()); System.out.println(" State: " + channel.getState()); System.out.println(" Order: " + channel.getOrdering()); System.out.println(" Counterparty: " + channel.getCounterpartyChannelId() + " on " + channel.getCounterpartyChainId()); System.out.println(" Version: " + channel.getVersion()); } // Create a new channel (4-step handshake) System.out.println("\nInitiating channel creation..."); // Step 1: ChanOpenInit ChannelInitResult initResult = ibc.channels().openInit(ChannelInitRequest.builder() .portId("transfer") .counterpartyChainId("cosmos-hub-4") .counterpartyPortId("transfer") .version("ics20-1") .ordering(ChannelOrdering.UNORDERED) .build()).get(); System.out.println("Channel init:"); System.out.println(" Channel ID: " + initResult.getChannelId()); System.out.println(" State: " + initResult.getState()); System.out.println(" TX hash: " + initResult.getTxHash()); // Step 2: Wait for ChanOpenTry (counterparty) System.out.println("\nWaiting for counterparty ChanOpenTry..."); ChannelState tryState = ibc.channels().waitForState( initResult.getChannelId(), ChannelState.TRYOPEN, Duration.ofMinutes(5) ).get(); System.out.println("Channel state: " + tryState); // Step 3: ChanOpenAck System.out.println("\nSending ChanOpenAck..."); ChannelAckResult ackResult = ibc.channels().openAck(ChannelAckRequest.builder() .channelId(initResult.getChannelId()) .counterpartyChannelId("channel-0") .counterpartyVersion("ics20-1") .build()).get(); System.out.println("Ack TX: " + ackResult.getTxHash()); // Step 4: Wait for ChanOpenConfirm (counterparty) System.out.println("\nWaiting for channel to open..."); ChannelState openState = ibc.channels().waitForState( initResult.getChannelId(), ChannelState.OPEN, Duration.ofMinutes(5) ).get(); System.out.println("Channel is now: " + openState); // Get channel details Channel channel = ibc.channels().get(initResult.getChannelId()).get(); System.out.println("\nChannel details:"); System.out.println(" Sequences - Send: " + channel.getNextSequenceSend() + ", Recv: " + channel.getNextSequenceRecv() + ", Ack: " + channel.getNextSequenceAck()); System.out.println(); } static void transferExample(SynorIbc ibc) throws Exception { System.out.println("=== Cross-Chain Transfers ==="); // Get supported tokens for transfer List tokens = ibc.transfers().getSupportedTokens("cosmos-hub-4").get(); System.out.println("Transferable tokens to Cosmos Hub:"); for (TransferableToken token : tokens.subList(0, Math.min(5, tokens.size()))) { System.out.println(" " + token.getSymbol() + " (" + token.getDenom() + ")"); } // Initiate a cross-chain transfer System.out.println("\nInitiating transfer..."); TransferResult transfer = ibc.transfers().send(TransferRequest.builder() .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") .build()).get(); System.out.println("Transfer initiated:"); System.out.println(" TX hash: " + transfer.getTxHash()); System.out.println(" Sequence: " + transfer.getSequence()); System.out.println(" Packet ID: " + transfer.getPacketId()); System.out.println(" Status: " + transfer.getStatus()); // Track transfer progress System.out.println("\nTracking transfer..."); TransferStatus status = ibc.transfers().track(transfer.getPacketId()).get(); System.out.println("Current status: " + status.getState()); System.out.println("Source TX: " + status.getSourceTxHash()); if (status.getDestTxHash() != null) { System.out.println("Dest TX: " + status.getDestTxHash()); } // Wait for completion System.out.println("\nWaiting for transfer completion..."); TransferStatus finalStatus = ibc.transfers().waitForCompletion( transfer.getPacketId(), Duration.ofMinutes(10) ).get(); System.out.println("Transfer completed:"); System.out.println(" Final status: " + finalStatus.getState()); System.out.println(" Acknowledgment: " + finalStatus.getAcknowledgment()); // Get transfer history List history = ibc.transfers().getHistory(10).get(); System.out.println("\nRecent transfers: " + history.size()); for (Transfer t : history.subList(0, Math.min(3, history.size()))) { System.out.println(" " + t.getAmount() + " " + t.getDenom() + " -> " + t.getDestChain() + " (" + t.getStatus() + ")"); } System.out.println(); } static void packetExample(SynorIbc ibc) throws Exception { System.out.println("=== Packet Operations ==="); // List pending packets List pending = ibc.packets().listPending("channel-0").get(); System.out.println("Pending packets on channel-0: " + pending.size()); for (Packet packet : pending.subList(0, Math.min(3, pending.size()))) { System.out.println("\n Packet #" + packet.getSequence() + ":"); System.out.println(" Source: " + packet.getSourcePort() + "/" + packet.getSourceChannel()); System.out.println(" Dest: " + packet.getDestPort() + "/" + packet.getDestChannel()); System.out.println(" State: " + packet.getState()); System.out.println(" Timeout: " + packet.getTimeoutTimestamp()); } // Get specific packet Packet packet = ibc.packets().get("channel-0", 1).get(); System.out.println("\nPacket details:"); System.out.println(" Data (hex): " + packet.getDataHex().substring(0, 40) + "..."); System.out.println(" Created: " + packet.getCreatedAt()); // Get packet commitment proof PacketProof proof = ibc.packets().getCommitmentProof("channel-0", 1).get(); System.out.println("\nCommitment proof:"); System.out.println(" Height: " + proof.getProofHeight()); System.out.println(" Proof size: " + proof.getProof().length + " bytes"); // Get acknowledgment PacketAck ack = ibc.packets().getAcknowledgment("channel-0", 1).get(); System.out.println("\nAcknowledgment:"); System.out.println(" Result: " + (ack.isSuccess() ? "Success" : "Error: " + ack.getError())); System.out.println(" TX hash: " + ack.getTxHash()); // List timed-out packets List timedOut = ibc.packets().listTimedOut().get(); System.out.println("\nTimed-out packets: " + timedOut.size()); // Timeout a packet manually if (!timedOut.isEmpty()) { Packet toTimeout = timedOut.get(0); System.out.println("\nProcessing timeout for packet #" + toTimeout.getSequence()); TimeoutResult timeout = ibc.packets().timeout( toTimeout.getSourceChannel(), toTimeout.getSequence() ).get(); System.out.println("Timeout TX: " + timeout.getTxHash()); } System.out.println(); } static void relayerExample(SynorIbc ibc) throws Exception { System.out.println("=== Relayer Operations ==="); // Get relayer status RelayerStatus status = ibc.relayer().getStatus().get(); System.out.println("Relayer status:"); System.out.println(" Running: " + status.isRunning()); System.out.println(" Uptime: " + status.getUptime()); System.out.println(" Packets relayed: " + status.getPacketsRelayed()); System.out.println(" Errors: " + status.getErrorCount()); // List active paths List paths = ibc.relayer().listPaths().get(); System.out.println("\nActive relay paths: " + paths.size()); for (RelayPath path : paths) { System.out.println("\n " + path.getPathId() + ":"); System.out.println(" " + path.getSourceChain() + " <-> " + path.getDestChain()); System.out.println(" Channel: " + path.getSourceChannel() + " <-> " + path.getDestChannel()); System.out.println(" Status: " + path.getStatus()); System.out.println(" Pending packets: " + path.getPendingPackets()); } // Configure a new path System.out.println("\nConfiguring new relay path..."); RelayPath newPath = ibc.relayer().addPath(PathConfig.builder() .sourceChain("synor-mainnet-1") .destChain("osmosis-1") .sourceChannel("channel-1") .destChannel("channel-100") .filterDenoms(List.of("usynor", "uosmo")) .minRelayAmount("1000") .maxRelayAmount("1000000000") .build()).get(); System.out.println("Path created: " + newPath.getPathId()); // Start relaying on path System.out.println("\nStarting relayer on path..."); ibc.relayer().startPath(newPath.getPathId()).get(); System.out.println("Relayer started"); // Manually relay pending packets System.out.println("\nRelaying pending packets..."); RelayResult relayResult = ibc.relayer().relayPending(newPath.getPathId()).get(); System.out.println("Relayed " + relayResult.getPacketCount() + " packets"); System.out.println("TX hashes: " + relayResult.getTxHashes().size()); // Get relay history List history = ibc.relayer().getHistory(newPath.getPathId(), 10).get(); System.out.println("\nRelay history:"); for (RelayEvent event : history.subList(0, Math.min(3, history.size()))) { System.out.println(" " + event.getTimestamp() + ": " + event.getEventType() + " - " + event.getPacketCount() + " packets"); } System.out.println(); } static void monitoringExample(SynorIbc ibc) throws Exception { System.out.println("=== IBC Monitoring ==="); // Get IBC metrics IbcMetrics metrics = ibc.monitoring().getMetrics().get(); System.out.println("IBC metrics:"); System.out.println(" Total channels: " + metrics.getTotalChannels()); System.out.println(" Active channels: " + metrics.getActiveChannels()); System.out.println(" Total packets: " + metrics.getTotalPackets()); System.out.println(" Pending packets: " + metrics.getPendingPackets()); System.out.println(" Failed packets: " + metrics.getFailedPackets()); System.out.println(" Avg relay time: " + metrics.getAvgRelayTime() + "ms"); // Get chain health List chainHealth = ibc.monitoring().getChainHealth().get(); System.out.println("\nChain health:"); for (ChainHealth health : chainHealth.subList(0, Math.min(3, chainHealth.size()))) { System.out.println(" " + health.getChainId() + ":"); System.out.println(" Status: " + health.getStatus()); System.out.println(" Block lag: " + health.getBlockLag()); System.out.println(" Last update: " + health.getLastUpdate()); } // Get channel statistics ChannelStats stats = ibc.monitoring().getChannelStats("channel-0").get(); System.out.println("\nChannel-0 statistics:"); System.out.println(" Packets sent: " + stats.getPacketsSent()); System.out.println(" Packets received: " + stats.getPacketsReceived()); System.out.println(" Success rate: " + stats.getSuccessRate() + "%"); System.out.println(" Avg confirmation time: " + stats.getAvgConfirmationTime() + "ms"); // Subscribe to IBC events System.out.println("\nSubscribing to IBC events..."); ibc.monitoring().subscribe(event -> { System.out.println("Event: " + event.getType() + " on " + event.getChannelId()); }).get(); // Get alerts List alerts = ibc.monitoring().getAlerts().get(); System.out.println("\nActive alerts: " + alerts.size()); for (IbcAlert alert : alerts) { System.out.println(" [" + alert.getSeverity() + "] " + alert.getMessage()); } System.out.println(); } }