mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
522 lines
12 KiB
Plaintext
522 lines
12 KiB
Plaintext
---
|
|
title: Getting Started with Golang
|
|
description: A quick start guide for building applications with Sonr using the Go Client SDK
|
|
sidebarTitle: Golang Quickstart
|
|
icon: "golang"
|
|
---
|
|
|
|
This guide provides a walkthrough for setting up a Go project to interact with the Sonr network using the official Go Client SDK. You will learn how to configure the client, manage keys, query the blockchain, send transactions, and use advanced features like WebAuthn gasless transactions.
|
|
|
|
## Prerequisites
|
|
|
|
- A local Sonr network running. See the [Validator Setup Guide](/quickstart/validators) for instructions
|
|
- Go version 1.24 or higher
|
|
|
|
## 1. Project Setup
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Initialize a Go Module
|
|
|
|
Create a new directory for your project and initialize a Go module:
|
|
|
|
```bash
|
|
mkdir sonr-go-quickstart
|
|
cd sonr-go-quickstart
|
|
go mod init github.com/your-username/sonr-go-quickstart
|
|
```
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Add the Sonr Client SDK Dependency
|
|
|
|
Add the Sonr Client SDK to your project's dependencies:
|
|
|
|
```bash
|
|
go get github.com/sonr-io/sonr/client
|
|
```
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## 2. Client Configuration and Setup
|
|
|
|
Let's set up the Sonr client with proper configuration and key management.
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Create the Main File
|
|
|
|
Create a new file named `main.go`.
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Initialize the Client
|
|
|
|
Add the following code to `main.go` to initialize the Sonr client:
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
|
|
"github.com/sonr-io/sonr/client/config"
|
|
"github.com/sonr-io/sonr/client/keys"
|
|
"github.com/sonr-io/sonr/client/sonr"
|
|
"github.com/sonr-io/sonr/client/tx"
|
|
)
|
|
|
|
func main() {
|
|
// Use local network configuration
|
|
cfg := config.LocalNetwork()
|
|
|
|
// Establish gRPC connection
|
|
conn, err := grpc.Dial(
|
|
cfg.GRPC,
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
)
|
|
if err != nil {
|
|
log.Fatal("Failed to connect:", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
// Create the Sonr client
|
|
client, err := sonr.NewClient(&cfg, conn)
|
|
if err != nil {
|
|
log.Fatal("Failed to create client:", err)
|
|
}
|
|
|
|
fmt.Println("Sonr client initialized successfully!")
|
|
fmt.Printf("Connected to: %s\n", cfg.ChainID)
|
|
}
|
|
```
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Create a Keyring Manager
|
|
|
|
Add key management to handle wallet operations:
|
|
|
|
```go
|
|
// Initialize keyring manager (using test backend for development)
|
|
keyringManager, err := keys.NewKeyringManager(
|
|
"test", // backend: test, file, os
|
|
".sonr-keys", // directory for keys
|
|
cfg.ChainID, // chain ID
|
|
)
|
|
if err != nil {
|
|
log.Fatal("Failed to create keyring:", err)
|
|
}
|
|
|
|
// Create a new wallet
|
|
walletIdentity, mnemonic, err := keyringManager.CreateWallet(
|
|
context.Background(),
|
|
"my-wallet", // wallet name
|
|
"", // passphrase (empty for test backend)
|
|
)
|
|
if err != nil {
|
|
log.Fatal("Failed to create wallet:", err)
|
|
}
|
|
|
|
fmt.Printf("Wallet created!\n")
|
|
fmt.Printf("Address: %s\n", walletIdentity.Address)
|
|
fmt.Printf("DID: %s\n", walletIdentity.DID)
|
|
fmt.Printf("Mnemonic: %s\n", mnemonic)
|
|
```
|
|
|
|
<Note type="warning">
|
|
**Important**: In production, use secure keyring backends like "os" or "file" with proper passphrase protection. Never expose mnemonics in your code.
|
|
</Note>
|
|
</Step>
|
|
</Steps>
|
|
|
|
## 3. Querying the Blockchain
|
|
|
|
Now, let's query the blockchain using the unified query client.
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Create a Query Client
|
|
|
|
Add the query client to your application:
|
|
|
|
```go
|
|
import (
|
|
"github.com/sonr-io/sonr/client/query"
|
|
)
|
|
|
|
// Create query client
|
|
queryClient, err := query.NewQueryClient(conn, &cfg)
|
|
if err != nil {
|
|
log.Fatal("Failed to create query client:", err)
|
|
}
|
|
```
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Query Account Balance
|
|
|
|
Query an account's balance:
|
|
|
|
```go
|
|
// Query account balance
|
|
address := walletIdentity.Address // or any other address
|
|
balance, err := queryClient.Balance(
|
|
context.Background(),
|
|
address,
|
|
cfg.StakingDenom, // "usnr"
|
|
)
|
|
if err != nil {
|
|
log.Printf("Failed to query balance: %v", err)
|
|
} else {
|
|
fmt.Printf("Balance for %s: %s %s\n",
|
|
address,
|
|
balance.Balance.Amount.String(),
|
|
balance.Balance.Denom,
|
|
)
|
|
}
|
|
|
|
// Query all balances for an account
|
|
allBalances, err := queryClient.AllBalances(
|
|
context.Background(),
|
|
address,
|
|
nil, // pagination
|
|
)
|
|
if err != nil {
|
|
log.Printf("Failed to query all balances: %v", err)
|
|
} else {
|
|
fmt.Printf("All balances: %v\n", allBalances.Balances)
|
|
}
|
|
```
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Query Module-Specific Data
|
|
|
|
Query DID documents and other module data:
|
|
|
|
```go
|
|
import (
|
|
"github.com/sonr-io/sonr/client/modules/did"
|
|
)
|
|
|
|
// Create DID module client
|
|
didClient := did.NewDIDClient()
|
|
|
|
// Query DID document (if exists)
|
|
didID := "did:sonr:example123"
|
|
didDoc, err := queryClient.GetDID(context.Background(), didID)
|
|
if err != nil {
|
|
log.Printf("DID not found: %v", err)
|
|
} else {
|
|
fmt.Printf("DID Document: %+v\n", didDoc)
|
|
}
|
|
|
|
// List all DIDs with pagination
|
|
didList, err := queryClient.ListDIDs(
|
|
context.Background(),
|
|
&query.ListOptions{
|
|
Limit: 10,
|
|
Offset: 0,
|
|
},
|
|
)
|
|
if err != nil {
|
|
log.Printf("Failed to list DIDs: %v", err)
|
|
} else {
|
|
fmt.Printf("Found %d DIDs\n", len(didList.DIDs))
|
|
}
|
|
```
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## 4. Building and Broadcasting Transactions
|
|
|
|
Let's build and broadcast transactions using the transaction builder.
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Create a Transaction Builder
|
|
|
|
Initialize the transaction builder with gas estimation:
|
|
|
|
```go
|
|
// Create transaction builder
|
|
txBuilder, err := tx.NewTxBuilder(&cfg, conn)
|
|
if err != nil {
|
|
log.Fatal("Failed to create tx builder:", err)
|
|
}
|
|
|
|
// Create broadcaster
|
|
broadcaster, err := tx.NewBroadcaster(&cfg, conn)
|
|
if err != nil {
|
|
log.Fatal("Failed to create broadcaster:", err)
|
|
}
|
|
|
|
// Create gas estimator
|
|
gasEstimator := tx.NewGasEstimator(conn, &cfg)
|
|
```
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Send Tokens Between Accounts
|
|
|
|
Build and broadcast a bank send transaction:
|
|
|
|
```go
|
|
import (
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
)
|
|
|
|
// Create a second wallet to receive funds
|
|
receiver, _, err := keyringManager.CreateWallet(
|
|
context.Background(),
|
|
"receiver-wallet",
|
|
"",
|
|
)
|
|
if err != nil {
|
|
log.Fatal("Failed to create receiver wallet:", err)
|
|
}
|
|
|
|
// Create send message
|
|
amount := sdk.NewCoins(sdk.NewInt64Coin("usnr", 1000000)) // 1 SNR
|
|
sendMsg := &banktypes.MsgSend{
|
|
FromAddress: walletIdentity.Address,
|
|
ToAddress: receiver.Address,
|
|
Amount: amount,
|
|
}
|
|
|
|
// Build transaction
|
|
txBuilder = txBuilder.
|
|
AddMessage(sendMsg).
|
|
WithMemo("Test transaction").
|
|
WithGasLimit(200000)
|
|
|
|
// Estimate gas
|
|
gasEstimate, err := gasEstimator.EstimateGas(
|
|
context.Background(),
|
|
[]sdk.Msg{sendMsg},
|
|
)
|
|
if err != nil {
|
|
log.Printf("Gas estimation failed: %v", err)
|
|
} else {
|
|
fmt.Printf("Estimated gas: %d\n", gasEstimate.GasLimit)
|
|
txBuilder = txBuilder.WithGasLimit(gasEstimate.GasLimit)
|
|
}
|
|
|
|
// Calculate and set fee
|
|
fee := gasEstimator.CalculateFee(
|
|
gasEstimate.GasLimit,
|
|
cfg.GasPrice,
|
|
cfg.StakingDenom,
|
|
)
|
|
txBuilder = txBuilder.WithFee(fee)
|
|
|
|
// Sign the transaction
|
|
signedTx, err := txBuilder.Sign(context.Background(), keyringManager)
|
|
if err != nil {
|
|
log.Fatal("Failed to sign transaction:", err)
|
|
}
|
|
|
|
// Broadcast the transaction
|
|
result, err := broadcaster.BroadcastTx(context.Background(), signedTx)
|
|
if err != nil {
|
|
log.Fatal("Failed to broadcast transaction:", err)
|
|
}
|
|
|
|
fmt.Printf("Transaction successful!\n")
|
|
fmt.Printf("TxHash: %s\n", result.TxHash)
|
|
fmt.Printf("Height: %d\n", result.Height)
|
|
fmt.Printf("Gas Used: %d\n", result.GasUsed)
|
|
```
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## 5. WebAuthn Gasless Transactions (Advanced)
|
|
|
|
Sonr supports gasless WebAuthn registration, allowing users to onboard without holding tokens.
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Initialize WebAuthn Client
|
|
|
|
Set up the WebAuthn client for gasless operations:
|
|
|
|
```go
|
|
import (
|
|
"github.com/sonr-io/sonr/client/auth"
|
|
)
|
|
|
|
// Create WebAuthn client
|
|
webauthnClient := auth.NewWebAuthnClient(
|
|
keyringManager,
|
|
"localhost", // Relying Party ID
|
|
"Sonr Local", // Relying Party Name
|
|
)
|
|
|
|
// Create gasless transaction manager
|
|
gaslessManager := auth.NewGaslessTransactionManager(
|
|
txBuilder,
|
|
broadcaster,
|
|
&cfg,
|
|
)
|
|
|
|
// Create WebAuthn gasless client
|
|
gaslessClient := auth.NewWebAuthnGaslessClient(
|
|
webauthnClient,
|
|
gaslessManager,
|
|
&cfg,
|
|
)
|
|
```
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Initiate Gasless Registration
|
|
|
|
Start a gasless WebAuthn registration:
|
|
|
|
```go
|
|
// Begin gasless registration
|
|
registrationResult, err := gaslessClient.RegisterGasless(
|
|
context.Background(),
|
|
"alice", // username
|
|
"Alice Smith", // display name
|
|
)
|
|
if err != nil {
|
|
log.Fatal("Failed to initiate registration:", err)
|
|
}
|
|
|
|
fmt.Printf("Registration initiated!\n")
|
|
fmt.Printf("Gasless eligible: %v\n", registrationResult.GaslessEligible)
|
|
fmt.Printf("Estimated gas: %d\n", registrationResult.EstimatedGas)
|
|
|
|
// The challenge would be sent to a browser for completion
|
|
// In a real application, you'd handle the browser response
|
|
```
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Check Gasless Eligibility
|
|
|
|
Verify if a transaction is eligible for gasless processing:
|
|
|
|
```go
|
|
// Check if messages are eligible for gasless
|
|
msgs := []sdk.Msg{
|
|
&didtypes.MsgRegisterWebAuthnCredential{
|
|
Controller: "sonr1...",
|
|
Username: "alice",
|
|
},
|
|
}
|
|
|
|
isEligible := gaslessManager.IsEligibleForGasless(msgs)
|
|
fmt.Printf("Transaction eligible for gasless: %v\n", isEligible)
|
|
|
|
// Estimate gas for gasless transaction
|
|
gasNeeded := gaslessManager.EstimateGaslessGas(
|
|
"/did.v1.MsgRegisterWebAuthnCredential",
|
|
)
|
|
fmt.Printf("Gas needed for gasless WebAuthn: %d\n", gasNeeded)
|
|
```
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## 6. Working with DID Module
|
|
|
|
Create and manage decentralized identities:
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Create a DID Document
|
|
|
|
```go
|
|
import (
|
|
didtypes "github.com/sonr-io/sonr/x/did/types"
|
|
)
|
|
|
|
// Create DID document
|
|
didDoc := &didtypes.DidDocument{
|
|
Id: "did:sonr:" + walletIdentity.Address,
|
|
Controller: walletIdentity.Address,
|
|
VerificationMethod: []*didtypes.VerificationMethod{
|
|
{
|
|
Id: "did:sonr:" + walletIdentity.Address + "#key-1",
|
|
VerificationMethodKind: didtypes.VerificationMethodKind_Ed25519VerificationKey2020,
|
|
Controller: "did:sonr:" + walletIdentity.Address,
|
|
PublicKeyMultibase: "z6MkhaXgBZD...", // Your public key
|
|
},
|
|
},
|
|
Service: []*didtypes.Service{
|
|
{
|
|
Id: "did:sonr:" + walletIdentity.Address + "#dwn",
|
|
ServiceKind: didtypes.ServiceKind_DecentralizedWebNode,
|
|
SingleEndpoint: "https://dwn.example.com",
|
|
},
|
|
},
|
|
}
|
|
|
|
// Create the message
|
|
createDIDMsg, err := didClient.CreateDID(
|
|
walletIdentity.Address,
|
|
didDoc,
|
|
)
|
|
if err != nil {
|
|
log.Fatal("Failed to create DID message:", err)
|
|
}
|
|
|
|
// Add to transaction and broadcast
|
|
txBuilder = txBuilder.
|
|
ClearMessages().
|
|
AddMessage(createDIDMsg).
|
|
WithMemo("Create DID")
|
|
|
|
// Sign and broadcast as shown earlier
|
|
```
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Next Steps
|
|
|
|
This quickstart has covered the fundamentals of the Sonr Go Client SDK:
|
|
|
|
- **Client Configuration**: Setting up connections and network configurations
|
|
- **Key Management**: Creating and managing wallets with the keyring
|
|
- **Querying**: Reading blockchain state and module data
|
|
- **Transactions**: Building, signing, and broadcasting transactions
|
|
- **Gas Estimation**: Calculating optimal gas limits and fees
|
|
- **WebAuthn**: Gasless onboarding with WebAuthn credentials
|
|
- **DID Module**: Creating decentralized identities
|
|
|
|
### Advanced Topics to Explore:
|
|
|
|
- **DWN Module**: Manage decentralized web nodes and data records
|
|
- **Service Module**: Register and verify services with domain verification
|
|
- **UCAN Integration**: Implement capability-based authorization
|
|
- **Multi-signature**: Create and manage multi-sig accounts
|
|
- **IBC Transfers**: Cross-chain token transfers
|
|
- **Custom Modules**: Interact with your own custom modules
|
|
|
|
### Useful Resources:
|
|
|
|
- [Client SDK API Reference](https://pkg.go.dev/github.com/sonr-io/sonr/client)
|
|
- [Cosmos SDK Documentation](https://docs.cosmos.network)
|
|
- [Sonr GitHub Repository](https://github.com/sonr-io/sonr)
|