synor/sdk/go/examples/ibc_example.go
Gulshan Yadav 9416d76108 Add IBC and ZK SDK examples for Rust
- Introduced `ibc_example.rs` demonstrating Inter-Blockchain Communication operations including cross-chain transfers, channel management, packet handling, and relayer operations.
- Introduced `zk_example.rs` showcasing Zero-Knowledge proof operations such as circuit compilation, proof generation and verification, and on-chain verification with multiple proving systems.
2026-01-28 14:15:51 +05:30

509 lines
15 KiB
Go

// Package main demonstrates the Synor IBC SDK for Go
//
// This example covers Inter-Blockchain Communication operations:
// - Cross-chain token transfers
// - Channel management
// - Packet handling
// - Relayer operations
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/synor/sdk-go/ibc"
)
func main() {
// Initialize client
config := ibc.Config{
APIKey: getEnv("SYNOR_API_KEY", "your-api-key"),
Endpoint: "https://ibc.synor.io/v1",
Timeout: 30 * time.Second,
Retries: 3,
Debug: false,
DefaultNetwork: ibc.NetworkMainnet,
}
client, err := ibc.NewClient(config)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
ctx := context.Background()
// Check service health
healthy, err := client.HealthCheck(ctx)
if err != nil {
log.Printf("Health check failed: %v", err)
} else {
fmt.Printf("Service healthy: %v\n\n", healthy)
}
// Run examples
chainsExample(ctx, client)
channelsExample(ctx, client)
transferExample(ctx, client)
packetExample(ctx, client)
relayerExample(ctx, client)
connectionExample(ctx, client)
}
func chainsExample(ctx context.Context, client *ibc.Client) {
fmt.Println("=== Connected Chains ===")
// Get all connected chains
chains, err := client.Chains.List(ctx)
if err != nil {
log.Printf("Failed to list chains: %v", err)
return
}
fmt.Printf("Connected chains: %d\n", len(chains))
for _, chain := range chains {
fmt.Printf(" %s:\n", chain.ChainID)
fmt.Printf(" Name: %s\n", chain.Name)
fmt.Printf(" Status: %s\n", chain.Status)
fmt.Printf(" Block height: %d\n", chain.LatestHeight)
fmt.Printf(" Channels: %d\n", chain.ChannelCount)
}
// Get specific chain info
cosmos, err := client.Chains.Get(ctx, "cosmoshub-4")
if err != nil {
log.Printf("Failed to get Cosmos Hub: %v", err)
return
}
fmt.Println("\nCosmos Hub details:")
fmt.Printf(" RPC: %s\n", cosmos.RPCEndpoint)
fmt.Printf(" Rest: %s\n", cosmos.RestEndpoint)
fmt.Printf(" Native denom: %s\n", cosmos.NativeDenom)
fmt.Printf(" Prefix: %s\n", cosmos.Bech32Prefix)
// Get supported assets on a chain
assets, err := client.Chains.GetAssets(ctx, "cosmoshub-4")
if err != nil {
log.Printf("Failed to get assets: %v", err)
return
}
fmt.Println("\nSupported assets on Cosmos Hub:")
for _, asset := range assets[:min(5, len(assets))] {
fmt.Printf(" %s: %s\n", asset.Symbol, asset.Denom)
fmt.Printf(" Origin: %s\n", asset.OriginChain)
fmt.Printf(" Decimals: %d\n", asset.Decimals)
}
// Get chain paths (routes)
paths, err := client.Chains.GetPaths(ctx, "synor-1", "cosmoshub-4")
if err != nil {
log.Printf("Failed to get paths: %v", err)
return
}
fmt.Println("\nPaths from Synor to Cosmos Hub:")
for _, path := range paths {
fmt.Printf(" %s -> %s\n", path.SourceChannel, path.DestChannel)
fmt.Printf(" Hops: %d\n", path.Hops)
fmt.Printf(" Avg time: %ds\n", path.AvgTransferTime)
}
fmt.Println()
}
func channelsExample(ctx context.Context, client *ibc.Client) {
fmt.Println("=== Channel Management ===")
// List all channels
channels, err := client.Channels.List(ctx)
if err != nil {
log.Printf("Failed to list channels: %v", err)
return
}
fmt.Printf("Total channels: %d\n", len(channels))
// Filter by state
var openChannels []ibc.Channel
for _, c := range channels {
if c.State == ibc.ChannelStateOpen {
openChannels = append(openChannels, c)
}
}
fmt.Printf("Open channels: %d\n", len(openChannels))
for _, channel := range openChannels[:min(3, len(openChannels))] {
fmt.Printf("\n Channel %s:\n", channel.ChannelID)
fmt.Printf(" Port: %s\n", channel.PortID)
fmt.Printf(" Counterparty: %s on %s\n", channel.CounterpartyChannelID, channel.CounterpartyChainID)
fmt.Printf(" Ordering: %s\n", channel.Ordering)
fmt.Printf(" Version: %s\n", channel.Version)
fmt.Printf(" State: %s\n", channel.State)
}
// Get specific channel
channel, err := client.Channels.Get(ctx, "channel-0")
if err != nil {
log.Printf("Failed to get channel: %v", err)
return
}
fmt.Println("\nChannel-0 details:")
fmt.Printf(" Connection: %s\n", channel.ConnectionID)
fmt.Printf(" Counterparty port: %s\n", channel.CounterpartyPortID)
// Get channel statistics
stats, err := client.Channels.GetStats(ctx, "channel-0")
if err != nil {
log.Printf("Failed to get channel stats: %v", err)
return
}
fmt.Println("\nChannel-0 statistics:")
fmt.Printf(" Total packets sent: %d\n", stats.PacketsSent)
fmt.Printf(" Total packets received: %d\n", stats.PacketsReceived)
fmt.Printf(" Pending packets: %d\n", stats.PendingPackets)
fmt.Printf(" Success rate: %.1f%%\n", stats.SuccessRate)
fmt.Printf(" Avg relay time: %ds\n", stats.AvgRelayTime)
// Get channel capacity
capacity, err := client.Channels.GetCapacity(ctx, "channel-0")
if err != nil {
log.Printf("Failed to get channel capacity: %v", err)
return
}
fmt.Println("\nChannel-0 capacity:")
fmt.Printf(" Max throughput: %d packets/block\n", capacity.MaxPacketsPerBlock)
fmt.Printf(" Current utilization: %.1f%%\n", capacity.Utilization)
fmt.Println()
}
func transferExample(ctx context.Context, client *ibc.Client) {
fmt.Println("=== Cross-Chain Transfers ===")
// Estimate transfer fee
estimate, err := client.Transfers.EstimateFee(ctx, &ibc.FeeEstimateRequest{
SourceChain: "synor-1",
DestChain: "cosmoshub-4",
Denom: "usyn",
Amount: "1000000", // 1 SYN (6 decimals)
})
if err != nil {
log.Printf("Failed to estimate fee: %v", err)
return
}
fmt.Println("Transfer fee estimate:")
fmt.Printf(" Gas: %d\n", estimate.Gas)
fmt.Printf(" Fee: %s %s\n", estimate.Fee, estimate.FeeDenom)
fmt.Printf(" Timeout: %ds\n", estimate.Timeout)
// Initiate a transfer
fmt.Println("\nInitiating transfer...")
transfer, err := client.Transfers.Send(ctx, &ibc.TransferRequest{
SourceChain: "synor-1",
DestChain: "cosmoshub-4",
Channel: "channel-0",
Sender: "synor1abc...", // Your address
Receiver: "cosmos1xyz...", // Recipient address
Denom: "usyn",
Amount: "1000000", // 1 SYN
Memo: "Cross-chain transfer example",
TimeoutHeight: 0, // Use timestamp instead
TimeoutTimestamp: time.Now().Add(10 * time.Minute).UnixMilli(),
})
if err != nil {
log.Printf("Failed to initiate transfer: %v", err)
return
}
fmt.Println("Transfer initiated:")
fmt.Printf(" TX Hash: %s\n", transfer.TxHash)
fmt.Printf(" Sequence: %d\n", transfer.Sequence)
fmt.Printf(" Status: %s\n", transfer.Status)
// Track transfer status
fmt.Println("\nTracking transfer...")
status, err := client.Transfers.GetStatus(ctx, transfer.TxHash)
if err != nil {
log.Printf("Failed to get transfer status: %v", err)
return
}
fmt.Printf("Current status: %s\n", status.State)
fmt.Printf(" Source confirmed: %v\n", status.SourceConfirmed)
fmt.Printf(" Relayed: %v\n", status.Relayed)
fmt.Printf(" Dest confirmed: %v\n", status.DestConfirmed)
// Get transfer history
history, err := client.Transfers.GetHistory(ctx, "synor1abc...", 5)
if err != nil {
log.Printf("Failed to get transfer history: %v", err)
return
}
fmt.Println("\nTransfer history (last 5):")
for _, tx := range history {
direction := "OUT"
if tx.Sender != "synor1abc..." {
direction = "IN"
}
fmt.Printf(" %s %s %s (%s)\n", direction, tx.Amount, tx.Denom, tx.Status)
}
// Get pending transfers
pending, err := client.Transfers.GetPending(ctx, "synor1abc...")
if err != nil {
log.Printf("Failed to get pending transfers: %v", err)
return
}
fmt.Printf("\nPending transfers: %d\n", len(pending))
fmt.Println()
}
func packetExample(ctx context.Context, client *ibc.Client) {
fmt.Println("=== Packet Handling ===")
// Get pending packets
packets, err := client.Packets.GetPending(ctx, "channel-0")
if err != nil {
log.Printf("Failed to get pending packets: %v", err)
return
}
fmt.Printf("Pending packets on channel-0: %d\n", len(packets))
for _, packet := range packets[:min(3, len(packets))] {
fmt.Printf("\n Packet %d:\n", packet.Sequence)
fmt.Printf(" Source: %s/%s\n", packet.SourcePort, packet.SourceChannel)
fmt.Printf(" Dest: %s/%s\n", packet.DestPort, packet.DestChannel)
fmt.Printf(" State: %s\n", packet.State)
fmt.Printf(" Data size: %d bytes\n", len(packet.Data))
fmt.Printf(" Timeout height: %d\n", packet.TimeoutHeight)
fmt.Printf(" Timeout timestamp: %d\n", packet.TimeoutTimestamp)
}
// Get packet by sequence
packet, err := client.Packets.Get(ctx, "channel-0", 1)
if err != nil {
log.Printf("Failed to get packet: %v", err)
return
}
fmt.Println("\nPacket details:")
fmt.Printf(" Commitment: %s\n", packet.Commitment)
fmt.Printf(" Receipt: %s\n", packet.Receipt)
fmt.Printf(" Acknowledgement: %s\n", packet.Acknowledgement)
// Get packet receipts
receipts, err := client.Packets.GetReceipts(ctx, "channel-0", []uint64{1, 2, 3})
if err != nil {
log.Printf("Failed to get receipts: %v", err)
return
}
fmt.Println("\nPacket receipts:")
for seq, receipt := range receipts {
status := "not received"
if receipt {
status = "received"
}
fmt.Printf(" Sequence %d: %s\n", seq, status)
}
// Get timed out packets
timedOut, err := client.Packets.GetTimedOut(ctx, "channel-0")
if err != nil {
log.Printf("Failed to get timed out packets: %v", err)
return
}
fmt.Printf("\nTimed out packets: %d\n", len(timedOut))
for _, p := range timedOut {
fmt.Printf(" Sequence %d: timeout at %d\n", p.Sequence, p.TimeoutTimestamp)
}
// Get unreceived packets
unreceived, err := client.Packets.GetUnreceived(ctx, "channel-0")
if err != nil {
log.Printf("Failed to get unreceived packets: %v", err)
return
}
unreceivedStr := "none"
if len(unreceived) > 0 {
unreceivedStr = fmt.Sprintf("%v", unreceived)
}
fmt.Printf("\nUnreceived packet sequences: %s\n", unreceivedStr)
// Get unacknowledged packets
unacked, err := client.Packets.GetUnacknowledged(ctx, "channel-0")
if err != nil {
log.Printf("Failed to get unacknowledged packets: %v", err)
return
}
unackedStr := "none"
if len(unacked) > 0 {
unackedStr = fmt.Sprintf("%v", unacked)
}
fmt.Printf("Unacknowledged packet sequences: %s\n", unackedStr)
fmt.Println()
}
func relayerExample(ctx context.Context, client *ibc.Client) {
fmt.Println("=== Relayer Operations ===")
// Get active relayers
relayers, err := client.Relayers.List(ctx)
if err != nil {
log.Printf("Failed to list relayers: %v", err)
return
}
fmt.Printf("Active relayers: %d\n", len(relayers))
for _, relayer := range relayers[:min(3, len(relayers))] {
fmt.Printf("\n %s:\n", relayer.Address)
fmt.Printf(" Chains: %v\n", relayer.Chains)
fmt.Printf(" Packets relayed: %d\n", relayer.PacketsRelayed)
fmt.Printf(" Success rate: %.1f%%\n", relayer.SuccessRate)
fmt.Printf(" Avg latency: %dms\n", relayer.AvgLatency)
fmt.Printf(" Fee rate: %.2f%%\n", relayer.FeeRate)
}
// Get relayer statistics
stats, err := client.Relayers.GetStats(ctx)
if err != nil {
log.Printf("Failed to get relayer stats: %v", err)
return
}
fmt.Println("\nGlobal relayer statistics:")
fmt.Printf(" Total relayers: %d\n", stats.TotalRelayers)
fmt.Printf(" Active relayers: %d\n", stats.ActiveRelayers)
fmt.Printf(" Packets relayed (24h): %d\n", stats.PacketsRelayed24h)
fmt.Printf(" Total fees earned: %s\n", stats.TotalFeesEarned)
// Register as a relayer
fmt.Println("\nRegistering as relayer...")
registration, err := client.Relayers.Register(ctx, &ibc.RelayerRegistration{
Chains: []string{"synor-1", "cosmoshub-4"},
FeeRate: 0.1, // 0.1% fee
MinPacketSize: 0,
MaxPacketSize: 1000000,
})
if err != nil {
log.Printf("Failed to register as relayer: %v", err)
return
}
fmt.Printf("Registered with address: %s\n", registration.RelayerAddress)
// Start relaying (in background)
fmt.Println("\nStarting relay service...")
relaySession, err := client.Relayers.StartRelay(ctx, &ibc.RelayConfig{
Channels: []string{"channel-0"},
AutoAck: true,
BatchSize: 10,
PollInterval: 5000,
})
if err != nil {
log.Printf("Failed to start relay: %v", err)
return
}
fmt.Printf("Relay session started: %s\n", relaySession.SessionID)
// Get relay queue
queue, err := client.Relayers.GetQueue(ctx, "channel-0")
if err != nil {
log.Printf("Failed to get relay queue: %v", err)
return
}
fmt.Printf("\nRelay queue for channel-0: %d packets\n", len(queue))
// Manually relay a packet
if len(queue) > 0 {
fmt.Println("\nRelaying packet...")
relayResult, err := client.Relayers.RelayPacket(ctx, queue[0].Sequence, "channel-0")
if err != nil {
log.Printf("Failed to relay packet: %v", err)
} else {
fmt.Printf("Relay result: %s\n", relayResult.Status)
fmt.Printf(" TX Hash: %s\n", relayResult.TxHash)
fmt.Printf(" Fee earned: %s\n", relayResult.FeeEarned)
}
}
// Stop relay session
err = client.Relayers.StopRelay(ctx, relaySession.SessionID)
if err != nil {
log.Printf("Failed to stop relay: %v", err)
} else {
fmt.Println("\nRelay session stopped")
}
fmt.Println()
}
func connectionExample(ctx context.Context, client *ibc.Client) {
fmt.Println("=== Connection Information ===")
// List connections
connections, err := client.Connections.List(ctx)
if err != nil {
log.Printf("Failed to list connections: %v", err)
return
}
fmt.Printf("Total connections: %d\n", len(connections))
for _, conn := range connections[:min(3, len(connections))] {
fmt.Printf("\n %s:\n", conn.ConnectionID)
fmt.Printf(" Client: %s\n", conn.ClientID)
fmt.Printf(" Counterparty: %s\n", conn.CounterpartyConnectionID)
fmt.Printf(" State: %s\n", conn.State)
fmt.Printf(" Versions: %v\n", conn.Versions)
}
// Get connection details
connection, err := client.Connections.Get(ctx, "connection-0")
if err != nil {
log.Printf("Failed to get connection: %v", err)
return
}
fmt.Println("\nConnection-0 details:")
fmt.Printf(" Delay period: %dns\n", connection.DelayPeriod)
fmt.Printf(" Counterparty client: %s\n", connection.CounterpartyClientID)
fmt.Printf(" Counterparty prefix: %s\n", connection.CounterpartyPrefix)
// Get client state
clientState, err := client.Clients.Get(ctx, connection.ClientID)
if err != nil {
log.Printf("Failed to get client state: %v", err)
return
}
fmt.Println("\nClient state:")
fmt.Printf(" Chain ID: %s\n", clientState.ChainID)
fmt.Printf(" Trust level: %s\n", clientState.TrustLevel)
fmt.Printf(" Trusting period: %s\n", clientState.TrustingPeriod)
fmt.Printf(" Unbonding period: %s\n", clientState.UnbondingPeriod)
fmt.Printf(" Latest height: %d\n", clientState.LatestHeight)
fmt.Printf(" Frozen: %v\n", clientState.Frozen)
// Get consensus state
consensus, err := client.Clients.GetConsensusState(ctx, connection.ClientID, clientState.LatestHeight)
if err != nil {
log.Printf("Failed to get consensus state: %v", err)
return
}
fmt.Printf("\nConsensus state at height %d:\n", clientState.LatestHeight)
fmt.Printf(" Timestamp: %s\n", consensus.Timestamp)
fmt.Printf(" Root: %s...\n", consensus.Root[:min(20, len(consensus.Root))])
fmt.Printf(" Next validators hash: %s...\n", consensus.NextValidatorsHash[:min(20, len(consensus.NextValidatorsHash))])
fmt.Println()
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}