- 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.
506 lines
14 KiB
Go
506 lines
14 KiB
Go
// Package main demonstrates the Synor DEX SDK for Go
|
|
//
|
|
// This example covers decentralized exchange operations:
|
|
// - Spot trading (limit/market orders)
|
|
// - Perpetual futures trading
|
|
// - Liquidity provision (AMM pools)
|
|
// - Order book management
|
|
// - Portfolio tracking
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/synor/sdk-go/dex"
|
|
)
|
|
|
|
func main() {
|
|
// Initialize client
|
|
config := dex.Config{
|
|
APIKey: getEnv("SYNOR_API_KEY", "your-api-key"),
|
|
Endpoint: "https://dex.synor.io/v1",
|
|
Timeout: 30 * time.Second,
|
|
Retries: 3,
|
|
Debug: false,
|
|
DefaultMarket: "SYN-USDC",
|
|
}
|
|
|
|
client, err := dex.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
|
|
marketsExample(ctx, client)
|
|
spotTradingExample(ctx, client)
|
|
perpsTradingExample(ctx, client)
|
|
liquidityExample(ctx, client)
|
|
orderbookExample(ctx, client)
|
|
portfolioExample(ctx, client)
|
|
}
|
|
|
|
func marketsExample(ctx context.Context, client *dex.Client) {
|
|
fmt.Println("=== Markets ===")
|
|
|
|
// Get all markets
|
|
markets, err := client.Markets.List(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to list markets: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf("Available markets: %d\n", len(markets))
|
|
|
|
for _, market := range markets[:min(5, len(markets))] {
|
|
fmt.Printf("\n %s:\n", market.Symbol)
|
|
fmt.Printf(" Base: %s, Quote: %s\n", market.BaseAsset, market.QuoteAsset)
|
|
fmt.Printf(" Price: %s\n", market.LastPrice)
|
|
fmt.Printf(" 24h Volume: %s\n", market.Volume24h)
|
|
fmt.Printf(" 24h Change: %s%%\n", market.Change24h)
|
|
fmt.Printf(" Status: %s\n", market.Status)
|
|
}
|
|
|
|
// Get specific market
|
|
market, err := client.Markets.Get(ctx, "SYN-USDC")
|
|
if err != nil {
|
|
log.Printf("Failed to get market: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf("\nSYN-USDC details:\n")
|
|
fmt.Printf(" Min order size: %s\n", market.MinOrderSize)
|
|
fmt.Printf(" Tick size: %s\n", market.TickSize)
|
|
fmt.Printf(" Maker fee: %s%%\n", market.MakerFee)
|
|
fmt.Printf(" Taker fee: %s%%\n", market.TakerFee)
|
|
|
|
// Get market statistics
|
|
stats, err := client.Markets.GetStats(ctx, "SYN-USDC")
|
|
if err != nil {
|
|
log.Printf("Failed to get market stats: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf("\nMarket statistics:\n")
|
|
fmt.Printf(" High 24h: %s\n", stats.High24h)
|
|
fmt.Printf(" Low 24h: %s\n", stats.Low24h)
|
|
fmt.Printf(" Open interest: %s\n", stats.OpenInterest)
|
|
fmt.Printf(" Funding rate: %s%%\n", stats.FundingRate)
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func spotTradingExample(ctx context.Context, client *dex.Client) {
|
|
fmt.Println("=== Spot Trading ===")
|
|
|
|
// Place a limit order
|
|
fmt.Println("Placing limit buy order...")
|
|
limitOrder, err := client.Spot.PlaceOrder(ctx, &dex.OrderRequest{
|
|
Market: "SYN-USDC",
|
|
Side: dex.SideBuy,
|
|
OrderType: dex.OrderTypeLimit,
|
|
Price: "1.50",
|
|
Quantity: "100",
|
|
TimeInForce: dex.TimeInForceGTC,
|
|
})
|
|
if err != nil {
|
|
log.Printf("Failed to place limit order: %v", err)
|
|
} else {
|
|
fmt.Printf("Limit order placed:\n")
|
|
fmt.Printf(" Order ID: %s\n", limitOrder.OrderID)
|
|
fmt.Printf(" Status: %s\n", limitOrder.Status)
|
|
fmt.Printf(" Price: %s\n", limitOrder.Price)
|
|
fmt.Printf(" Quantity: %s\n", limitOrder.Quantity)
|
|
}
|
|
|
|
// Place a market order
|
|
fmt.Println("\nPlacing market sell order...")
|
|
marketOrder, err := client.Spot.PlaceOrder(ctx, &dex.OrderRequest{
|
|
Market: "SYN-USDC",
|
|
Side: dex.SideSell,
|
|
OrderType: dex.OrderTypeMarket,
|
|
Quantity: "50",
|
|
})
|
|
if err != nil {
|
|
log.Printf("Failed to place market order: %v", err)
|
|
} else {
|
|
fmt.Printf("Market order executed:\n")
|
|
fmt.Printf(" Order ID: %s\n", marketOrder.OrderID)
|
|
fmt.Printf(" Status: %s\n", marketOrder.Status)
|
|
fmt.Printf(" Filled: %s\n", marketOrder.FilledQuantity)
|
|
fmt.Printf(" Avg price: %s\n", marketOrder.AveragePrice)
|
|
}
|
|
|
|
// Get order status
|
|
if limitOrder != nil {
|
|
status, err := client.Spot.GetOrder(ctx, limitOrder.OrderID)
|
|
if err != nil {
|
|
log.Printf("Failed to get order status: %v", err)
|
|
} else {
|
|
fmt.Printf("\nOrder status:\n")
|
|
fmt.Printf(" Status: %s\n", status.Status)
|
|
fmt.Printf(" Filled: %s / %s\n", status.FilledQuantity, status.Quantity)
|
|
fmt.Printf(" Remaining: %s\n", status.RemainingQuantity)
|
|
}
|
|
|
|
// Cancel order
|
|
fmt.Println("\nCancelling order...")
|
|
err = client.Spot.CancelOrder(ctx, limitOrder.OrderID)
|
|
if err != nil {
|
|
log.Printf("Failed to cancel order: %v", err)
|
|
} else {
|
|
fmt.Println("Order cancelled successfully")
|
|
}
|
|
}
|
|
|
|
// Get open orders
|
|
openOrders, err := client.Spot.GetOpenOrders(ctx, "SYN-USDC")
|
|
if err != nil {
|
|
log.Printf("Failed to get open orders: %v", err)
|
|
} else {
|
|
fmt.Printf("\nOpen orders: %d\n", len(openOrders))
|
|
}
|
|
|
|
// Get trade history
|
|
trades, err := client.Spot.GetTradeHistory(ctx, "SYN-USDC", 10)
|
|
if err != nil {
|
|
log.Printf("Failed to get trade history: %v", err)
|
|
} else {
|
|
fmt.Printf("\nRecent trades: %d\n", len(trades))
|
|
for _, trade := range trades[:min(3, len(trades))] {
|
|
fmt.Printf(" %s %s @ %s (%s)\n", trade.Side, trade.Quantity, trade.Price, trade.Timestamp.Format(time.RFC3339))
|
|
}
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func perpsTradingExample(ctx context.Context, client *dex.Client) {
|
|
fmt.Println("=== Perpetual Futures Trading ===")
|
|
|
|
// Get available perps markets
|
|
perpsMarkets, err := client.Perps.ListMarkets(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to list perps markets: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf("Available perps markets: %d\n", len(perpsMarkets))
|
|
|
|
for _, market := range perpsMarkets[:min(3, len(perpsMarkets))] {
|
|
fmt.Printf(" %s: %s (funding: %s%%)\n", market.Symbol, market.MarkPrice, market.FundingRate)
|
|
}
|
|
|
|
// Open a long position
|
|
fmt.Println("\nOpening long position...")
|
|
position, err := client.Perps.OpenPosition(ctx, &dex.PerpsOrderRequest{
|
|
Market: "SYN-USDC-PERP",
|
|
Side: dex.SideBuy,
|
|
OrderType: dex.OrderTypeLimit,
|
|
Price: "1.50",
|
|
Size: "1000",
|
|
Leverage: 10,
|
|
ReduceOnly: false,
|
|
})
|
|
if err != nil {
|
|
log.Printf("Failed to open position: %v", err)
|
|
} else {
|
|
fmt.Printf("Position opened:\n")
|
|
fmt.Printf(" Position ID: %s\n", position.PositionID)
|
|
fmt.Printf(" Size: %s\n", position.Size)
|
|
fmt.Printf(" Entry price: %s\n", position.EntryPrice)
|
|
fmt.Printf(" Leverage: %dx\n", position.Leverage)
|
|
fmt.Printf(" Liquidation price: %s\n", position.LiquidationPrice)
|
|
}
|
|
|
|
// Get position details
|
|
if position != nil {
|
|
details, err := client.Perps.GetPosition(ctx, position.PositionID)
|
|
if err != nil {
|
|
log.Printf("Failed to get position: %v", err)
|
|
} else {
|
|
fmt.Printf("\nPosition details:\n")
|
|
fmt.Printf(" Unrealized PnL: %s\n", details.UnrealizedPnL)
|
|
fmt.Printf(" Margin: %s\n", details.Margin)
|
|
fmt.Printf(" Margin ratio: %s%%\n", details.MarginRatio)
|
|
}
|
|
}
|
|
|
|
// Set stop loss and take profit
|
|
if position != nil {
|
|
fmt.Println("\nSetting stop loss and take profit...")
|
|
err = client.Perps.SetStopLoss(ctx, position.PositionID, "1.40")
|
|
if err != nil {
|
|
log.Printf("Failed to set stop loss: %v", err)
|
|
} else {
|
|
fmt.Println("Stop loss set at 1.40")
|
|
}
|
|
|
|
err = client.Perps.SetTakeProfit(ctx, position.PositionID, "1.80")
|
|
if err != nil {
|
|
log.Printf("Failed to set take profit: %v", err)
|
|
} else {
|
|
fmt.Println("Take profit set at 1.80")
|
|
}
|
|
|
|
// Close position
|
|
fmt.Println("\nClosing position...")
|
|
closeResult, err := client.Perps.ClosePosition(ctx, position.PositionID)
|
|
if err != nil {
|
|
log.Printf("Failed to close position: %v", err)
|
|
} else {
|
|
fmt.Printf("Position closed:\n")
|
|
fmt.Printf(" Realized PnL: %s\n", closeResult.RealizedPnL)
|
|
fmt.Printf(" Close price: %s\n", closeResult.ClosePrice)
|
|
}
|
|
}
|
|
|
|
// Get all positions
|
|
positions, err := client.Perps.GetPositions(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to get positions: %v", err)
|
|
} else {
|
|
fmt.Printf("\nOpen positions: %d\n", len(positions))
|
|
}
|
|
|
|
// Get funding history
|
|
funding, err := client.Perps.GetFundingHistory(ctx, "SYN-USDC-PERP", 10)
|
|
if err != nil {
|
|
log.Printf("Failed to get funding history: %v", err)
|
|
} else {
|
|
fmt.Printf("Funding payments: %d\n", len(funding))
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func liquidityExample(ctx context.Context, client *dex.Client) {
|
|
fmt.Println("=== Liquidity Provision ===")
|
|
|
|
// Get available pools
|
|
pools, err := client.Liquidity.ListPools(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to list pools: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf("Available pools: %d\n", len(pools))
|
|
|
|
for _, pool := range pools[:min(3, len(pools))] {
|
|
fmt.Printf("\n %s:\n", pool.Name)
|
|
fmt.Printf(" TVL: $%s\n", pool.TVL)
|
|
fmt.Printf(" APR: %s%%\n", pool.APR)
|
|
fmt.Printf(" Volume 24h: $%s\n", pool.Volume24h)
|
|
fmt.Printf(" Fee tier: %s%%\n", pool.FeeTier)
|
|
}
|
|
|
|
// Get pool details
|
|
pool, err := client.Liquidity.GetPool(ctx, "SYN-USDC")
|
|
if err != nil {
|
|
log.Printf("Failed to get pool: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf("\nSYN-USDC pool details:\n")
|
|
fmt.Printf(" Token0: %s (%s)\n", pool.Token0.Symbol, pool.Token0Reserve)
|
|
fmt.Printf(" Token1: %s (%s)\n", pool.Token1.Symbol, pool.Token1Reserve)
|
|
fmt.Printf(" Price: %s\n", pool.Price)
|
|
fmt.Printf(" Total LP tokens: %s\n", pool.TotalLPTokens)
|
|
|
|
// Add liquidity
|
|
fmt.Println("\nAdding liquidity...")
|
|
addResult, err := client.Liquidity.AddLiquidity(ctx, &dex.AddLiquidityRequest{
|
|
Pool: "SYN-USDC",
|
|
Amount0: "100",
|
|
Amount1: "150",
|
|
SlippageBps: 50, // 0.5%
|
|
})
|
|
if err != nil {
|
|
log.Printf("Failed to add liquidity: %v", err)
|
|
} else {
|
|
fmt.Printf("Liquidity added:\n")
|
|
fmt.Printf(" LP tokens received: %s\n", addResult.LPTokens)
|
|
fmt.Printf(" Position ID: %s\n", addResult.PositionID)
|
|
fmt.Printf(" Share of pool: %s%%\n", addResult.ShareOfPool)
|
|
}
|
|
|
|
// Get LP positions
|
|
lpPositions, err := client.Liquidity.GetPositions(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to get LP positions: %v", err)
|
|
} else {
|
|
fmt.Printf("\nLP positions: %d\n", len(lpPositions))
|
|
for _, pos := range lpPositions {
|
|
fmt.Printf(" %s: %s LP tokens (value: $%s)\n", pos.Pool, pos.LPTokens, pos.Value)
|
|
}
|
|
}
|
|
|
|
// Claim fees
|
|
if addResult != nil {
|
|
fmt.Println("\nClaiming fees...")
|
|
fees, err := client.Liquidity.ClaimFees(ctx, addResult.PositionID)
|
|
if err != nil {
|
|
log.Printf("Failed to claim fees: %v", err)
|
|
} else {
|
|
fmt.Printf("Fees claimed:\n")
|
|
fmt.Printf(" Token0: %s\n", fees.Amount0)
|
|
fmt.Printf(" Token1: %s\n", fees.Amount1)
|
|
}
|
|
|
|
// Remove liquidity
|
|
fmt.Println("\nRemoving liquidity...")
|
|
removeResult, err := client.Liquidity.RemoveLiquidity(ctx, &dex.RemoveLiquidityRequest{
|
|
PositionID: addResult.PositionID,
|
|
LPTokens: addResult.LPTokens,
|
|
SlippageBps: 50,
|
|
})
|
|
if err != nil {
|
|
log.Printf("Failed to remove liquidity: %v", err)
|
|
} else {
|
|
fmt.Printf("Liquidity removed:\n")
|
|
fmt.Printf(" Token0 received: %s\n", removeResult.Amount0)
|
|
fmt.Printf(" Token1 received: %s\n", removeResult.Amount1)
|
|
}
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func orderbookExample(ctx context.Context, client *dex.Client) {
|
|
fmt.Println("=== Order Book ===")
|
|
|
|
// Get order book snapshot
|
|
orderbook, err := client.Orderbook.GetSnapshot(ctx, "SYN-USDC", 10)
|
|
if err != nil {
|
|
log.Printf("Failed to get orderbook: %v", err)
|
|
return
|
|
}
|
|
|
|
fmt.Println("Order book for SYN-USDC:")
|
|
fmt.Println("\nAsks (sells):")
|
|
for _, ask := range orderbook.Asks[:min(5, len(orderbook.Asks))] {
|
|
fmt.Printf(" %s @ %s\n", ask.Quantity, ask.Price)
|
|
}
|
|
|
|
fmt.Println("\nBids (buys):")
|
|
for _, bid := range orderbook.Bids[:min(5, len(orderbook.Bids))] {
|
|
fmt.Printf(" %s @ %s\n", bid.Quantity, bid.Price)
|
|
}
|
|
|
|
fmt.Printf("\nSpread: %s (%s%%)\n", orderbook.Spread, orderbook.SpreadPercent)
|
|
fmt.Printf("Mid price: %s\n", orderbook.MidPrice)
|
|
|
|
// Get recent trades
|
|
recentTrades, err := client.Orderbook.GetRecentTrades(ctx, "SYN-USDC", 10)
|
|
if err != nil {
|
|
log.Printf("Failed to get recent trades: %v", err)
|
|
} else {
|
|
fmt.Println("\nRecent trades:")
|
|
for _, trade := range recentTrades[:min(5, len(recentTrades))] {
|
|
fmt.Printf(" %s %s @ %s\n", trade.Side, trade.Quantity, trade.Price)
|
|
}
|
|
}
|
|
|
|
// Subscribe to orderbook updates (simulated)
|
|
fmt.Println("\nSubscribing to orderbook updates...")
|
|
updates := client.Orderbook.Subscribe(ctx, "SYN-USDC")
|
|
|
|
// Process a few updates (in real usage, this would be a goroutine)
|
|
go func() {
|
|
for i := 0; i < 3; i++ {
|
|
select {
|
|
case update := <-updates:
|
|
fmt.Printf(" Update: %s %s @ %s\n", update.Side, update.Quantity, update.Price)
|
|
case <-time.After(5 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
time.Sleep(2 * time.Second) // Wait for some updates
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func portfolioExample(ctx context.Context, client *dex.Client) {
|
|
fmt.Println("=== Portfolio ===")
|
|
|
|
// Get portfolio overview
|
|
portfolio, err := client.Portfolio.GetOverview(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to get portfolio: %v", err)
|
|
return
|
|
}
|
|
|
|
fmt.Println("Portfolio overview:")
|
|
fmt.Printf(" Total value: $%s\n", portfolio.TotalValue)
|
|
fmt.Printf(" Available balance: $%s\n", portfolio.AvailableBalance)
|
|
fmt.Printf(" In orders: $%s\n", portfolio.InOrders)
|
|
fmt.Printf(" In positions: $%s\n", portfolio.InPositions)
|
|
fmt.Printf(" Unrealized PnL: $%s\n", portfolio.UnrealizedPnL)
|
|
|
|
// Get balances
|
|
balances, err := client.Portfolio.GetBalances(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to get balances: %v", err)
|
|
} else {
|
|
fmt.Println("\nBalances:")
|
|
for _, balance := range balances {
|
|
fmt.Printf(" %s: %s (available: %s, in orders: %s)\n",
|
|
balance.Asset, balance.Total, balance.Available, balance.InOrders)
|
|
}
|
|
}
|
|
|
|
// Get PnL history
|
|
pnlHistory, err := client.Portfolio.GetPnLHistory(ctx, 30) // Last 30 days
|
|
if err != nil {
|
|
log.Printf("Failed to get PnL history: %v", err)
|
|
} else {
|
|
fmt.Printf("\nPnL history (last %d days):\n", len(pnlHistory))
|
|
if len(pnlHistory) > 0 {
|
|
totalPnL := "0"
|
|
for _, day := range pnlHistory {
|
|
totalPnL = day.CumulativePnL
|
|
}
|
|
fmt.Printf(" Total PnL: $%s\n", totalPnL)
|
|
}
|
|
}
|
|
|
|
// Get trade statistics
|
|
stats, err := client.Portfolio.GetStats(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to get trade stats: %v", err)
|
|
} else {
|
|
fmt.Println("\nTrade statistics:")
|
|
fmt.Printf(" Total trades: %d\n", stats.TotalTrades)
|
|
fmt.Printf(" Win rate: %s%%\n", stats.WinRate)
|
|
fmt.Printf(" Avg profit: $%s\n", stats.AvgProfit)
|
|
fmt.Printf(" Avg loss: $%s\n", stats.AvgLoss)
|
|
fmt.Printf(" Best trade: $%s\n", stats.BestTrade)
|
|
fmt.Printf(" Worst trade: $%s\n", stats.WorstTrade)
|
|
}
|
|
|
|
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
|
|
}
|