- 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.
509 lines
15 KiB
Go
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
|
|
}
|