Overview
Go is a statically-typed, compiled language known for its simplicity, efficiency, and strong concurrency support. Follow the official installation guide to install Go. Verify the installation:
go version
Authentication Required for Sui gRPC
To ensure secure access to Sui gRPC, users are required to authenticate themselves. This authentication process is necessary before utilizing any method. QuickNode endpoints consist of two crucial components: the endpoint name
and the corresponding token
. Users will need to use these two components to configure a gRPC client with authentication credentials before they make any method calls.
Authentication for the Sui gRPC can be handled in two ways:
- Basic Authentication
- x-token Authentication
Throughout this documentation, we will call either the getClientWithBasicAuth
or getClientWithXToken
functions to demonstrate how to handle these different authentication mechanisms.
Basic Authentication
The getClientWithBasicAuth
function demonstrates how to handle authentication using Basic Authentication, which encodes the credentials as base64. Below is the code implementation of the getClientWithBasicAuth
function as well as the basicAuth
implementation of RPC credentials:
import (
"context"
"crypto/tls"
"encoding/base64"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func getClientWithBasicAuth(endpoint, token string) (client.GRPCClient, error) {
target := endpoint + ".sui-mainnet.quiknode.pro:9000" // for TLS connections
conn, err := grpc.Dial(target,
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
grpc.WithPerRPCCredentials(basicAuth{
username: endpoint,
password: token,
}),
)
if err != nil {
return nil, fmt.Errorf("Unable to dial endpoint %w", err)
}
return client.NewGRPCClient(conn), nil
}
// basicAuth implements the credentials.PerRPCCredentials interface to support basic authentication for grpc requests.
type basicAuth struct {
username string
password string
}
func (b basicAuth) GetRequestMetadata(ctx context.Context, in ...string) (map[string]string, error) {
auth := b.username + ":" + b.password
enc := base64.StdEncoding.EncodeToString([]byte(auth))
return map[string]string{"authorization": "Basic " + enc}, nil
}
func (basicAuth) RequireTransportSecurity() bool {
return false
}
The getClientWithBasicAuth
function configures a gRPC client with the necessary security options and establishes a connection to the specified endpoint on port 9000
. It takes the endpoint name and token as input parameters and returns an instance of the GRPCClient interface, which you can use to make authenticated API calls.
client, err := getClientWithBasicAuth("ENDPOINT_NAME", "TOKEN")
if err != nil {
log.Fatalf("err: %v", err)
}
x-token Authentication
The getClientWithXToken
function demonstrates how to handle authentication using an x-token. This method attaches the token to the x-token header of each request.
import (
"context"
"crypto/tls"
"fmt"
"github.com/fbsobreira/gosui-sdk/pkg/client"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func getClientWithXToken(endpoint, token string) (client.GRPCClient, error) {
target := endpoint + ".sui-mainnet.quiknode.pro:9000" // for TLS connections
conn, err := grpc.Dial(target,
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
grpc.WithPerRPCCredentials(auth{
token: token,
}),
)
if err != nil {
return nil, fmt.Errorf("Unable to dial endpoint %w", err)
}
return client.NewGRPCClient(conn), nil
}
// auth implements the credentials.PerRPCCredentials interface to support x-token authentication for grpc requests.
type auth struct {
token string
}
func (a *auth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"x-token": a.token,
}, nil
}
func (auth) RequireTransportSecurity() bool {
return false
}
This method configures a gRPC client similarly to the basic authentication example, but it attaches the authentication token in the x-token header. Here's how you can use this function to make API calls:
client, err := getClientWithXToken("ENDPOINT_NAME", "TOKEN")
if err != nil {
log.Fatalf("err: %v", err)
}
The below section provides a step-by-step process to set up a Go environment for making gRPC requests. The instructions include setting up Go, configuring dependencies, and implementing authentication mechanisms.
Initiating the Go Project for Sui gRPC
Step 1: Create a New Project Directory
Create a dedicated directory for your Sui gRPC project and navigate into it:
mkdir sui-grpc
cd sui-grpc
Step 2: Initialize a Go Module
Create a Go module for your project. The module name can match your directory name or be a repository URL:
go mod init sui-grpc # directory name
Step 3: Install gRPC and Protobuf Dependencies
Ensure you have both Go and protoc
installed on your machine.
You can Install the core gRPC and Protobuf libraries by following commands:
go get google.golang.org/grpc
go get google.golang.org/protobuf
You can also define versions directly in your go.mod
:
require (
google.golang.org/grpc v1.60.0
google.golang.org/protobuf v1.33.0
)
Next, install the protoc plugins for Go:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Make sure $GOPATH/bin
is in your system’s PATH. You can follow below steps to set the system PATH for GO.
To use Go-installed tools globally (e.g., protoc-gen-go
, grpcurl
), add $GOPATH/bin
to your system PATH
.
For macOS / Linux
- Add to your shell config file:
echo 'export PATH="$PATH:$(go env GOPATH)/bin"' >> ~/.bashrc
source ~/.bashrc
Use .zshrc instead of .bashrc if you're using Zsh.
- Verify:
which protoc-gen-go
For Windows
-
Open Start Menu → search for Environment Variables
-
Under System Variables, select Path → click Edit
-
Click New and add:
%USERPROFILE%\go\bin
- Open a new Command Prompt or PowerShell and verify:
where protoc-gen-go
Step 4: Organize Your Project Directory
Create a protos
folder to store the original Protocol Buffer definition files:
mkdir protos
Download the official Sui proto files from the MystenLabs/sui repository. Extract and place the entire sui
directory structure into your newly created protos
folder. Alternatively, you can run the following commands:
# Clone the repository with minimal depth
git clone https://github.com/MystenLabs/sui.git --depth=1
# Copy the proto files to your working directory
cp -r sui/crates/sui-rpc-api/proto protos
# Remove the cloned repository (optional)
rm -rf sui
Your project structure should look like this:
sui-grpc/
├── protos/
│ └── sui/
│ └── rpc/
│ └── v2beta/
│ ├── ledger_service.proto
│ ├── common.proto
│ ├── transaction.proto
│ └── ... (other proto files)
├── go.mod
Step 5: Generate Go Code from Proto Files
First, we need to add go_package
to each .proto
File. For that we need to modify each .proto
file (e.g. argument.proto
, checkpoint.proto
, etc.) to include a go_package
option near the top:
syntax = "proto3";
package sui.rpc.v2beta;
option go_package = "sui/rpc/v2beta";
Once the go_package is added and your folder structure matches the above layout, generate the .pb.go
files by running the following command:
protoc \
--proto_path=protos/proto \
--go_out=. \
--go-grpc_out=. \
protos/proto/sui/rpc/v2beta/*.proto
Step 6: Create a Main Go File
Set up a main Go file for implementing client or server logic:
touch main.go
You can copy and paste the following sample code into your main.go file to get started. The example demonstrates how to interact with the Sui gRPC service to fetch object information.
package main
import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/fieldmaskpb"
pb "sui-grpc/sui/proto/generated/sui/rpc/v2beta" // Your Generated .pb.go files path
)
// QuickNode endpoints consist of two crucial components: the endpoint name and the corresponding token
// For eg: QN Endpoint: https://docs-demo.sui-mainnet.quiknode.pro/abcde123456789
// endpoint will be: docs-demo.sui-mainnet.quiknode.pro:9000 {9000 is the port number for Sui gRPC}
// token will be : abcde123456789
var (
token = "YOUR_TOKEN_NUMBER"
endpoint = "YOUR_QN_ENDPOINT:9000"
)
type auth struct {
token string
}
func (a *auth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{"x-token": a.token}, nil
}
func (a *auth) RequireTransportSecurity() bool {
return true
}
func main() {
creds := credentials.NewTLS(&tls.Config{})
opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithPerRPCCredentials(&auth{token}),
}
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()
client := pb.NewLedgerServiceClient(conn)
// Object ID to fetch
objectID := "0x27c4fdb3b846aa3ae4a65ef5127a309aa3c1f466671471a806d8912a18b253e8"
// Build request with field mask
req := &pb.BatchGetObjectsRequest{
Requests: []*pb.GetObjectRequest{
{
ObjectId: &objectID,
},
},
ReadMask: &fieldmaskpb.FieldMask{
Paths: []string{
"object_id",
"version",
"digest",
"owner",
"object_type",
"has_public_transfer",
"contents",
"modules",
"type_origin_table",
"linkage_table",
"previous_transaction",
"storage_rebate",
"bcs",
},
},
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
resp, err := client.BatchGetObjects(ctx, req)
if err != nil {
log.Fatalf("BatchGetObjects failed: %v", err)
}
// Pretty print the response
marshaler := protojson.MarshalOptions{
UseProtoNames: true,
EmitUnpopulated: true,
Indent: " ",
}
jsonBytes, err := marshaler.Marshal(resp)
if err != nil {
log.Fatalf("Failed to marshal: %v", err)
}
var pretty map[string]interface{}
if err := json.Unmarshal(jsonBytes, &pretty); err != nil {
log.Fatalf("Failed to parse JSON: %v", err)
}
out, _ := json.MarshalIndent(pretty, "", " ")
fmt.Println(string(out))
}
Step 7: Run Your Code
Before running your code, clean up and ensure all dependencies are correctly resolved:
go mod tidy
Build and run the project using:
go run main.go
We ❤️ Feedback!
If you have any feedback or questions about this documentation, let us know. We'd love to hear from you!