Docs

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

TypeScript
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

TypeScript
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

TypeScript
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

TypeScript
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

TypeScript
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

TypeScript
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

TypeScript
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

TypeScript
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

TypeScript
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.