Sui gRPC API
High-Performance Blockchain Data Access#
Dwellir's Sui gRPC API provides a high-performance alternative to traditional JSON-RPC for accessing Sui blockchain data. Built on Protocol Buffers and HTTP/2, gRPC offers superior performance, type safety, and efficient binary serialization for demanding applications that require minimal latency and maximum throughput.
Why Use gRPC?#
Performance Advantages#
- Binary Protocol: Protocol Buffers provide compact binary encoding, reducing payload sizes by up to 70% compared to JSON
- HTTP/2 Multiplexing: Multiple concurrent requests over a single connection eliminate connection overhead
- Streaming Support: Bidirectional streaming enables real-time data feeds with minimal latency
- Efficient Serialization: Native binary format significantly reduces parsing overhead
Developer Benefits#
- Strong Typing: Protocol Buffer definitions provide compile-time type checking
- Code Generation: Automatic client generation from
.protofiles eliminates boilerplate - Language Support: Native implementations available for Go, Python, TypeScript, Rust, and more
- Built-in Features: Deadlines, cancellation, and load balancing come standard
Use Cases for gRPC#
- High-frequency trading: Microsecond-level latency requirements
- Real-time monitoring: Live blockchain event streaming and monitoring dashboards
- Analytics pipelines: Bulk data extraction and processing
- Mobile applications: Reduced bandwidth consumption on limited connections
- Microservices: Efficient inter-service communication in distributed architectures
gRPC vs JSON-RPC Comparison#
| Feature | gRPC | JSON-RPC |
|---|---|---|
| Protocol | HTTP/2 + Protocol Buffers | HTTP/1.1 + JSON |
| Payload Size | Compact binary (~30% smaller) | Text-based JSON |
| Streaming | Bidirectional streaming support | Request/response only |
| Type Safety | Strong typing via .proto | Runtime validation required |
| Performance | 5-10x faster serialization | Slower text parsing |
| Browser Support | Requires gRPC-Web proxy | Native browser support |
| Tooling | Code generation required | Simpler setup |
Available Services#
The Sui gRPC API is organized into six specialized services:
1. Ledger Service#
Access historical blockchain data and core object information:
- Retrieve objects by ID with field masking
- Query transactions with execution details
- Access checkpoint and epoch data
- Batch operations for multiple objects or transactions
2. Live Data Service#
Query current blockchain state efficiently:
- Check account balances for any coin type
- List owned objects with pagination
- Enumerate dynamic fields
- Simulate transactions before execution
- Retrieve coin metadata and information
3. Transaction Service#
Execute and broadcast transactions:
- Submit signed transactions for on-chain execution
- Monitor transaction status and finality
- Dry-run transactions for gas estimation
4. Move Package Service#
Inspect Move smart contracts and modules:
- Retrieve package information and metadata
- Query function signatures and capabilities
- Inspect data types and structures
- List package version history
5. Subscription Service#
Real-time blockchain event streaming:
- Subscribe to checkpoint updates as they finalize
- Stream events matching specific filters
- Monitor transaction confirmations in real-time
6. Signature Verification Service#
Cryptographic signature operations:
- Verify transaction signatures off-chain
- Validate multi-sig configurations
- Check signature authenticity
Connection Configuration#
Endpoint Structure#
Dwellir's Sui gRPC endpoints follow this format:
[your-endpoint-name].sui-mainnet.dwellir.com:9000
Important Notes:
- gRPC uses port 9000 (different from HTTP port 443)
- Connections require TLS encryption
- Authentication via metadata headers
Network Endpoints#
| Network | gRPC Endpoint |
|---|---|
| Mainnet | api-sui-mainnet-full.n.dwellir.com |
| Testnet | your-endpoint.sui-testnet.dwellir.com:9000 |
Quick Start Guide#
Prerequisites#
- Dwellir API Key: Obtain from dashboard.dwellir.com
- Protocol Buffers: Install
protoccompiler for code generation - gRPC Libraries: Language-specific gRPC implementation
Protocol Buffer Files#
Download the official Sui proto definitions from the MystenLabs sui-apis repository:
# Clone the Sui API definitions
git clone https://github.com/MystenLabs/sui-apis.git
cd sui-apis
Key proto files:
ledger.proto- Ledger service definitionslive_data.proto- Live data queriestransaction.proto- Transaction executionmove_package.proto- Move package inspectionsubscription.proto- Real-time subscriptionssignature_verification.proto- Signature operations
Language-Specific Setup#
- TypeScript
- Python
- Go
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client
# Initialize Node.js project
npm init -y
# Install dependencies
npm install @grpc/grpc-js @grpc/proto-loader
npm install -D @types/node tsx
# Download proto files
mkdir -p protos
# Copy proto files from sui-apis repository to protos/
Basic Client Example:
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import { ProtoGrpcType } from './generated/ledger';
// Configuration
const ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com';
const API_TOKEN = 'your_api_token_here';
// Load proto definition
const packageDefinition = protoLoader.loadSync(
'./protos/ledger.proto',
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs: ['./protos']
}
);
const protoDescriptor = grpc.loadPackageDefinition(
packageDefinition
) as unknown as ProtoGrpcType;
// Create secure channel with TLS
const credentials = grpc.credentials.createSsl();
// Setup authentication metadata
const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_TOKEN);
// Create client
const client = new protoDescriptor.sui.rpc.v2beta2.LedgerService(
ENDPOINT,
credentials
);
// Example: Get object information
const objectId = '0x5';
const request = {
object_id: objectId,
read_mask: {
paths: ['object_id', 'version', 'digest', 'owner', 'object_type']
}
};
client.GetObject(request, metadata, (error, response) => {
if (error) {
console.error('Error:', error.message);
return;
}
console.log('Object data:', JSON.stringify(response, null, 2));
});
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install grpcio grpcio-tools protobuf
# Create protos directory
mkdir protos
# Copy proto files from sui-apis repository to protos/
# Generate Python code from proto files
python -m grpc_tools.protoc \
--proto_path=./protos \
--python_out=. \
--grpc_python_out=. \
./protos/ledger.proto
Basic Client Example:
import grpc
import ledger_service_pb2
import ledger_service_pb2_grpc
# Configuration
ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com'
API_TOKEN = 'your_api_token_here'
# Create secure channel with TLS
credentials = grpc.ssl_channel_credentials()
channel = grpc.secure_channel(ENDPOINT, credentials)
# Create client stub
client = ledger_service_pb2_grpc.LedgerServiceStub(channel)
# Setup authentication metadata
metadata = [('x-api-key', API_TOKEN)]
# Example: Get object information
object_id = '0x5'
request = ledger_service_pb2.GetObjectRequest(
object_id=object_id,
read_mask=ledger_service_pb2.google_dot_protobuf_dot_field__mask__pb2.FieldMask(
paths=['object_id', 'version', 'digest', 'owner', 'object_type']
)
)
try:
response = client.GetObject(request, metadata=metadata)
print(f'Object data: {response}')
except grpc.RpcError as e:
print(f'Error: {e.code()}: {e.details()}')
finally:
channel.close()
# Create project directory
mkdir sui-grpc-client && cd sui-grpc-client
# Initialize Go module
go mod init sui-grpc-client
# Install dependencies
go get google.golang.org/grpc
go get google.golang.org/protobuf
# Install protoc plugins for Go code generation
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# Ensure Go bin is in PATH (add to ~/.zshrc or ~/.bash_profile for persistence)
export PATH="$PATH:$HOME/go/bin"
# Copy proto files from sui-apis repository
mkdir -p protos
cp -r ../proto/* protos/
# Add go_package option to all proto files
find protos/sui/rpc/v2 -name "*.proto" -type f | while read proto_file; do
if ! grep -q "option go_package" "$proto_file"; then
sed -i.bak '/^package sui.rpc.v2;$/a\
\
option go_package = "sui-grpc-client/sui/rpc/v2";
' "$proto_file"
fi
done
# Generate Go code from proto files
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
--proto_path=./protos \
./protos/sui/rpc/v2/*.proto
Basic Client Example:
package main
import (
"context"
"fmt"
"log"
"time"
pb "sui-grpc-client/sui/rpc/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)
const (
// Dwellir gRPC endpoint - note: uses .tech domain, not .com
endpoint = "api-sui-mainnet-full.n.dwellir.com:443"
apiKey = "api_key"
)
func main() {
// Create TLS credentials for secure connection
creds := credentials.NewClientTLSFromCert(nil, "")
// Connect to Dwellir Sui gRPC server using NewClient (replaces deprecated Dial)
conn, err := grpc.NewClient(
endpoint,
grpc.WithTransportCredentials(creds),
)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer conn.Close()
client := pb.NewLedgerServiceClient(conn)
// Setup authentication metadata with API key
// Dwellir uses x-api-key header (not authorization or x-api-key)
ctx := metadata.AppendToOutgoingContext(
context.Background(),
"x-api-key", apiKey,
)
// Set timeout
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
// Get service info
resp, err := client.GetServiceInfo(ctx, &pb.GetServiceInfoRequest{})
if err != nil {
log.Fatalf("GetServiceInfo failed: %v", err)
}
fmt.Printf("Connected to Sui Node via Dwellir\n")
fmt.Printf("Chain: %s\n", resp.GetChain())
fmt.Printf("Chain ID: %s\n", resp.GetChainId())
fmt.Printf("Current Epoch: %d\n", resp.GetEpoch())
fmt.Printf("Checkpoint Height: %d\n", resp.GetCheckpointHeight())
fmt.Printf("Server: %s\n", resp.GetServer())
}
Authentication#
All gRPC requests to Dwellir's Sui endpoints require authentication via metadata headers:
x-api-key: YOUR_API_TOKEN
The API token is extracted from your Dwellir endpoint URL. For example, if your endpoint is:
https://api-sui-mainnet-full.n.dwellir.com/abc123xyz
Your gRPC token is: `abc123xyz`
### Security Best Practices
- **Never expose tokens in client-side code**: Use backend services to proxy gRPC requests
- **Rotate tokens periodically**: Generate new tokens through the Dwellir dashboard
- **Use environment variables**: Store tokens outside of source code
- **Monitor usage**: Track API consumption via the Dwellir dashboard
## Field Masking
gRPC requests support field masking to optimize response payloads and reduce bandwidth. Specify only the fields you need:
```typescript
const request = {
object_id: '0x5',
read_mask: {
paths: ['object_id', 'version', 'owner'] // Only return these fields
}
};
Benefits:
- Reduced response sizes (up to 80% smaller)
- Faster serialization and network transfer
- Lower bandwidth costs
- Improved application performance
Error Handling#
gRPC provides standardized error codes for consistent error handling:
| Code | Description | Action |
|---|---|---|
OK (0) | Success | Continue processing |
CANCELLED (1) | Client cancelled | Retry if needed |
INVALID_ARGUMENT (3) | Invalid request parameters | Fix request and retry |
NOT_FOUND (5) | Resource not found | Verify object IDs |
ALREADY_EXISTS (6) | Resource exists | Handle duplicate |
PERMISSION_DENIED (7) | Authentication failed | Check API token |
RESOURCE_EXHAUSTED (8) | Rate limit exceeded | Implement backoff |
FAILED_PRECONDITION (9) | System state invalid | Retry later |
UNAVAILABLE (14) | Service unavailable | Retry with backoff |
DEADLINE_EXCEEDED (4) | Request timeout | Increase timeout |
Example Error Handling#
- TypeScript
- Python
client.GetObject(request, metadata, (error, response) => {
if (error) {
switch (error.code) {
case grpc.status.NOT_FOUND:
console.error('Object not found:', error.message);
break;
case grpc.status.PERMISSION_DENIED:
console.error('Authentication failed. Check API token.');
break;
case grpc.status.RESOURCE_EXHAUSTED:
console.error('Rate limit exceeded. Retrying after backoff...');
// Implement exponential backoff
break;
case grpc.status.UNAVAILABLE:
console.error('Service temporarily unavailable. Retrying...');
// Retry with backoff
break;
default:
console.error('Unexpected error:', error.message);
}
return;
}
// Process successful response
console.log('Success:', response);
});
import grpc
import time
def get_object_with_retry(client, request, metadata, max_retries=3):
"""Get object with automatic retry logic"""
for attempt in range(max_retries):
try:
response = client.GetObject(request, metadata=metadata)
return response
except grpc.RpcError as e:
code = e.code()
if code == grpc.StatusCode.NOT_FOUND:
print(f'Object not found: {e.details()}')
return None
elif code == grpc.StatusCode.PERMISSION_DENIED:
print(f'Authentication failed: {e.details()}')
return None
elif code == grpc.StatusCode.RESOURCE_EXHAUSTED:
wait_time = 2 ** attempt # Exponential backoff
print(f'Rate limited. Retrying in {wait_time}s...')
time.sleep(wait_time)
elif code == grpc.StatusCode.UNAVAILABLE:
wait_time = 2 ** attempt
print(f'Service unavailable. Retrying in {wait_time}s...')
time.sleep(wait_time)
else:
print(f'Unexpected error: {code}: {e.details()}')
return None
print(f'Failed after {max_retries} attempts')
return None
Performance Optimization#
Connection Pooling#
Reuse gRPC channels across requests to avoid connection overhead:
// Create a single channel for the application lifecycle
const channel = new grpc.Client(
ENDPOINT,
credentials,
{ 'grpc.keepalive_time_ms': 10000 }
);
// Reuse channel for all services
const ledgerClient = new protoDescriptor.sui.rpc.v2beta2.LedgerService(channel);
const liveDataClient = new protoDescriptor.sui.rpc.v2beta2.LiveDataService(channel);
Batch Requests#
Use batch methods when querying multiple items:
// Efficient: Single batch request
const batchResponse = await client.BatchGetObjects({
object_ids: ['0x1', '0x2', '0x3', '0x4', '0x5']
});
// Inefficient: Multiple individual requests
for (const id of objectIds) {
await client.GetObject({ object_id: id }); // Avoid this pattern
}
Field Masking#
Request only necessary fields to minimize payload size:
// Efficient: Only request needed fields
const request = {
object_id: '0x5',
read_mask: { paths: ['object_id', 'owner'] }
};
// Inefficient: Requesting all fields
const request = { object_id: '0x5' }; // Returns everything
Compression#
Enable gRPC compression for large payloads:
const options = {
'grpc.default_compression_algorithm': grpc.compressionAlgorithms.gzip,
'grpc.default_compression_level': grpc.compressionLevels.high
};
const client = new protoDescriptor.sui.rpc.v2beta2.LedgerService(
ENDPOINT,
credentials,
options
);
Real-Time Streaming#
gRPC's streaming capabilities enable real-time blockchain monitoring:
Checkpoint Subscription Example#
const subscribeRequest = {
read_mask: {
paths: [
'sequence_number',
'digest',
'timestamp_ms',
'network_total_transactions'
]
}
};
const stream = client.SubscribeCheckpoints(subscribeRequest, metadata);
stream.on('data', (checkpoint) => {
console.log('New checkpoint:', {
sequence: checkpoint.sequence_number,
digest: checkpoint.digest,
timestamp: new Date(parseInt(checkpoint.timestamp_ms)),
txCount: checkpoint.network_total_transactions
});
});
stream.on('error', (error) => {
console.error('Stream error:', error.message);
// Implement reconnection logic
});
stream.on('end', () => {
console.log('Stream ended');
});
Stream Management Best Practices#
- Implement reconnection logic: Automatically reconnect on stream failures
- Handle backpressure: Process data faster than it arrives or implement buffering
- Monitor connection health: Use keepalive pings and heartbeats
- Graceful shutdown: Close streams properly to avoid resource leaks
Best Practices#
1. Use Appropriate Timeouts#
Set reasonable timeouts to prevent hanging requests:
const deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 10);
client.GetObject(request, { deadline }, (error, response) => {
// Handle response
});
2. Implement Exponential Backoff#
Handle rate limits and transient failures gracefully:
async function retryWithBackoff(fn, maxRetries = 5) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
const waitTime = Math.min(1000 * Math.pow(2, i), 30000);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
}
3. Monitor and Log#
Track gRPC performance metrics:
const call = client.GetObject(request, metadata, callback);
call.on('status', (status) => {
console.log('RPC Status:', status.code, status.details);
});
call.on('metadata', (metadata) => {
console.log('Server metadata:', metadata.getMap());
});
4. Validate Inputs#
Validate request parameters before sending:
function isValidObjectId(id: string): boolean {
return /^0x[a-f0-9]+$/i.test(id);
}
if (!isValidObjectId(objectId)) {
throw new Error('Invalid object ID format');
}
Migration from JSON-RPC#
Transitioning from JSON-RPC to gRPC requires minimal code changes:
| JSON-RPC | gRPC Equivalent |
|---|---|
sui_getObject | LedgerService.GetObject |
suix_getBalance | LiveDataService.GetBalance |
sui_executeTransactionBlock | TransactionService.ExecuteTransaction |
suix_subscribeEvent | SubscriptionService.SubscribeCheckpoints |
Example Migration#
Before (JSON-RPC):
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'sui_getObject',
params: [objectId],
id: 1
})
});
const data = await response.json();
After (gRPC):
const response = await new Promise((resolve, reject) => {
client.GetObject(
{ object_id: objectId },
metadata,
(error, response) => {
if (error) reject(error);
else resolve(response);
}
);
});
Troubleshooting#
Common Issues#
Connection Refused
- Verify port 9000 is used for gRPC
- Check firewall settings allow outbound connections on port 9000
- Ensure TLS credentials are properly configured
Authentication Errors
- Verify API token is correct and active
- Check token is passed in
x-api-keymetadata header - Confirm endpoint URL matches your Dwellir account
Timeout Errors
- Increase request timeout/deadline
- Check network connectivity and latency
- Verify endpoint availability via Dwellir dashboard
Protocol Buffer Errors
- Ensure proto files match server version
- Regenerate client code after proto updates
- Check import paths and dependencies
Support and Resources#
Documentation#
- Ledger Service Methods - Object and transaction queries
- Live Data Service Methods - Real-time state queries
- Subscription Service - Event streaming
Getting Help#
- Email: support@dwellir.com
- Dashboard: dashboard.dwellir.com
- Status Page: Monitor service health and incidents
Additional Resources#
Ready to build with gRPC? Get your API key and experience the performance difference with Dwellir's enterprise-grade Sui infrastructure.