GetPackage - Query Move Package Details
Retrieve comprehensive Move package information via gRPC including modules, functions, and datatypes. Essential for smart contract exploration with Dwellir.
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.
Overview
Move packages are the deployment units for smart contracts on Sui. Each package contains one or more modules, and each module defines functions, structs, and constants. The GetPackage method provides a complete view of a deployed package, allowing you to enumerate all modules, discover their public interfaces, inspect struct definitions, and trace package dependencies.
Sui's package system supports immutable publishing and upgradeable packages. When a package is upgraded, a new version is published with a new object ID, but the original ID is preserved in the type origin table for backward compatibility. The linkage table maps dependencies to their resolved versions, ensuring consistent type resolution across the ecosystem.
Key Capabilities
- Module Enumeration: List all modules within a package with their functions and datatypes
- Dependency Resolution: Inspect the linkage table to understand which packages this package depends on
- Type Origin Tracking: Trace where types were originally defined across package upgrade chains
- Package Verification: Compare on-chain bytecode against local source compilation
- Explorer Building: Provide complete package browsing for developer tools and block explorers
- Version Analysis: Compare different package versions to detect added, removed, or modified modules
Method Signature
Service: sui.rpc.v2.MovePackageService
Method: GetPackage
Type: Unary RPC
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'); // CachedHandle 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.
GetFunction
Retrieve detailed Move function information via gRPC including parameters, return types, and visibility. Essential for smart contract integration with Dwellir.
VerifySignature
Verify cryptographic signatures for Sui transactions via gRPC. Essential for security validation and multi-sig workflows with Dwellir.