Go SDK
The Omne Go SDK delivers high-performance blockchain integration for Go applications. Built for scalability, concurrency, and production-grade reliability.
Installation
Go Module Installation
# Initialize Go module (if not already done)
go mod init your-project
# Install Omne Go SDK
go get github.com/omne-foundation/omne-go-sdk
# Install specific version
go get github.com/omne-foundation/omne-go-sdk@v1.2.3
# Update dependencies
go mod tidy
Requirements
go.modgo
module your-project
go 1.19
require (
github.com/omne-foundation/omne-go-sdk v1.2.3
github.com/gorilla/websocket v1.5.0 // Auto-installed
github.com/btcsuite/btcd v0.23.0 // Auto-installed
golang.org/x/crypto v0.10.0 // Auto-installed
)
Go Version Support
The SDK requires Go 1.19 or later for optimal performance and access to the latest language features. We recommend using the latest stable Go version.
Quick Start
Basic Setup
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/omne-foundation/omne-go-sdk/client"
"github.com/omne-foundation/omne-go-sdk/types"
)
func main() {
// Initialize client
config := &client.Config{
Network: types.TestNet,
Endpoint: "https://testnet-rpc.omne.foundation",
Timeout: 30 * time.Second,
}
omneClient, err := client.NewOmneClient(config)
if err != nil {
log.Fatal("Failed to create client:", err)
}
defer omneClient.Close()
// Check connection
ctx := context.Background()
status, err := omneClient.GetNetworkStatus(ctx)
if err != nil {
log.Fatal("Failed to get network status:", err)
}
fmt.Printf("Connected to: %s\n", status.NetworkID)
fmt.Printf("Latest block: %d\n", status.LatestBlock)
}
Account Management
package main
import (
"fmt"
"log"
"github.com/omne-foundation/omne-go-sdk/account"
"github.com/omne-foundation/omne-go-sdk/wallet"
)
func main() {
// Generate new account
acc, err := account.Generate()
if err != nil {
log.Fatal("Failed to generate account:", err)
}
fmt.Printf("Address: %s\n", acc.Address())
fmt.Printf("Public key: %s\n", acc.PublicKey())
// Import from private key
privateKey := "your-private-key-hex"
importedAcc, err := account.FromPrivateKey(privateKey)
if err != nil {
log.Fatal("Failed to import account:", err)
}
// Create wallet for multiple accounts
w := wallet.New()
w.AddAccount(acc)
w.AddAccount(importedAcc)
// Get account by address
foundAcc, exists := w.GetAccount("omne1...")
if exists {
fmt.Printf("Found account: %s\n", foundAcc.Address())
}
// Save/load wallet (encrypted)
err = w.SaveToFile("wallet.json", "secure-password")
if err != nil {
log.Fatal("Failed to save wallet:", err)
}
loadedWallet, err := wallet.LoadFromFile("wallet.json", "secure-password")
if err != nil {
log.Fatal("Failed to load wallet:", err)
}
}
Core Features
🚀 High Performance
- • Zero-copy operations
- • Optimized serialization
- • Connection pooling
- • Efficient memory usage
⚡ Concurrency
- • Goroutine-safe
- • Context support
- • Channel-based streams
- • Worker pool patterns
🛡️ Type Safety
- • Strong typing
- • Compile-time checks
- • Interface definitions
- • Generic support
🔧 Production Ready
- • Comprehensive logging
- • Metrics collection
- • Health checks
- • Graceful shutdown
Working with Transactions
Simple Transfer
package main
import (
"context"
"fmt"
"log"
"github.com/omne-foundation/omne-go-sdk/client"
"github.com/omne-foundation/omne-go-sdk/types"
"github.com/omne-foundation/omne-go-sdk/transactions"
)
func sendTransfer(client *client.OmneClient, account *account.Account) error {
ctx := context.Background()
// Create transfer transaction
tx := &transactions.TransferTx{
FromAddress: account.Address(),
ToAddress: "omne1recipient-address",
Amount: "1000000", // 1 OMNE in micro-OMNE
Fee: "auto", // Auto fee estimation
Memo: "Payment for services",
}
// Sign transaction
signedTx, err := account.Sign(tx)
if err != nil {
return fmt.Errorf("failed to sign transaction: %w", err)
}
// Broadcast to network
result, err := client.Broadcast(ctx, signedTx)
if err != nil {
return fmt.Errorf("failed to broadcast transaction: %w", err)
}
fmt.Printf("Transaction hash: %s\n", result.Hash)
// Wait for confirmation
receipt, err := client.WaitForTransaction(ctx, result.Hash)
if err != nil {
return fmt.Errorf("failed to wait for transaction: %w", err)
}
fmt.Printf("Confirmed in block: %d\n", receipt.BlockNumber)
return nil
}
Concurrent Processing
package main
import (
"context"
"fmt"
"sync"
"github.com/omne-foundation/omne-go-sdk/transactions"
)
type PaymentRequest struct {
ToAddress string
Amount string
Memo string
}
func processBatchPayments(
client *client.OmneClient,
account *account.Account,
payments []PaymentRequest,
) error {
ctx := context.Background()
// Use worker pool for concurrent processing
const numWorkers = 10
paymentChan := make(chan PaymentRequest, len(payments))
resultChan := make(chan error, len(payments))
// Start workers
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for payment := range paymentChan {
tx := &transactions.TransferTx{
FromAddress: account.Address(),
ToAddress: payment.ToAddress,
Amount: payment.Amount,
Fee: "auto",
Memo: payment.Memo,
}
signedTx, err := account.Sign(tx)
if err != nil {
resultChan <- err
continue
}
result, err := client.Broadcast(ctx, signedTx)
if err != nil {
resultChan <- err
continue
}
fmt.Printf("Sent payment: %s\n", result.Hash)
resultChan <- nil
}
}()
}
// Send payments to workers
for _, payment := range payments {
paymentChan <- payment
}
close(paymentChan)
// Wait for workers to finish
go func() {
wg.Wait()
close(resultChan)
}()
// Collect results
var errors []error
for err := range resultChan {
if err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
return fmt.Errorf("some payments failed: %v", errors)
}
return nil
}
Transaction Monitoring
// Monitor transaction status
func monitorTransaction(client *client.OmneClient, txHash string) {
ctx := context.Background()
tx, err := client.GetTransaction(ctx, txHash)
if err != nil {
log.Printf("Failed to get transaction: %v", err)
return
}
fmt.Printf("Status: %s\n", tx.Status)
fmt.Printf("Block: %d\n", tx.BlockNumber)
fmt.Printf("Confirmations: %d\n", tx.Confirmations)
fmt.Printf("Gas used: %d\n", tx.GasUsed)
if tx.Status == "failed" {
fmt.Printf("Error: %s\n", tx.Error)
}
}
// Subscribe to account transactions
func subscribeToTransactions(client *client.OmneClient, address string) {
ctx := context.Background()
txChan, err := client.SubscribeTransactions(ctx, address)
if err != nil {
log.Fatal("Failed to subscribe to transactions:", err)
}
for tx := range txChan {
fmt.Printf("New transaction: %s\n", tx.Hash)
fmt.Printf("Amount: %s\n", tx.Amount)
fmt.Printf("Direction: %s\n", tx.Direction) // "in" or "out"
}
}
Smart Contracts
Contract Deployment
package main
import (
"context"
"fmt"
"github.com/omne-foundation/omne-go-sdk/contracts"
)
func deployContract(
client *client.OmneClient,
account *account.Account,
) (*contracts.Contract, error) {
ctx := context.Background()
// Load contract from files
contract, err := contracts.LoadFromFiles(
"contract.wasm", // Bytecode file
"contract.json", // ABI file
)
if err != nil {
return nil, fmt.Errorf("failed to load contract: %w", err)
}
// Set constructor arguments
constructorArgs := []interface{}{
"initial_value",
1000,
}
// Deploy contract
deployment, err := contract.Deploy(ctx, account, constructorArgs)
if err != nil {
return nil, fmt.Errorf("failed to deploy contract: %w", err)
}
fmt.Printf("Contract deployed at: %s\n", deployment.Address)
return contract, nil
}
Contract Interaction
// Connect to existing contract
func interactWithContract(client *client.OmneClient, account *account.Account) error {
ctx := context.Background()
contract, err := contracts.NewContract(
"omne1contract-address",
contractABI,
)
if err != nil {
return fmt.Errorf("failed to create contract instance: %w", err)
}
// Read contract state (free)
balance, err := contract.Call(ctx, "GetBalance", []interface{}{
"omne1user-address",
})
if err != nil {
return fmt.Errorf("failed to call contract: %w", err)
}
fmt.Printf("Balance: %v\n", balance)
// Write contract state (requires transaction)
result, err := contract.Execute(ctx, account, "Transfer", []interface{}{
"omne1recipient",
"1000000",
}, &contracts.ExecuteOptions{
Fee: "auto",
})
if err != nil {
return fmt.Errorf("failed to execute contract: %w", err)
}
fmt.Printf("Transaction hash: %s\n", result.Hash)
return nil
}
Event Listening
// Listen to contract events
func listenToEvents(contract *contracts.Contract, account *account.Account) {
ctx := context.Background()
// Listen to all Transfer events
eventChan, err := contract.SubscribeEvents(ctx, "Transfer", nil)
if err != nil {
log.Fatal("Failed to subscribe to events:", err)
}
for event := range eventChan {
fmt.Printf("Transfer event:\n")
fmt.Printf("From: %s\n", event.Data["from"])
fmt.Printf("To: %s\n", event.Data["to"])
fmt.Printf("Amount: %s\n", event.Data["amount"])
}
}
// Listen with filters
func listenToMyTransfers(contract *contracts.Contract, account *account.Account) {
ctx := context.Background()
// Filter for transfers to our account
filters := map[string]interface{}{
"to": account.Address(),
}
eventChan, err := contract.SubscribeEvents(ctx, "Transfer", filters)
if err != nil {
log.Fatal("Failed to subscribe to filtered events:", err)
}
for event := range eventChan {
fmt.Printf("Received transfer: %s OMNE\n", event.Data["amount"])
}
}
Context & Cancellation
Timeout Handling
package main
import (
"context"
"fmt"
"time"
)
func operationWithTimeout(client *client.OmneClient) error {
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Operation will be cancelled after 10 seconds
status, err := client.GetNetworkStatus(ctx)
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
return fmt.Errorf("operation timed out")
}
return fmt.Errorf("operation failed: %w", err)
}
fmt.Printf("Network status: %v\n", status)
return nil
}
func cancellableOperation(client *client.OmneClient) error {
ctx, cancel := context.WithCancel(context.Background())
// Cancel operation after 5 seconds
go func() {
time.Sleep(5 * time.Second)
cancel()
}()
// This operation can be cancelled
balance, err := client.GetBalance(ctx, "omne1address")
if err != nil {
if ctx.Err() == context.Canceled {
return fmt.Errorf("operation was cancelled")
}
return fmt.Errorf("operation failed: %w", err)
}
fmt.Printf("Balance: %s\n", balance.Amount)
return nil
}
Graceful Shutdown
package main
import (
"context"
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
func gracefulService(client *client.OmneClient) {
// Create context for graceful shutdown
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Handle shutdown signals
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
var wg sync.WaitGroup
// Start monitoring goroutine
wg.Add(1)
go func() {
defer wg.Done()
txChan, err := client.SubscribeNewTransactions(ctx)
if err != nil {
fmt.Printf("Failed to subscribe to transactions: %v\n", err)
return
}
for {
select {
case tx := <-txChan:
fmt.Printf("New transaction: %s\n", tx.Hash)
case <-ctx.Done():
fmt.Println("Stopping transaction monitoring...")
return
}
}
}()
// Wait for shutdown signal
<-sigChan
fmt.Println("Received shutdown signal...")
// Cancel context to stop all operations
cancel()
// Wait for all goroutines to finish with timeout
done := make(chan struct{})
go func() {
wg.Wait()
close(done)
}()
select {
case <-done:
fmt.Println("All goroutines stopped gracefully")
case <-time.After(10 * time.Second):
fmt.Println("Timeout waiting for goroutines to stop")
}
// Close client connection
client.Close()
fmt.Println("Shutdown complete")
}
Error Handling
Error Types
package main
import (
"errors"
"fmt"
"github.com/omne-foundation/omne-go-sdk/errors"
)
func handleErrors(client *client.OmneClient, account *account.Account) {
ctx := context.Background()
_, err := client.Transfer(ctx, &transactions.TransferTx{
FromAddress: account.Address(),
ToAddress: "invalid-address",
Amount: "1000000",
})
if err != nil {
// Check specific error types
var validationErr *errors.ValidationError
var networkErr *errors.NetworkError
var txErr *errors.TransactionError
switch {
case errors.As(err, &validationErr):
fmt.Printf("Validation failed: %s\n", validationErr.Message)
fmt.Printf("Field: %s\n", validationErr.Field)
fmt.Printf("Value: %v\n", validationErr.Value)
case errors.As(err, &networkErr):
fmt.Printf("Network error: %s\n", networkErr.Message)
fmt.Printf("Status code: %d\n", networkErr.StatusCode)
fmt.Printf("Retryable: %t\n", networkErr.Retryable)
case errors.As(err, &txErr):
fmt.Printf("Transaction failed: %s\n", txErr.Message)
fmt.Printf("Code: %d\n", txErr.Code)
fmt.Printf("Gas used: %d\n", txErr.GasUsed)
default:
fmt.Printf("Unknown error: %v\n", err)
}
}
}
Retry Logic
package main
import (
"context"
"fmt"
"time"
"github.com/omne-foundation/omne-go-sdk/errors"
)
func retryWithBackoff(
ctx context.Context,
operation func() error,
maxRetries int,
baseDelay time.Duration,
) error {
var lastErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
if err := operation(); err != nil {
lastErr = err
// Check if error is retryable
var networkErr *errors.NetworkError
if errors.As(err, &networkErr) && networkErr.Retryable {
if attempt < maxRetries {
delay := baseDelay * time.Duration(1<<attempt) // Exponential backoff
select {
case <-time.After(delay):
continue
case <-ctx.Done():
return ctx.Err()
}
}
}
return err
}
return nil
}
return lastErr
}
// Usage example
func reliableTransfer(client *client.OmneClient, account *account.Account) error {
return retryWithBackoff(
context.Background(),
func() error {
_, err := client.Transfer(context.Background(), &transactions.TransferTx{
FromAddress: account.Address(),
ToAddress: "omne1recipient",
Amount: "1000000",
})
return err
},
3, // max retries
1*time.Second, // base delay
)
}
Testing
Mock Client
package main
import (
"context"
"testing"
"github.com/omne-foundation/omne-go-sdk/testing"
"github.com/omne-foundation/omne-go-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTransfer(t *testing.T) {
// Create mock client
mockClient := testing.NewMockOmneClient()
// Set up mock responses
mockClient.MockBalance("omne1test-address", &types.Balance{
Amount: "1000000",
Denom: "uomne",
})
mockClient.MockTransactionResult(&types.TransactionResult{
Hash: "0x123...",
Status: "success",
})
// Test transfer
account := testing.GenerateMockAccount()
result, err := mockClient.Transfer(context.Background(), &transactions.TransferTx{
FromAddress: account.Address(),
ToAddress: "omne1recipient",
Amount: "500000",
})
require.NoError(t, err)
assert.Equal(t, "0x123...", result.Hash)
assert.Equal(t, "success", result.Status)
}
func TestBalanceCheck(t *testing.T) {
mockClient := testing.NewMockOmneClient()
expectedBalance := &types.Balance{
Amount: "1000000",
Denom: "uomne",
}
mockClient.MockBalance("omne1test-address", expectedBalance)
balance, err := mockClient.GetBalance(context.Background(), "omne1test-address")
require.NoError(t, err)
assert.Equal(t, expectedBalance.Amount, balance.Amount)
assert.Equal(t, expectedBalance.Denom, balance.Denom)
}
Integration Tests
package main
import (
"context"
"os"
"testing"
"time"
"github.com/omne-foundation/omne-go-sdk/client"
"github.com/omne-foundation/omne-go-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestIntegration(t *testing.T) {
// Skip integration tests in short mode
if testing.Short() {
t.Skip("Skipping integration test in short mode")
}
// Set up test client
config := &client.Config{
Network: types.TestNet,
Endpoint: os.Getenv("OMNE_TESTNET_ENDPOINT"),
Timeout: 30 * time.Second,
}
omneClient, err := client.NewOmneClient(config)
require.NoError(t, err)
defer omneClient.Close()
ctx := context.Background()
t.Run("NetworkConnection", func(t *testing.T) {
status, err := omneClient.GetNetworkStatus(ctx)
require.NoError(t, err)
assert.Contains(t, status.NetworkID, "omne-testnet")
assert.Greater(t, status.LatestBlock, uint64(0))
})
t.Run("AccountBalance", func(t *testing.T) {
testAddress := os.Getenv("OMNE_TEST_ADDRESS")
if testAddress == "" {
t.Skip("OMNE_TEST_ADDRESS not set")
}
balance, err := omneClient.GetBalance(ctx, testAddress)
require.NoError(t, err)
assert.Equal(t, "uomne", balance.Denom)
assert.GreaterOrEqual(t, balance.Amount, "0")
})
t.Run("SmallTransfer", func(t *testing.T) {
testPrivateKey := os.Getenv("OMNE_TEST_PRIVATE_KEY")
if testPrivateKey == "" {
t.Skip("OMNE_TEST_PRIVATE_KEY not set")
}
account, err := account.FromPrivateKey(testPrivateKey)
require.NoError(t, err)
// Small test transfer
result, err := omneClient.Transfer(ctx, &transactions.TransferTx{
FromAddress: account.Address(),
ToAddress: "omne1testrecipient",
Amount: "1000", // 0.001 OMNE
})
require.NoError(t, err)
assert.NotEmpty(t, result.Hash)
receipt, err := omneClient.WaitForTransaction(ctx, result.Hash)
require.NoError(t, err)
assert.Equal(t, "success", receipt.Status)
})
}
Advanced Configuration
Client Configuration
package main
import (
"time"
"github.com/omne-foundation/omne-go-sdk/client"
"github.com/omne-foundation/omne-go-sdk/types"
)
func main() {
config := &client.Config{
// Network settings
Network: types.MainNet,
Endpoint: "https://rpc.omne.foundation",
// Request settings
Timeout: 30 * time.Second,
MaxRetries: 3,
RetryDelay: 1 * time.Second,
// WebSocket settings
WSEndpoint: "wss://ws.omne.foundation",
WSReconnect: true,
WSReconnectDelay: 5 * time.Second,
// Fee settings
DefaultFee: "1000",
FeeMultiplier: 1.2,
// Gas settings
DefaultGas: 200000,
GasMultiplier: 1.5,
// Connection pool settings
MaxIdleConns: 10,
MaxConnsPerHost: 100,
IdleConnTimeout: 90 * time.Second,
// TLS settings
InsecureSkipVerify: false,
// Custom HTTP headers
Headers: map[string]string{
"User-Agent": "MyApp/1.0.0",
"X-Custom-Header": "value",
},
// Logging
LogLevel: "info",
Logger: customLogger,
}
client, err := client.NewOmneClient(config)
if err != nil {
log.Fatal("Failed to create client:", err)
}
defer client.Close()
}
Custom Network
// Define custom network
customNetwork := &types.Network{
NetworkID: "omne-devnet-1",
ChainID: "omne-devnet",
RPCEndpoint: "http://localhost:26657",
WSEndpoint: "ws://localhost:26657/websocket",
AddressPrefix: "omne",
CoinType: 118,
GasPrice: "0.001",
FeeDenom: "uomne",
}
config := &client.Config{
Network: customNetwork,
Endpoint: customNetwork.RPCEndpoint,
}
client, err := client.NewOmneClient(config)