Add example code demonstrating all SDK services (Crypto, DEX, ZK, IBC, Compiler) for the remaining languages: - C SDK (5 examples): Using synor_* C API with explicit memory management - C++ SDK (5 examples): Modern C++17 with RAII and designated initializers - C# SDK (5 examples): Async/await patterns with .NET conventions - Ruby SDK (5 examples): Ruby idioms with blocks and symbols Each example covers: - Crypto: Hybrid signatures, mnemonics, Falcon, SPHINCS+, KDF, hashing - DEX: Markets, spot trading, perpetuals, liquidity, portfolio - ZK: Circuits, Groth16, PLONK, STARK, recursive proofs, ceremonies - IBC: Chains, channels, transfers, packets, relayer, monitoring - Compiler: Compilation, optimization, ABI, analysis, validation, security
290 lines
8.9 KiB
Ruby
290 lines
8.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
#
|
|
# Synor IBC SDK Examples for Ruby
|
|
#
|
|
# Demonstrates Inter-Blockchain Communication operations:
|
|
# - Chain and channel management
|
|
# - Cross-chain token transfers
|
|
# - Packet lifecycle handling
|
|
# - Relayer operations
|
|
# - Connection monitoring
|
|
#
|
|
|
|
require 'synor/ibc'
|
|
|
|
class IbcExample
|
|
def initialize(ibc)
|
|
@ibc = ibc
|
|
end
|
|
|
|
def run_chains_example
|
|
puts '=== Chain Information ==='
|
|
|
|
# List connected chains
|
|
chains = @ibc.chains.list
|
|
puts "Connected chains: #{chains.length}"
|
|
chains.first(5).each do |chain|
|
|
puts " #{chain.chain_id}: #{chain.name} (#{chain.status})"
|
|
end
|
|
|
|
# Get specific chain info
|
|
cosmos_hub = @ibc.chains.get('cosmoshub-4')
|
|
puts "\n#{cosmos_hub.name}:"
|
|
puts " Chain ID: #{cosmos_hub.chain_id}"
|
|
puts " RPC endpoint: #{cosmos_hub.rpc_endpoint}"
|
|
puts " Block height: #{cosmos_hub.latest_height}"
|
|
puts " Active channels: #{cosmos_hub.active_channels}"
|
|
|
|
# Get chain clients
|
|
clients = @ibc.chains.get_clients('cosmoshub-4')
|
|
puts "\nIBC clients: #{clients.length}"
|
|
clients.first(3).each do |client|
|
|
puts " #{client.client_id}: #{client.chain_id} (#{client.client_type})"
|
|
end
|
|
puts
|
|
end
|
|
|
|
def run_channels_example
|
|
puts '=== Channel Management ==='
|
|
|
|
# List channels
|
|
channels = @ibc.channels.list
|
|
puts "IBC channels: #{channels.length}"
|
|
channels.first(5).each do |channel|
|
|
puts " #{channel.channel_id}: #{channel.source_chain} <-> #{channel.dest_chain} (#{channel.state})"
|
|
end
|
|
|
|
# Get channel details
|
|
channel_id = 'channel-0'
|
|
channel = @ibc.channels.get(channel_id)
|
|
puts "\nChannel #{channel_id}:"
|
|
puts " State: #{channel.state}"
|
|
puts " Port: #{channel.port_id}"
|
|
puts " Counterparty: #{channel.counterparty_channel_id}"
|
|
puts " Connection: #{channel.connection_id}"
|
|
puts " Ordering: #{channel.ordering}"
|
|
puts " Version: #{channel.version}"
|
|
|
|
# Create a new channel (4-step handshake)
|
|
puts "\nInitiating channel creation..."
|
|
init_result = @ibc.channels.init(
|
|
source_chain: 'synor-mainnet',
|
|
dest_chain: 'osmosis-1',
|
|
port_id: 'transfer',
|
|
version: 'ics20-1'
|
|
)
|
|
puts " ChanOpenInit sent: #{init_result.channel_id}"
|
|
|
|
# In production, the following steps happen through relayers:
|
|
# ChanOpenTry -> ChanOpenAck -> ChanOpenConfirm
|
|
|
|
# Get channel statistics
|
|
stats = @ibc.channels.get_stats(channel_id)
|
|
puts "\nChannel statistics:"
|
|
puts " Packets sent: #{stats.packets_sent}"
|
|
puts " Packets received: #{stats.packets_received}"
|
|
puts " Packets acknowledged: #{stats.packets_acknowledged}"
|
|
puts " Packets timed out: #{stats.packets_timed_out}"
|
|
puts
|
|
end
|
|
|
|
def run_transfer_example
|
|
puts '=== Cross-Chain Transfers ==='
|
|
|
|
# Get transfer routes
|
|
puts 'Available transfer routes:'
|
|
routes = @ibc.transfers.get_routes('ATOM', 'synor-mainnet')
|
|
routes.each do |route|
|
|
puts " #{route.source_chain} -> #{route.dest_chain}: #{route.channel_id}"
|
|
puts " Estimated time: #{route.estimated_time}"
|
|
puts " Fee: #{route.fee} #{route.fee_asset}"
|
|
end
|
|
|
|
# Initiate a transfer
|
|
puts "\nInitiating transfer..."
|
|
transfer = @ibc.transfers.send(
|
|
source_chain: 'cosmoshub-4',
|
|
dest_chain: 'synor-mainnet',
|
|
channel_id: 'channel-0',
|
|
asset: 'uatom',
|
|
amount: '1000000', # 1 ATOM
|
|
sender: 'cosmos1abc...',
|
|
receiver: 'synor1xyz...',
|
|
timeout: 1800, # 30 minutes in seconds
|
|
memo: 'IBC transfer test'
|
|
)
|
|
|
|
puts 'Transfer initiated:'
|
|
puts " Transfer ID: #{transfer.transfer_id}"
|
|
puts " Sequence: #{transfer.sequence}"
|
|
puts " Status: #{transfer.status}"
|
|
|
|
# Track transfer status
|
|
puts "\nTracking transfer..."
|
|
status = @ibc.transfers.get_status(transfer.transfer_id)
|
|
puts " Current status: #{status.status}"
|
|
puts " Source tx: #{status.source_tx_hash}"
|
|
puts " Dest tx: #{status.dest_tx_hash}" if status.dest_tx_hash
|
|
|
|
# Get transfer history
|
|
history = @ibc.transfers.get_history(limit: 5)
|
|
puts "\nRecent transfers: #{history.length}"
|
|
history.each do |tx|
|
|
puts " #{tx.transfer_id}: #{tx.amount} #{tx.asset} (#{tx.status})"
|
|
end
|
|
puts
|
|
end
|
|
|
|
def run_packet_example
|
|
puts '=== Packet Handling ==='
|
|
|
|
# Get pending packets
|
|
pending_packets = @ibc.packets.get_pending('channel-0')
|
|
puts "Pending packets: #{pending_packets.length}"
|
|
pending_packets.first(5).each do |packet|
|
|
puts " Seq #{packet.sequence}: #{packet.source_port} -> #{packet.dest_port}"
|
|
end
|
|
|
|
# Get packet details
|
|
if pending_packets.any?
|
|
packet = @ibc.packets.get('channel-0', pending_packets.first.sequence)
|
|
puts "\nPacket #{packet.sequence}:"
|
|
puts " Source: #{packet.source_port}/#{packet.source_channel}"
|
|
puts " Dest: #{packet.dest_port}/#{packet.dest_channel}"
|
|
puts " Timeout height: #{packet.timeout_height}"
|
|
puts " Timeout timestamp: #{packet.timeout_timestamp}"
|
|
data_hex = packet.data.unpack1('H*')
|
|
puts " Data: #{data_hex[0, 64]}..."
|
|
end
|
|
|
|
# Query packet commitments
|
|
commitments = @ibc.packets.get_commitments('channel-0')
|
|
puts "\nPacket commitments: #{commitments.length}"
|
|
|
|
# Query unreceived packets
|
|
unreceived = @ibc.packets.get_unreceived('channel-0', [1, 2, 3, 4, 5])
|
|
puts "Unreceived packets: #{unreceived.join(', ')}"
|
|
|
|
# Query acknowledgements
|
|
acks = @ibc.packets.get_acknowledgements('channel-0')
|
|
puts "Packet acknowledgements: #{acks.length}"
|
|
puts
|
|
end
|
|
|
|
def run_relayer_example
|
|
puts '=== Relayer Operations ==='
|
|
|
|
# Get relayer status
|
|
relayers = @ibc.relayer.list
|
|
puts "Active relayers: #{relayers.length}"
|
|
relayers.first(3).each do |relayer|
|
|
puts " #{relayer.address}: #{relayer.packets_relayed} packets (#{relayer.status})"
|
|
end
|
|
|
|
# Register as a relayer
|
|
puts "\nRegistering as relayer..."
|
|
registration = @ibc.relayer.register(
|
|
address: 'synor1relayer...',
|
|
chains: %w[synor-mainnet cosmoshub-4 osmosis-1],
|
|
commission: 0.1 # 0.1%
|
|
)
|
|
puts " Registered: #{registration.relayer_id}"
|
|
|
|
# Start relaying
|
|
puts "\nStarting packet relay..."
|
|
relay_config = {
|
|
channels: %w[channel-0 channel-1],
|
|
batch_size: 10,
|
|
poll_interval: 5
|
|
}
|
|
|
|
# In production, this would run continuously
|
|
pending_count = @ibc.relayer.get_pending_count(relay_config[:channels])
|
|
puts " Pending packets to relay: #{pending_count}"
|
|
|
|
# Relay a batch
|
|
relay_result = @ibc.relayer.relay_batch('channel-0', 5)
|
|
puts " Relayed: #{relay_result.packets_relayed}"
|
|
puts " Fees earned: #{relay_result.fees_earned}"
|
|
|
|
# Get relayer earnings
|
|
earnings = @ibc.relayer.get_earnings('synor1relayer...')
|
|
puts "\nRelayer earnings:"
|
|
puts " Total earned: #{earnings.total_earned}"
|
|
puts " Packets relayed: #{earnings.packets_relayed}"
|
|
puts " Success rate: #{format('%.1f', earnings.success_rate)}%"
|
|
puts
|
|
end
|
|
|
|
def run_monitoring_example
|
|
puts '=== Connection Monitoring ==='
|
|
|
|
# Get connection health
|
|
connections = @ibc.monitoring.get_connections
|
|
puts 'Connection health:'
|
|
connections.each do |conn|
|
|
health_icon = conn.healthy? ? '✓' : '✗'
|
|
puts " [#{health_icon}] #{conn.connection_id}: #{conn.chain_a} <-> #{conn.chain_b}"
|
|
puts " Latency: #{conn.latency}ms, Uptime: #{format('%.1f', conn.uptime)}%"
|
|
end
|
|
|
|
# Get channel metrics
|
|
metrics = @ibc.monitoring.get_channel_metrics('channel-0')
|
|
puts "\nChannel metrics:"
|
|
puts " Throughput: #{metrics.packets_per_hour}/hour"
|
|
puts " Avg latency: #{metrics.avg_latency_ms}ms"
|
|
puts " Success rate: #{format('%.1f', metrics.success_rate)}%"
|
|
puts " Volume 24h: #{metrics.volume_24h}"
|
|
|
|
# Subscribe to events (in production)
|
|
puts "\nEvent subscription example:"
|
|
puts ' Subscribing to packet events...'
|
|
# @ibc.monitoring.subscribe('channel-0') do |event|
|
|
# puts " Event: #{event.type} - #{event.data}"
|
|
# end
|
|
|
|
# Get alerts
|
|
alerts = @ibc.monitoring.get_alerts
|
|
puts "\nActive alerts: #{alerts.length}"
|
|
alerts.each do |alert|
|
|
puts " [#{alert.severity}] #{alert.message}"
|
|
puts " Channel: #{alert.channel_id}, Time: #{alert.timestamp}"
|
|
end
|
|
puts
|
|
end
|
|
end
|
|
|
|
# Main execution
|
|
if __FILE__ == $PROGRAM_NAME
|
|
# Initialize client
|
|
api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
|
|
config = Synor::Ibc::Config.new(
|
|
api_key: api_key,
|
|
endpoint: 'https://ibc.synor.io/v1',
|
|
timeout: 60,
|
|
retries: 3,
|
|
debug: false,
|
|
default_timeout: 1800 # 30 minutes
|
|
)
|
|
|
|
ibc = Synor::Ibc::Client.new(config)
|
|
example = IbcExample.new(ibc)
|
|
|
|
begin
|
|
# Check service health
|
|
healthy = ibc.health_check
|
|
puts "Service healthy: #{healthy}\n\n"
|
|
|
|
# Run examples
|
|
example.run_chains_example
|
|
example.run_channels_example
|
|
example.run_transfer_example
|
|
example.run_packet_example
|
|
example.run_relayer_example
|
|
example.run_monitoring_example
|
|
rescue StandardError => e
|
|
warn "Error: #{e.message}"
|
|
exit 1
|
|
end
|
|
end
|