A Go SDK for interacting with 0G Storage through an S3-compatible API, featuring SIWE (Sign-In With Ethereum) authentication and AWS SDK-style upload interface.
- SIWE Authentication - Secure wallet-based authentication using Ethereum signatures
- AWS SDK-style API - Familiar interface matching AWS S3 SDK patterns
- Direct Upload - Synchronous/Asynchronous uploads with context support
- Configurable - Extensive 0G storage-specific configuration options
First, authenticate using SIWE (Sign-In With Ethereum):
package main
import (
"fmt"
"log"
"github.com/0gfoundation/0g-storage-s3-sdk/client"
)
func main() {
// Create client
c := client.New("http://localhost:8080")
// Step 1: Get nonce
nonceResp, err := c.Auth.GetNonce()
if err != nil {
log.Fatal(err)
}
// Step 2: Create SIWE message
messageText, err := c.SIWEUtils.CreateAndFormatSIWEMessage(
client.DefaultDomain,
user_address,
"http://localhost",
nonceResp.Nonce,
client.DefaultChainID,
)
if err != nil {
log.Fatal(err)
}
// Step 3: Sign message with your wallet (private key)
privateKey := "your-private-key-hex"
signature, err := c.SIWEUtils.SignMessage(messageText, privateKey)
if err != nil {
log.Fatal(err)
}
// Step 4: Verify signature and get credentials
verifyResp, err := c.Auth.VerifySignature(messageText, signature)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Authentication successful!\n")
fmt.Printf("Access Key: %s\n", verifyResp.AccessKeyID)
fmt.Printf("Session Token: %s\n", verifyResp.SessionToken)
}For the examples, you can use a single .env file (see .env.example) to set:
STORAGE_SERVER_ENDPOINT, RPC_URL, PAYMENT_VAULT_ADDRESS, PRIVATE_KEY,
ACCESS_KEY_ID, SECRET_ACCESS_KEY, SESSION_TOKEN, BUCKET, and REGION.
After authentication, use the AWS SDK-style API for uploads:
package main
import (
"context"
"fmt"
"log"
"os"
"strings"
"github.com/0gfoundation/0g-storage-s3-sdk/client"
)
func main() {
// Configure credentials from auth step
credentials := &client.Credentials{
AccessKeyID: "your-access-key-from-auth",
SecretAccessKey: "your-secret-key-from-auth", // nullable
SessionToken: "your-session-token-from-auth",
}
// Create S3-style config
cfg := client.Config{
Credentials: credentials,
Region: "us-east-1",
Endpoint: "http://localhost:8080",
Config: nil, // Use default 0G storage settings
}
// Create S3 client (AWS SDK-style)
s3Client := client.NewFromConfig(cfg)
// Read file
fileContent := "Hello, 0G Storage!"
bucket := "my-bucket"
key := "test-file.txt"
// Upload (AWS SDK-style)
jobID, err := s3Client.UploadAsync(context.TODO(), &client.PutObjectInput{
Bucket: &bucket,
Key: &key,
Body: strings.NewReader(fileContent),
})
if err != nil {
log.Fatalf("Upload failed: %v", err)
}
result, err := s3Client.PollUpload(context.TODO(), jobID)
if err != nil {
log.Fatalf("Upload failed: %v", err)
}
fmt.Println("Upload successful!")
fmt.Printf("Location: %s\n", result.Location)
fmt.Printf("ETag: %s\n", result.ETag)
fmt.Printf("Transaction Hashes: %v\n", result.TxHashes)
}Paid uploads require a funded payment vault balance. The testnet PaymentVault contract address is:
0x45f64a8b2eF0dD7A534EE401ca414E5407645247
Mainnet contract address: not available yet.
Contract method:
depositFor(address user) payable
Go helper (same as examples/auth/main.go):
const paymentVaultAddress = "0x45f64a8b2eF0dD7A534EE401ca414E5407645247"
txHash, err := client.FundPaymentVault(
context.Background(),
"https://rpc.0g.ai",
"your-private-key-hex", // wallet to pay the funding
paymentVaultAddress,
"address-to-fund-to", // can be a different eoa
big.NewInt(1_000_000_000_000_000), // 0.001 ETH in wei
)
if err != nil {
log.Fatal(err)
}
fmt.Println("funded tx:", txHash.Hex())The SDK supports extensive 0G storage configuration through the UploadConfig struct:
config := &client.UploadConfig{
Tags: "0x", // X-0g-Tags
ExpectedReplica: 1, // X-0g-Expected-Replica
TaskSize: 10, // X-0g-Task-Size
FinalityRequired: true, // X-0g-Finality-Required
SkipTx: false, // X-0g-Skip-Tx
FastMode: true, // X-0g-Fast-Mode
Fee: 0.01, // X-0g-Fee (in ETH/tokens)
Indexer: "https://indexer-storage-testnet-turbo.0g.ai", // X-0g-Indexer
// ... more options available
}
cfg := client.Config{
Credentials: credentials,
Config: config, // Pass custom config
}c.Auth.GetNonce()- Get nonce for SIWEc.SIWEUtils.CreateAndFormatSIWEMessage(...)- Create and format SIWE message textc.SIWEUtils.SignMessage(message, privateKey)- Sign messagec.Auth.VerifySignature(message, signature)- Verify and get credentials
client.NewFromConfig(cfg)- Create S3 clients3Client.UploadAsync(ctx, input)- Submit upload jobs3Client.PollUpload(ctx, jobID)- Poll upload status
type Credentials struct {
AccessKeyID string
SecretAccessKey string
SessionToken string
}
type PutObjectInput struct {
Bucket *string // Required
Key *string // Required
Body io.Reader // Required
ContentType *string // Optional
}
type UploadResult struct {
Status string // "success" or "pending"
DataSize int64 // Uploaded size
UploadCost string // Cost in wei
TxHashes []string // Blockchain transaction hashes
Roots []string // Merkle roots
}