/** * Synor IBC SDK Examples for C++ * * Demonstrates Inter-Blockchain Communication operations: * - Cross-chain transfers and messages * - Channel lifecycle management * - Packet handling and acknowledgments * - Relayer operations * - Connection monitoring */ #include #include #include #include #include using namespace synor::ibc; void chains_example(SynorIbc& ibc) { std::cout << "=== Chain Discovery ===" << std::endl; // Get all connected chains auto chains = ibc.chains().list(); std::cout << "Connected chains: " << chains.size() << std::endl; for (size_t i = 0; i < std::min(chains.size(), size_t(5)); ++i) { const auto& chain = chains[i]; std::cout << "\n " << chain.chain_id() << ":" << std::endl; std::cout << " Name: " << chain.name() << std::endl; std::cout << " Type: " << chain.chain_type() << std::endl; std::cout << " Status: " << chain.status() << std::endl; std::cout << " Block height: " << chain.latest_height() << std::endl; std::cout << " Light client: " << chain.light_client() << std::endl; } // Get specific chain info auto synor_chain = ibc.chains().get("synor-mainnet-1"); std::cout << "\nSynor chain details:" << std::endl; std::cout << " Bech32 prefix: " << synor_chain.bech32_prefix() << std::endl; std::cout << " Gas price: " << synor_chain.gas_price() << std::endl; auto features = synor_chain.features(); std::cout << " Supported features: "; for (size_t i = 0; i < features.size(); ++i) { std::cout << features[i] << (i < features.size() - 1 ? ", " : ""); } std::cout << std::endl; // Get chain connections auto connections = ibc.chains().get_connections("synor-mainnet-1"); std::cout << "\nChain connections: " << connections.size() << std::endl; for (size_t i = 0; i < std::min(connections.size(), size_t(3)); ++i) { const auto& conn = connections[i]; std::cout << " " << conn.connection_id() << " -> " << conn.counterparty_chain_id() << std::endl; } std::cout << std::endl; } void channels_example(SynorIbc& ibc) { std::cout << "=== Channel Management ===" << std::endl; // List existing channels auto channels = ibc.channels().list(); std::cout << "Active channels: " << channels.size() << std::endl; for (size_t i = 0; i < std::min(channels.size(), size_t(3)); ++i) { const auto& channel = channels[i]; std::cout << "\n Channel " << channel.channel_id() << ":" << std::endl; std::cout << " Port: " << channel.port_id() << std::endl; std::cout << " State: " << channel.state() << std::endl; std::cout << " Order: " << channel.ordering() << std::endl; std::cout << " Counterparty: " << channel.counterparty_channel_id() << " on " << channel.counterparty_chain_id() << std::endl; std::cout << " Version: " << channel.version() << std::endl; } // Create a new channel (4-step handshake) std::cout << "\nInitiating channel creation..." << std::endl; // Step 1: ChanOpenInit auto init_result = ibc.channels().open_init({ .port_id = "transfer", .counterparty_chain_id = "cosmos-hub-4", .counterparty_port_id = "transfer", .version = "ics20-1", .ordering = ChannelOrdering::Unordered }); std::cout << "Channel init:" << std::endl; std::cout << " Channel ID: " << init_result.channel_id() << std::endl; std::cout << " State: " << init_result.state() << std::endl; std::cout << " TX hash: " << init_result.tx_hash() << std::endl; // Step 2: Wait for ChanOpenTry (counterparty) std::cout << "\nWaiting for counterparty ChanOpenTry..." << std::endl; auto try_state = ibc.channels().wait_for_state( init_result.channel_id(), ChannelState::TryOpen, std::chrono::minutes(5) ); std::cout << "Channel state: " << try_state << std::endl; // Step 3: ChanOpenAck std::cout << "\nSending ChanOpenAck..." << std::endl; auto ack_result = ibc.channels().open_ack({ .channel_id = init_result.channel_id(), .counterparty_channel_id = "channel-0", .counterparty_version = "ics20-1" }); std::cout << "Ack TX: " << ack_result.tx_hash() << std::endl; // Step 4: Wait for ChanOpenConfirm (counterparty) std::cout << "\nWaiting for channel to open..." << std::endl; auto open_state = ibc.channels().wait_for_state( init_result.channel_id(), ChannelState::Open, std::chrono::minutes(5) ); std::cout << "Channel is now: " << open_state << std::endl; // Get channel details auto channel = ibc.channels().get(init_result.channel_id()); std::cout << "\nChannel details:" << std::endl; std::cout << " Sequences - Send: " << channel.next_sequence_send() << ", Recv: " << channel.next_sequence_recv() << ", Ack: " << channel.next_sequence_ack() << std::endl; std::cout << std::endl; } void transfer_example(SynorIbc& ibc) { std::cout << "=== Cross-Chain Transfers ===" << std::endl; // Get supported tokens for transfer auto tokens = ibc.transfers().get_supported_tokens("cosmos-hub-4"); std::cout << "Transferable tokens to Cosmos Hub:" << std::endl; for (size_t i = 0; i < std::min(tokens.size(), size_t(5)); ++i) { const auto& token = tokens[i]; std::cout << " " << token.symbol() << " (" << token.denom() << ")" << std::endl; } // Initiate a cross-chain transfer std::cout << "\nInitiating transfer..." << std::endl; auto now = std::chrono::system_clock::now(); auto timeout = std::chrono::duration_cast( (now + std::chrono::seconds(600)).time_since_epoch() ).count(); auto transfer = ibc.transfers().send({ .source_channel = "channel-0", .denom = "usynor", .amount = "1000000", .receiver = "cosmos1...", .timeout_height = 0, // Use timestamp instead .timeout_timestamp = static_cast(timeout), .memo = "IBC transfer from Synor" }); std::cout << "Transfer initiated:" << std::endl; std::cout << " TX hash: " << transfer.tx_hash() << std::endl; std::cout << " Sequence: " << transfer.sequence() << std::endl; std::cout << " Packet ID: " << transfer.packet_id() << std::endl; std::cout << " Status: " << transfer.status() << std::endl; // Track transfer progress std::cout << "\nTracking transfer..." << std::endl; auto status = ibc.transfers().track(transfer.packet_id()); std::cout << "Current status: " << status.state() << std::endl; std::cout << "Source TX: " << status.source_tx_hash() << std::endl; if (!status.dest_tx_hash().empty()) { std::cout << "Dest TX: " << status.dest_tx_hash() << std::endl; } // Wait for completion std::cout << "\nWaiting for transfer completion..." << std::endl; auto final_status = ibc.transfers().wait_for_completion( transfer.packet_id(), std::chrono::minutes(10) ); std::cout << "Transfer completed:" << std::endl; std::cout << " Final status: " << final_status.state() << std::endl; std::cout << " Acknowledgment: " << final_status.acknowledgment() << std::endl; // Get transfer history auto history = ibc.transfers().get_history(10); std::cout << "\nRecent transfers: " << history.size() << std::endl; for (size_t i = 0; i < std::min(history.size(), size_t(3)); ++i) { const auto& t = history[i]; std::cout << " " << t.amount() << " " << t.denom() << " -> " << t.dest_chain() << " (" << t.status() << ")" << std::endl; } std::cout << std::endl; } void packet_example(SynorIbc& ibc) { std::cout << "=== Packet Operations ===" << std::endl; // List pending packets auto pending = ibc.packets().list_pending("channel-0"); std::cout << "Pending packets on channel-0: " << pending.size() << std::endl; for (size_t i = 0; i < std::min(pending.size(), size_t(3)); ++i) { const auto& packet = pending[i]; std::cout << "\n Packet #" << packet.sequence() << ":" << std::endl; std::cout << " Source: " << packet.source_port() << "/" << packet.source_channel() << std::endl; std::cout << " Dest: " << packet.dest_port() << "/" << packet.dest_channel() << std::endl; std::cout << " State: " << packet.state() << std::endl; std::cout << " Timeout: " << packet.timeout_timestamp() << std::endl; } // Get specific packet auto packet = ibc.packets().get("channel-0", 1); std::cout << "\nPacket details:" << std::endl; std::cout << " Data (hex): " << packet.data_hex().substr(0, 40) << "..." << std::endl; std::cout << " Created: " << packet.created_at() << std::endl; // Get packet commitment proof auto proof = ibc.packets().get_commitment_proof("channel-0", 1); std::cout << "\nCommitment proof:" << std::endl; std::cout << " Height: " << proof.proof_height() << std::endl; std::cout << " Proof size: " << proof.proof().size() << " bytes" << std::endl; // Get acknowledgment auto ack = ibc.packets().get_acknowledgment("channel-0", 1); std::cout << "\nAcknowledgment:" << std::endl; std::cout << " Result: " << (ack.success() ? "Success" : std::string("Error: ") + ack.error()) << std::endl; std::cout << " TX hash: " << ack.tx_hash() << std::endl; // List timed-out packets auto timed_out = ibc.packets().list_timed_out(); std::cout << "\nTimed-out packets: " << timed_out.size() << std::endl; // Timeout a packet manually if (!timed_out.empty()) { const auto& to_timeout = timed_out.front(); std::cout << "\nProcessing timeout for packet #" << to_timeout.sequence() << std::endl; auto timeout = ibc.packets().timeout(to_timeout.source_channel(), to_timeout.sequence()); std::cout << "Timeout TX: " << timeout.tx_hash() << std::endl; } std::cout << std::endl; } void relayer_example(SynorIbc& ibc) { std::cout << "=== Relayer Operations ===" << std::endl; // Get relayer status auto status = ibc.relayer().get_status(); std::cout << "Relayer status:" << std::endl; std::cout << " Running: " << (status.running() ? "true" : "false") << std::endl; std::cout << " Uptime: " << status.uptime() << std::endl; std::cout << " Packets relayed: " << status.packets_relayed() << std::endl; std::cout << " Errors: " << status.error_count() << std::endl; // List active paths auto paths = ibc.relayer().list_paths(); std::cout << "\nActive relay paths: " << paths.size() << std::endl; for (const auto& path : paths) { std::cout << "\n " << path.path_id() << ":" << std::endl; std::cout << " " << path.source_chain() << " <-> " << path.dest_chain() << std::endl; std::cout << " Channel: " << path.source_channel() << " <-> " << path.dest_channel() << std::endl; std::cout << " Status: " << path.status() << std::endl; std::cout << " Pending packets: " << path.pending_packets() << std::endl; } // Configure a new path std::cout << "\nConfiguring new relay path..." << std::endl; auto new_path = ibc.relayer().add_path({ .source_chain = "synor-mainnet-1", .dest_chain = "osmosis-1", .source_channel = "channel-1", .dest_channel = "channel-100", .filter_denoms = {"usynor", "uosmo"}, .min_relay_amount = "1000", .max_relay_amount = "1000000000" }); std::cout << "Path created: " << new_path.path_id() << std::endl; // Start relaying on path std::cout << "\nStarting relayer on path..." << std::endl; ibc.relayer().start_path(new_path.path_id()); std::cout << "Relayer started" << std::endl; // Manually relay pending packets std::cout << "\nRelaying pending packets..." << std::endl; auto relay_result = ibc.relayer().relay_pending(new_path.path_id()); std::cout << "Relayed " << relay_result.packet_count() << " packets" << std::endl; std::cout << "TX hashes: " << relay_result.tx_hashes().size() << std::endl; // Get relay history auto history = ibc.relayer().get_history(new_path.path_id(), 10); std::cout << "\nRelay history:" << std::endl; for (size_t i = 0; i < std::min(history.size(), size_t(3)); ++i) { const auto& event = history[i]; std::cout << " " << event.timestamp() << ": " << event.event_type() << " - " << event.packet_count() << " packets" << std::endl; } std::cout << std::endl; } void monitoring_example(SynorIbc& ibc) { std::cout << "=== IBC Monitoring ===" << std::endl; // Get IBC metrics auto metrics = ibc.monitoring().get_metrics(); std::cout << "IBC metrics:" << std::endl; std::cout << " Total channels: " << metrics.total_channels() << std::endl; std::cout << " Active channels: " << metrics.active_channels() << std::endl; std::cout << " Total packets: " << metrics.total_packets() << std::endl; std::cout << " Pending packets: " << metrics.pending_packets() << std::endl; std::cout << " Failed packets: " << metrics.failed_packets() << std::endl; std::cout << " Avg relay time: " << metrics.avg_relay_time() << "ms" << std::endl; // Get chain health auto chain_health = ibc.monitoring().get_chain_health(); std::cout << "\nChain health:" << std::endl; for (size_t i = 0; i < std::min(chain_health.size(), size_t(3)); ++i) { const auto& health = chain_health[i]; std::cout << " " << health.chain_id() << ":" << std::endl; std::cout << " Status: " << health.status() << std::endl; std::cout << " Block lag: " << health.block_lag() << std::endl; std::cout << " Last update: " << health.last_update() << std::endl; } // Get channel statistics auto stats = ibc.monitoring().get_channel_stats("channel-0"); std::cout << "\nChannel-0 statistics:" << std::endl; std::cout << " Packets sent: " << stats.packets_sent() << std::endl; std::cout << " Packets received: " << stats.packets_received() << std::endl; std::cout << " Success rate: " << stats.success_rate() << "%" << std::endl; std::cout << " Avg confirmation time: " << stats.avg_confirmation_time() << "ms" << std::endl; // Subscribe to IBC events std::cout << "\nSubscribing to IBC events..." << std::endl; ibc.monitoring().subscribe([](const IbcEvent& event) { std::cout << "Event: " << event.type() << " on " << event.channel_id() << std::endl; }); // Get alerts auto alerts = ibc.monitoring().get_alerts(); std::cout << "\nActive alerts: " << alerts.size() << std::endl; for (const auto& alert : alerts) { std::cout << " [" << alert.severity() << "] " << alert.message() << std::endl; } std::cout << std::endl; } int main(int argc, char** argv) { // Initialize client const char* api_key = std::getenv("SYNOR_API_KEY"); IbcConfig config{ .api_key = api_key ? api_key : "your-api-key", .endpoint = "https://ibc.synor.io/v1", .timeout = std::chrono::seconds(30), .retries = 3, .debug = false, .default_chain = "synor-mainnet-1", .confirmations = 1 }; SynorIbc ibc(config); try { // Check service health bool healthy = ibc.health_check(); std::cout << "Service healthy: " << (healthy ? "true" : "false") << std::endl << std::endl; // Run examples chains_example(ibc); channels_example(ibc); transfer_example(ibc); packet_example(ibc); relayer_example(ibc); monitoring_example(ibc); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; } return 0; }