/** * 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 void chains_example(synor_ibc_t* ibc) { printf("=== Chain Discovery ===\n"); synor_error_t err; // Get all connected chains synor_chain_list_t* chains = NULL; err = synor_chains_list(ibc, &chains); if (err != SYNOR_OK) { fprintf(stderr, "Failed to get chains\n"); return; } printf("Connected chains: %zu\n", synor_chain_list_count(chains)); for (size_t i = 0; i < 5 && i < synor_chain_list_count(chains); i++) { synor_chain_t* chain = synor_chain_list_get(chains, i); printf("\n %s:\n", synor_chain_get_id(chain)); printf(" Name: %s\n", synor_chain_get_name(chain)); printf(" Type: %s\n", synor_chain_get_type(chain)); printf(" Status: %s\n", synor_chain_get_status(chain)); printf(" Block height: %lu\n", synor_chain_get_latest_height(chain)); printf(" Light client: %s\n", synor_chain_get_light_client(chain)); } synor_chain_list_free(chains); // Get specific chain info synor_chain_t* synor_chain = NULL; err = synor_chains_get(ibc, "synor-mainnet-1", &synor_chain); if (err == SYNOR_OK) { printf("\nSynor chain details:\n"); printf(" Bech32 prefix: %s\n", synor_chain_get_bech32_prefix(synor_chain)); printf(" Gas price: %s\n", synor_chain_get_gas_price(synor_chain)); char** features; size_t feature_count; synor_chain_get_features(synor_chain, &features, &feature_count); printf(" Supported features: "); for (size_t i = 0; i < feature_count; i++) { printf("%s%s", features[i], i < feature_count - 1 ? ", " : ""); } printf("\n"); synor_string_array_free(features, feature_count); synor_chain_free(synor_chain); } // Get chain connections synor_connection_list_t* connections = NULL; err = synor_chains_get_connections(ibc, "synor-mainnet-1", &connections); if (err == SYNOR_OK) { printf("\nChain connections: %zu\n", synor_connection_list_count(connections)); for (size_t i = 0; i < 3 && i < synor_connection_list_count(connections); i++) { synor_connection_t* conn = synor_connection_list_get(connections, i); printf(" %s -> %s\n", synor_connection_get_id(conn), synor_connection_get_counterparty_chain_id(conn)); } synor_connection_list_free(connections); } printf("\n"); } void channels_example(synor_ibc_t* ibc) { printf("=== Channel Management ===\n"); synor_error_t err; // List existing channels synor_channel_list_t* channels = NULL; err = synor_channels_list(ibc, &channels); if (err == SYNOR_OK) { printf("Active channels: %zu\n", synor_channel_list_count(channels)); for (size_t i = 0; i < 3 && i < synor_channel_list_count(channels); i++) { synor_channel_t* channel = synor_channel_list_get(channels, i); printf("\n Channel %s:\n", synor_channel_get_id(channel)); printf(" Port: %s\n", synor_channel_get_port_id(channel)); printf(" State: %s\n", synor_channel_get_state(channel)); printf(" Order: %s\n", synor_channel_get_ordering(channel)); printf(" Counterparty: %s on %s\n", synor_channel_get_counterparty_channel_id(channel), synor_channel_get_counterparty_chain_id(channel)); printf(" Version: %s\n", synor_channel_get_version(channel)); } synor_channel_list_free(channels); } // Create a new channel (4-step handshake) printf("\nInitiating channel creation...\n"); // Step 1: ChanOpenInit synor_channel_init_request_t init_req = { .port_id = "transfer", .counterparty_chain_id = "cosmos-hub-4", .counterparty_port_id = "transfer", .version = "ics20-1", .ordering = SYNOR_CHANNEL_ORDERING_UNORDERED }; synor_channel_init_result_t* init_result = NULL; err = synor_channels_open_init(ibc, &init_req, &init_result); if (err != SYNOR_OK) { fprintf(stderr, "Failed to init channel\n"); return; } printf("Channel init:\n"); printf(" Channel ID: %s\n", synor_channel_init_result_get_id(init_result)); printf(" State: %s\n", synor_channel_init_result_get_state(init_result)); printf(" TX hash: %s\n", synor_channel_init_result_get_tx_hash(init_result)); // Step 2: Wait for ChanOpenTry (counterparty) printf("\nWaiting for counterparty ChanOpenTry...\n"); synor_channel_state_t try_state; err = synor_channels_wait_for_state(ibc, synor_channel_init_result_get_id(init_result), SYNOR_CHANNEL_STATE_TRYOPEN, 300, &try_state); printf("Channel state: %d\n", try_state); // Step 3: ChanOpenAck printf("\nSending ChanOpenAck...\n"); synor_channel_ack_request_t ack_req = { .channel_id = synor_channel_init_result_get_id(init_result), .counterparty_channel_id = "channel-0", .counterparty_version = "ics20-1" }; synor_channel_ack_result_t* ack_result = NULL; err = synor_channels_open_ack(ibc, &ack_req, &ack_result); if (err == SYNOR_OK) { printf("Ack TX: %s\n", synor_channel_ack_result_get_tx_hash(ack_result)); synor_channel_ack_result_free(ack_result); } // Step 4: Wait for ChanOpenConfirm (counterparty) printf("\nWaiting for channel to open...\n"); synor_channel_state_t open_state; err = synor_channels_wait_for_state(ibc, synor_channel_init_result_get_id(init_result), SYNOR_CHANNEL_STATE_OPEN, 300, &open_state); printf("Channel is now: %d\n", open_state); // Get channel details synor_channel_t* channel = NULL; err = synor_channels_get(ibc, synor_channel_init_result_get_id(init_result), &channel); if (err == SYNOR_OK) { printf("\nChannel details:\n"); printf(" Sequences - Send: %lu, Recv: %lu, Ack: %lu\n", synor_channel_get_next_sequence_send(channel), synor_channel_get_next_sequence_recv(channel), synor_channel_get_next_sequence_ack(channel)); synor_channel_free(channel); } synor_channel_init_result_free(init_result); printf("\n"); } void transfer_example(synor_ibc_t* ibc) { printf("=== Cross-Chain Transfers ===\n"); synor_error_t err; // Get supported tokens for transfer synor_transferable_token_list_t* tokens = NULL; err = synor_transfers_get_supported_tokens(ibc, "cosmos-hub-4", &tokens); if (err == SYNOR_OK) { printf("Transferable tokens to Cosmos Hub:\n"); for (size_t i = 0; i < 5 && i < synor_transferable_token_list_count(tokens); i++) { synor_transferable_token_t* token = synor_transferable_token_list_get(tokens, i); printf(" %s (%s)\n", synor_transferable_token_get_symbol(token), synor_transferable_token_get_denom(token)); } synor_transferable_token_list_free(tokens); } // Initiate a cross-chain transfer printf("\nInitiating transfer...\n"); synor_transfer_request_t transfer_req = { .source_channel = "channel-0", .denom = "usynor", .amount = "1000000", .receiver = "cosmos1...", .timeout_height = 0, // Use timestamp instead .timeout_timestamp = (uint64_t)(time(NULL) + 600) * 1000000000ULL, .memo = "IBC transfer from Synor" }; synor_transfer_result_t* transfer = NULL; err = synor_transfers_send(ibc, &transfer_req, &transfer); if (err != SYNOR_OK) { fprintf(stderr, "Failed to send transfer\n"); return; } printf("Transfer initiated:\n"); printf(" TX hash: %s\n", synor_transfer_result_get_tx_hash(transfer)); printf(" Sequence: %lu\n", synor_transfer_result_get_sequence(transfer)); printf(" Packet ID: %s\n", synor_transfer_result_get_packet_id(transfer)); printf(" Status: %s\n", synor_transfer_result_get_status(transfer)); // Track transfer progress printf("\nTracking transfer...\n"); synor_transfer_status_t* status = NULL; err = synor_transfers_track(ibc, synor_transfer_result_get_packet_id(transfer), &status); if (err == SYNOR_OK) { printf("Current status: %s\n", synor_transfer_status_get_state(status)); printf("Source TX: %s\n", synor_transfer_status_get_source_tx_hash(status)); const char* dest_tx = synor_transfer_status_get_dest_tx_hash(status); if (dest_tx) { printf("Dest TX: %s\n", dest_tx); } synor_transfer_status_free(status); } // Wait for completion printf("\nWaiting for transfer completion...\n"); synor_transfer_status_t* final_status = NULL; err = synor_transfers_wait_for_completion(ibc, synor_transfer_result_get_packet_id(transfer), 600, &final_status); if (err == SYNOR_OK) { printf("Transfer completed:\n"); printf(" Final status: %s\n", synor_transfer_status_get_state(final_status)); printf(" Acknowledgment: %s\n", synor_transfer_status_get_acknowledgment(final_status)); synor_transfer_status_free(final_status); } // Get transfer history synor_transfer_list_t* history = NULL; err = synor_transfers_get_history(ibc, 10, &history); if (err == SYNOR_OK) { printf("\nRecent transfers: %zu\n", synor_transfer_list_count(history)); for (size_t i = 0; i < 3 && i < synor_transfer_list_count(history); i++) { synor_transfer_t* t = synor_transfer_list_get(history, i); printf(" %s %s -> %s (%s)\n", synor_transfer_get_amount(t), synor_transfer_get_denom(t), synor_transfer_get_dest_chain(t), synor_transfer_get_status(t)); } synor_transfer_list_free(history); } synor_transfer_result_free(transfer); printf("\n"); } void packet_example(synor_ibc_t* ibc) { printf("=== Packet Operations ===\n"); synor_error_t err; // List pending packets synor_packet_list_t* pending = NULL; err = synor_packets_list_pending(ibc, "channel-0", &pending); if (err == SYNOR_OK) { printf("Pending packets on channel-0: %zu\n", synor_packet_list_count(pending)); for (size_t i = 0; i < 3 && i < synor_packet_list_count(pending); i++) { synor_packet_t* packet = synor_packet_list_get(pending, i); printf("\n Packet #%lu:\n", synor_packet_get_sequence(packet)); printf(" Source: %s/%s\n", synor_packet_get_source_port(packet), synor_packet_get_source_channel(packet)); printf(" Dest: %s/%s\n", synor_packet_get_dest_port(packet), synor_packet_get_dest_channel(packet)); printf(" State: %s\n", synor_packet_get_state(packet)); printf(" Timeout: %lu\n", synor_packet_get_timeout_timestamp(packet)); } synor_packet_list_free(pending); } // Get specific packet synor_packet_t* packet = NULL; err = synor_packets_get(ibc, "channel-0", 1, &packet); if (err == SYNOR_OK) { printf("\nPacket details:\n"); const char* data_hex = synor_packet_get_data_hex(packet); printf(" Data (hex): %.40s...\n", data_hex); printf(" Created: %s\n", synor_packet_get_created_at(packet)); synor_packet_free(packet); } // Get packet commitment proof synor_packet_proof_t* proof = NULL; err = synor_packets_get_commitment_proof(ibc, "channel-0", 1, &proof); if (err == SYNOR_OK) { printf("\nCommitment proof:\n"); printf(" Height: %lu\n", synor_packet_proof_get_height(proof)); printf(" Proof size: %zu bytes\n", synor_packet_proof_get_size(proof)); synor_packet_proof_free(proof); } // Get acknowledgment synor_packet_ack_t* ack = NULL; err = synor_packets_get_acknowledgment(ibc, "channel-0", 1, &ack); if (err == SYNOR_OK) { printf("\nAcknowledgment:\n"); printf(" Result: %s\n", synor_packet_ack_is_success(ack) ? "Success" : synor_packet_ack_get_error(ack)); printf(" TX hash: %s\n", synor_packet_ack_get_tx_hash(ack)); synor_packet_ack_free(ack); } // List timed-out packets synor_packet_list_t* timed_out = NULL; err = synor_packets_list_timed_out(ibc, &timed_out); if (err == SYNOR_OK) { printf("\nTimed-out packets: %zu\n", synor_packet_list_count(timed_out)); // Timeout a packet manually if (synor_packet_list_count(timed_out) > 0) { synor_packet_t* to_timeout = synor_packet_list_get(timed_out, 0); printf("\nProcessing timeout for packet #%lu\n", synor_packet_get_sequence(to_timeout)); synor_timeout_result_t* timeout = NULL; err = synor_packets_timeout(ibc, synor_packet_get_source_channel(to_timeout), synor_packet_get_sequence(to_timeout), &timeout); if (err == SYNOR_OK) { printf("Timeout TX: %s\n", synor_timeout_result_get_tx_hash(timeout)); synor_timeout_result_free(timeout); } } synor_packet_list_free(timed_out); } printf("\n"); } void relayer_example(synor_ibc_t* ibc) { printf("=== Relayer Operations ===\n"); synor_error_t err; // Get relayer status synor_relayer_status_t* status = NULL; err = synor_relayer_get_status(ibc, &status); if (err == SYNOR_OK) { printf("Relayer status:\n"); printf(" Running: %s\n", synor_relayer_status_is_running(status) ? "true" : "false"); printf(" Uptime: %s\n", synor_relayer_status_get_uptime(status)); printf(" Packets relayed: %lu\n", synor_relayer_status_get_packets_relayed(status)); printf(" Errors: %lu\n", synor_relayer_status_get_error_count(status)); synor_relayer_status_free(status); } // List active paths synor_relay_path_list_t* paths = NULL; err = synor_relayer_list_paths(ibc, &paths); if (err == SYNOR_OK) { printf("\nActive relay paths: %zu\n", synor_relay_path_list_count(paths)); for (size_t i = 0; i < synor_relay_path_list_count(paths); i++) { synor_relay_path_t* path = synor_relay_path_list_get(paths, i); printf("\n %s:\n", synor_relay_path_get_id(path)); printf(" %s <-> %s\n", synor_relay_path_get_source_chain(path), synor_relay_path_get_dest_chain(path)); printf(" Channel: %s <-> %s\n", synor_relay_path_get_source_channel(path), synor_relay_path_get_dest_channel(path)); printf(" Status: %s\n", synor_relay_path_get_status(path)); printf(" Pending packets: %zu\n", synor_relay_path_get_pending_packets(path)); } synor_relay_path_list_free(paths); } // Configure a new path printf("\nConfiguring new relay path...\n"); const char* filter_denoms[] = {"usynor", "uosmo"}; synor_path_config_t path_config = { .source_chain = "synor-mainnet-1", .dest_chain = "osmosis-1", .source_channel = "channel-1", .dest_channel = "channel-100", .filter_denoms = filter_denoms, .filter_denoms_count = 2, .min_relay_amount = "1000", .max_relay_amount = "1000000000" }; synor_relay_path_t* new_path = NULL; err = synor_relayer_add_path(ibc, &path_config, &new_path); if (err == SYNOR_OK) { printf("Path created: %s\n", synor_relay_path_get_id(new_path)); // Start relaying on path printf("\nStarting relayer on path...\n"); err = synor_relayer_start_path(ibc, synor_relay_path_get_id(new_path)); if (err == SYNOR_OK) { printf("Relayer started\n"); } // Manually relay pending packets printf("\nRelaying pending packets...\n"); synor_relay_result_t* relay_result = NULL; err = synor_relayer_relay_pending(ibc, synor_relay_path_get_id(new_path), &relay_result); if (err == SYNOR_OK) { printf("Relayed %zu packets\n", synor_relay_result_get_packet_count(relay_result)); printf("TX hashes: %zu\n", synor_relay_result_get_tx_hash_count(relay_result)); synor_relay_result_free(relay_result); } // Get relay history synor_relay_event_list_t* history = NULL; err = synor_relayer_get_history(ibc, synor_relay_path_get_id(new_path), 10, &history); if (err == SYNOR_OK) { printf("\nRelay history:\n"); for (size_t i = 0; i < 3 && i < synor_relay_event_list_count(history); i++) { synor_relay_event_t* event = synor_relay_event_list_get(history, i); printf(" %s: %s - %zu packets\n", synor_relay_event_get_timestamp(event), synor_relay_event_get_type(event), synor_relay_event_get_packet_count(event)); } synor_relay_event_list_free(history); } synor_relay_path_free(new_path); } printf("\n"); } void monitoring_example(synor_ibc_t* ibc) { printf("=== IBC Monitoring ===\n"); synor_error_t err; // Get IBC metrics synor_ibc_metrics_t* metrics = NULL; err = synor_monitoring_get_metrics(ibc, &metrics); if (err == SYNOR_OK) { printf("IBC metrics:\n"); printf(" Total channels: %lu\n", synor_ibc_metrics_get_total_channels(metrics)); printf(" Active channels: %lu\n", synor_ibc_metrics_get_active_channels(metrics)); printf(" Total packets: %lu\n", synor_ibc_metrics_get_total_packets(metrics)); printf(" Pending packets: %lu\n", synor_ibc_metrics_get_pending_packets(metrics)); printf(" Failed packets: %lu\n", synor_ibc_metrics_get_failed_packets(metrics)); printf(" Avg relay time: %lums\n", synor_ibc_metrics_get_avg_relay_time(metrics)); synor_ibc_metrics_free(metrics); } // Get chain health synor_chain_health_list_t* chain_health = NULL; err = synor_monitoring_get_chain_health(ibc, &chain_health); if (err == SYNOR_OK) { printf("\nChain health:\n"); for (size_t i = 0; i < 3 && i < synor_chain_health_list_count(chain_health); i++) { synor_chain_health_t* health = synor_chain_health_list_get(chain_health, i); printf(" %s:\n", synor_chain_health_get_chain_id(health)); printf(" Status: %s\n", synor_chain_health_get_status(health)); printf(" Block lag: %lu\n", synor_chain_health_get_block_lag(health)); printf(" Last update: %s\n", synor_chain_health_get_last_update(health)); } synor_chain_health_list_free(chain_health); } // Get channel statistics synor_channel_stats_t* stats = NULL; err = synor_monitoring_get_channel_stats(ibc, "channel-0", &stats); if (err == SYNOR_OK) { printf("\nChannel-0 statistics:\n"); printf(" Packets sent: %lu\n", synor_channel_stats_get_packets_sent(stats)); printf(" Packets received: %lu\n", synor_channel_stats_get_packets_received(stats)); printf(" Success rate: %s%%\n", synor_channel_stats_get_success_rate(stats)); printf(" Avg confirmation time: %lums\n", synor_channel_stats_get_avg_confirmation_time(stats)); synor_channel_stats_free(stats); } // Get alerts synor_ibc_alert_list_t* alerts = NULL; err = synor_monitoring_get_alerts(ibc, &alerts); if (err == SYNOR_OK) { printf("\nActive alerts: %zu\n", synor_ibc_alert_list_count(alerts)); for (size_t i = 0; i < synor_ibc_alert_list_count(alerts); i++) { synor_ibc_alert_t* alert = synor_ibc_alert_list_get(alerts, i); printf(" [%s] %s\n", synor_ibc_alert_get_severity(alert), synor_ibc_alert_get_message(alert)); } synor_ibc_alert_list_free(alerts); } printf("\n"); } int main(int argc, char** argv) { synor_error_t err; // Initialize client synor_ibc_config_t config = { .api_key = getenv("SYNOR_API_KEY") ? getenv("SYNOR_API_KEY") : "your-api-key", .endpoint = "https://ibc.synor.io/v1", .timeout_ms = 30000, .retries = 3, .debug = false, .default_chain = "synor-mainnet-1", .confirmations = 1 }; synor_ibc_t* ibc = NULL; err = synor_ibc_init(&config, &ibc); if (err != SYNOR_OK) { fprintf(stderr, "Failed to initialize IBC client: %s\n", synor_error_string(err)); return 1; } // Check service health bool healthy; err = synor_ibc_health_check(ibc, &healthy); printf("Service healthy: %s\n\n", healthy ? "true" : "false"); // Run examples chains_example(ibc); channels_example(ibc); transfer_example(ibc); packet_example(ibc); relayer_example(ibc); monitoring_example(ibc); // Cleanup synor_ibc_free(ibc); return 0; }