GetPackage
Query Move Package Information#
The GetPackage method retrieves comprehensive information about a Move package deployed on Sui, including all modules, their functions, datatypes, and dependencies. This is essential for smart contract exploration, verification, and building development tools.
Method Signature#
Service: sui.rpc.v2beta2.MovePackageService
Method: GetPackage
Type: Unary RPC
Parameters#
| Parameter | Type | Required | Description |
|---|---|---|---|
package_id | string | Yes | Object ID of the package |
read_mask | FieldMask | No | Fields to include in response |
Field Mask Options#
| Path | Description |
|---|---|
package_id | Package identifier |
version | Package version |
modules | All modules in package |
type_origin_table | Type origin mappings |
linkage_table | Package dependencies |
Response Structure#
message MovePackage {
string package_id = 1;
uint64 version = 2;
map<string, MoveModule> modules = 3;
repeated TypeOrigin type_origin_table = 4;
map<string, UpgradeInfo> linkage_table = 5;
}
message MoveModule {
string name = 1;
repeated MoveFunction functions = 2;
repeated MoveStruct structs = 3;
bytes bytecode = 4;
}
Code Examples#
- TypeScript
- Python
- Go
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
const ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com';
const API_TOKEN = 'your_api_token_here';
const packageDefinition = protoLoader.loadSync('./protos/package.proto', {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs: ['./protos']
});
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition) as any;
const credentials = grpc.credentials.createSsl();
const client = new protoDescriptor.sui.rpc.v2beta2.MovePackageService(ENDPOINT, credentials);
const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_TOKEN);
async function getPackage(packageId: string): Promise<any> {
return new Promise((resolve, reject) => {
const request = {
package_id: packageId,
read_mask: {
paths: ['package_id', 'version', 'modules', 'linkage_table']
}
};
client.GetPackage(request, metadata, (error: any, response: any) => {
if (error) {
console.error('GetPackage error:', error.message);
reject(error);
return;
}
resolve(response);
});
});
}
// Usage - Query Sui Framework
const suiPackage = await getPackage('0x2');
console.log('Package ID:', suiPackage.package_id);
console.log('Version:', suiPackage.version);
console.log('Modules:', Object.keys(suiPackage.modules));
// Explore a specific module
const coinModule = suiPackage.modules['coin'];
if (coinModule) {
console.log('Coin module functions:', coinModule.functions.length);
}
import grpc
from google.protobuf import field_mask_pb2
import package_service_pb2
import package_service_pb2_grpc
ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com'
API_TOKEN = 'your_api_token_here'
def get_package(package_id: str):
credentials = grpc.ssl_channel_credentials()
channel = grpc.secure_channel(ENDPOINT, credentials)
client = package_service_pb2_grpc.MovePackageServiceStub(channel)
request = package_service_pb2.GetPackageRequest(
package_id=package_id,
read_mask=field_mask_pb2.FieldMask(
paths=['package_id', 'version', 'modules']
)
)
metadata = [('x-api-key', API_TOKEN)]
response = client.GetPackage(request, metadata=metadata)
print(f'Package ID: {response.package_id}')
print(f'Version: {response.version}')
print(f'Modules: {list(response.modules.keys())}')
channel.close()
return response
# Usage
package = get_package('0x2')
package main
import (
"context"
"fmt"
"log"
"time"
"sui-grpc-client/config"
pb "sui-grpc-client/sui/rpc/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)
func main() {
// Load configuration from .env file
cfg, err := config.Load()
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// Create TLS credentials
creds := credentials.NewClientTLSFromCert(nil, "")
// Connect to Dwellir
conn, err := grpc.NewClient(
cfg.Endpoint,
grpc.WithTransportCredentials(creds),
)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()
// Create move package service client
client := pb.NewMovePackageServiceClient(conn)
// Add authentication
ctx := metadata.AppendToOutgoingContext(
context.Background(),
"x-api-key", cfg.APIKey,
)
// Set timeout
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
// Example: Get the Sui Framework package (0x2)
packageId := "0x0000000000000000000000000000000000000000000000000000000000000002"
request := &pb.GetPackageRequest{
PackageId: &packageId,
}
response, err := client.GetPackage(ctx, request)
if err != nil {
log.Fatalf("Failed to get package: %v", err)
}
pkg := response.GetPackage()
if pkg == nil {
log.Fatal("No package data returned")
}
// Display package information
fmt.Println("Package Information:")
fmt.Println("====================")
fmt.Printf("Storage ID: %s\n", pkg.GetStorageId())
fmt.Printf("Original ID: %s\n", pkg.GetOriginalId())
fmt.Printf("Version: %d\n", pkg.GetVersion())
// Display modules
modules := pkg.GetModules()
fmt.Printf("\nModules: %d\n", len(modules))
fmt.Println("----------------------")
// Show first 5 modules as examples
maxToShow := 5
if len(modules) < maxToShow {
maxToShow = len(modules)
}
for i := 0; i < maxToShow; i++ {
module := modules[i]
fmt.Printf("\nModule %d: %s\n", i+1, module.GetName())
datatypes := module.GetDatatypes()
functions := module.GetFunctions()
fmt.Printf(" Datatypes: %d\n", len(datatypes))
fmt.Printf(" Functions: %d\n", len(functions))
// Show a few datatypes if available
if len(datatypes) > 0 {
fmt.Printf(" Sample datatypes:\n")
for j := 0; j < len(datatypes) && j < 3; j++ {
dt := datatypes[j]
fmt.Printf(" - %s\n", dt.GetName())
}
}
// Show a few functions if available
if len(functions) > 0 {
fmt.Printf(" Sample functions:\n")
for j := 0; j < len(functions) && j < 3; j++ {
fn := functions[j]
fmt.Printf(" - %s\n", fn.GetName())
}
}
}
if len(modules) > maxToShow {
fmt.Printf("\n... and %d more modules\n", len(modules)-maxToShow)
}
// Display linkage information
linkage := pkg.GetLinkage()
if len(linkage) > 0 {
fmt.Printf("\nPackage Dependencies: %d\n", len(linkage))
}
// Display type origins
typeOrigins := pkg.GetTypeOrigins()
if len(typeOrigins) > 0 {
fmt.Printf("Type Origins: %d\n", len(typeOrigins))
}
}
Use Cases#
Package Explorer#
interface PackageInfo {
id: string;
version: number;
modules: Array<{
name: string;
functionCount: number;
structCount: number;
}>;
dependencies: string[];
}
async function explorePackage(packageId: string): Promise<PackageInfo> {
const pkg = await getPackage(packageId);
const modules = Object.entries(pkg.modules).map(([name, module]: [string, any]) => ({
name,
functionCount: module.functions?.length || 0,
structCount: module.structs?.length || 0
}));
const dependencies = pkg.linkage_table
? Object.keys(pkg.linkage_table)
: [];
return {
id: pkg.package_id,
version: parseInt(pkg.version),
modules,
dependencies
};
}
// Usage
const info = await explorePackage('0x2');
console.log(`Package: ${info.id} (v${info.version})`);
console.log(`Modules: ${info.modules.length}`);
info.modules.forEach(mod => {
console.log(` ${mod.name}: ${mod.functionCount} functions, ${mod.structCount} structs`);
});
Find Function in Package#
interface FunctionInfo {
module: string;
name: string;
visibility: string;
parameters: string[];
returnTypes: string[];
}
async function findFunction(
packageId: string,
functionName: string
): Promise<FunctionInfo | null> {
const pkg = await getPackage(packageId);
for (const [moduleName, module] of Object.entries(pkg.modules)) {
const func = (module as any).functions?.find(
(f: any) => f.name === functionName
);
if (func) {
return {
module: moduleName,
name: func.name,
visibility: func.visibility,
parameters: func.parameters || [],
returnTypes: func.return_ || []
};
}
}
return null;
}
// Usage
const transferFunc = await findFunction('0x2', 'transfer');
if (transferFunc) {
console.log(`Found in module: ${transferFunc.module}`);
console.log(`Visibility: ${transferFunc.visibility}`);
console.log(`Parameters: ${transferFunc.parameters.join(', ')}`);
}
List All Public Functions#
async function listPublicFunctions(packageId: string): Promise<Array<{
module: string;
function: string;
signature: string;
}>> {
const pkg = await getPackage(packageId);
const publicFunctions: any[] = [];
for (const [moduleName, module] of Object.entries(pkg.modules)) {
const functions = (module as any).functions || [];
for (const func of functions) {
if (func.visibility === 'public' || func.visibility === 'public_entry') {
publicFunctions.push({
module: moduleName,
function: func.name,
signature: `${func.name}(${func.parameters?.join(', ') || ''})`
});
}
}
}
return publicFunctions;
}
// Usage
const publicFuncs = await listPublicFunctions('0x2');
console.log('Public functions:');
publicFuncs.forEach(f => {
console.log(` ${f.module}::${f.function}`);
console.log(` ${f.signature}`);
});
Verify Package Dependencies#
async function verifyDependencies(packageId: string): Promise<{
valid: boolean;
missing: string[];
dependencies: Map<string, string>;
}> {
const pkg = await getPackage(packageId);
const dependencies = new Map<string, string>();
const missing: string[] = [];
if (pkg.linkage_table) {
for (const [depId, upgradeInfo] of Object.entries(pkg.linkage_table)) {
try {
const depPkg = await getPackage(depId);
dependencies.set(depId, depPkg.version);
} catch (error) {
console.warn(`Dependency ${depId} not found`);
missing.push(depId);
}
}
}
return {
valid: missing.length === 0,
missing,
dependencies
};
}
// Usage
const verification = await verifyDependencies(packageId);
if (verification.valid) {
console.log('All dependencies verified');
} else {
console.error('Missing dependencies:', verification.missing);
}
Build Function Registry#
interface FunctionRegistry {
[moduleFunction: string]: {
packageId: string;
module: string;
function: string;
visibility: string;
isEntry: boolean;
};
}
async function buildFunctionRegistry(packageId: string): Promise<FunctionRegistry> {
const pkg = await getPackage(packageId);
const registry: FunctionRegistry = {};
for (const [moduleName, module] of Object.entries(pkg.modules)) {
const functions = (module as any).functions || [];
for (const func of functions) {
const key = `${moduleName}::${func.name}`;
registry[key] = {
packageId: pkg.package_id,
module: moduleName,
function: func.name,
visibility: func.visibility,
isEntry: func.is_entry || false
};
}
}
return registry;
}
// Usage
const registry = await buildFunctionRegistry('0x2');
// Quick function lookup
const coinTransfer = registry['coin::transfer'];
if (coinTransfer) {
console.log('Found coin::transfer');
console.log('Visibility:', coinTransfer.visibility);
console.log('Is entry:', coinTransfer.isEntry);
}
Package Version Comparison#
async function comparePackageVersions(
packageId1: string,
packageId2: string
): Promise<{
modulesAdded: string[];
modulesRemoved: string[];
modulesModified: string[];
}> {
const [pkg1, pkg2] = await Promise.all([
getPackage(packageId1),
getPackage(packageId2)
]);
const modules1 = new Set(Object.keys(pkg1.modules));
const modules2 = new Set(Object.keys(pkg2.modules));
const modulesAdded = Array.from(modules2).filter(m => !modules1.has(m));
const modulesRemoved = Array.from(modules1).filter(m => !modules2.has(m));
const modulesModified: string[] = [];
for (const moduleName of modules1) {
if (modules2.has(moduleName)) {
const mod1 = pkg1.modules[moduleName];
const mod2 = pkg2.modules[moduleName];
// Compare bytecode or function counts
if (mod1.bytecode !== mod2.bytecode) {
modulesModified.push(moduleName);
}
}
}
return { modulesAdded, modulesRemoved, modulesModified };
}
Best Practices#
Cache Package Data#
class PackageCache {
private cache = new Map<string, { data: any; timestamp: number }>();
private ttl = 3600000; // 1 hour (packages rarely change)
async getPackage(packageId: string): Promise<any> {
const cached = this.cache.get(packageId);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.data;
}
const pkg = await getPackage(packageId);
this.cache.set(packageId, {
data: pkg,
timestamp: Date.now()
});
return pkg;
}
clear(): void {
this.cache.clear();
}
}
// Usage
const cache = new PackageCache();
const pkg = await cache.getPackage('0x2'); // Network request
const pkg2 = await cache.getPackage('0x2'); // Cached
Handle Package Upgrades#
async function getPackageWithUpgradeCheck(packageId: string): Promise<{
package: any;
hasUpgrade: boolean;
latestVersion?: string;
}> {
const pkg = await getPackage(packageId);
// Check if there's a newer version
// (Implementation depends on your upgrade tracking mechanism)
return {
package: pkg,
hasUpgrade: false, // Implement upgrade detection logic
latestVersion: pkg.version
};
}
Error Handling#
async function getPackageSafe(packageId: string): Promise<any | null> {
try {
return await getPackage(packageId);
} catch (error: any) {
if (error.code === grpc.status.NOT_FOUND) {
console.warn(`Package ${packageId} not found`);
return null;
}
if (error.code === grpc.status.INVALID_ARGUMENT) {
console.error(`Invalid package ID: ${packageId}`);
return null;
}
throw error;
}
}
Performance Characteristics#
| Metric | Value |
|---|---|
| Typical Latency | 30-80ms |
| Response Size | 10-500KB (varies by package size) |
| Cache Recommended | Yes (long TTL) |
| Rate Limit Impact | Medium |
Common Sui Framework Packages#
| Package | ID | Description |
|---|---|---|
| Sui Framework | 0x2 | Core Sui types and functions |
| Move Stdlib | 0x1 | Standard library |
| DeepBook | 0xdee9 | On-chain orderbook |
Common Errors#
| Error Code | Scenario | Solution |
|---|---|---|
NOT_FOUND | Package doesn't exist | Verify package ID |
INVALID_ARGUMENT | Invalid package ID format | Check ID format |
UNAUTHENTICATED | Missing/invalid token | Verify x-api-key header |
Related Methods#
- GetFunction - Query specific function details
- GetDatatype - Query struct/type details
Need help? Contact support@dwellir.com or check the gRPC overview.