Skip to main content

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#

ParameterTypeRequiredDescription
package_idstringYesObject ID of the package
read_maskFieldMaskNoFields to include in response

Field Mask Options#

PathDescription
package_idPackage identifier
versionPackage version
modulesAll modules in package
type_origin_tableType origin mappings
linkage_tablePackage 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#

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);
}

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#

MetricValue
Typical Latency30-80ms
Response Size10-500KB (varies by package size)
Cache RecommendedYes (long TTL)
Rate Limit ImpactMedium

Common Sui Framework Packages#

PackageIDDescription
Sui Framework0x2Core Sui types and functions
Move Stdlib0x1Standard library
DeepBook0xdee9On-chain orderbook

Common Errors#

Error CodeScenarioSolution
NOT_FOUNDPackage doesn't existVerify package ID
INVALID_ARGUMENTInvalid package ID formatCheck ID format
UNAUTHENTICATEDMissing/invalid tokenVerify x-api-key header

Need help? Contact support@dwellir.com or check the gRPC overview.