Docs

GetFunction - Query Move Function Details

Retrieve detailed Move function information via gRPC including parameters, return types, and visibility. Essential for smart contract integration with Dwellir.

Query Move Function Details

The GetFunction method retrieves detailed information about a specific function in a Move module, including its signature, parameters, return types, visibility, and whether it's an entry function. This is essential for building transaction calls and understanding smart contract interfaces.

Overview

Move functions are the executable units of smart contracts on Sui. The GetFunction method lets you introspect any deployed function's signature, including its parameters, return types, visibility level, type parameters, and whether it can be called directly as a transaction entry point. This is the foundation for building dynamic transaction constructors, smart contract explorers, and developer tooling.

A key concept on Sui is the distinction between entry functions (callable directly in transactions) and non-entry functions (only callable from other Move code). The is_entry flag in the response tells you whether a function can be invoked from a MoveCall transaction command. Combined with visibility information (public, private, friend), this lets applications automatically determine which functions are available for external interaction.

Key Capabilities

  • Signature Introspection: Retrieve complete function signatures including all parameter and return types
  • Entry Point Detection: Determine which functions can be called directly from transactions
  • Visibility Checking: Verify whether a function is public, private, or friend-scoped
  • Type Parameter Discovery: Inspect generic type parameters and their ability constraints
  • Transaction Building: Use function metadata to construct valid MoveCall transaction commands
  • ABI Generation: Automatically generate client-side bindings from on-chain function definitions

Method Signature

Service: sui.rpc.v2.MovePackageService Method: GetFunction Type: Unary RPC

Use Cases

Build Function Signature

TypeScript
function buildFunctionSignature(func: any): string {
  const typeParams = func.type_parameters?.length > 0
    ? `<${func.type_parameters.map((t: any) => t.toString()).join(', ')}>`
    : '';

  const params = func.parameters
    .map((p: any, i: number) => `arg${i}: ${p}`)
    .join(', ');

  const returns = func.return_?.length > 0
    ? `: (${func.return_.join(', ')})`
    : '';

  return `${func.name}${typeParams}(${params})${returns}`;
}

// Usage
const func = await getFunction('0x2', 'coin', 'transfer');
const signature = buildFunctionSignature(func);

console.log(signature);
// Output: transfer<T>(arg0: &mut Coin<T>, arg1: u64, arg2: &mut TxContext): ()

Validate Function Call

TypeScript
interface FunctionCallValidation {
  isValid: boolean;
  errors: string[];
  canCall: boolean;
}

async function validateFunctionCall(
  packageId: string,
  moduleName: string,
  functionName: string,
  args: any[]
): Promise<FunctionCallValidation> {
  const result: FunctionCallValidation = {
    isValid: false,
    errors: [],
    canCall: false
  };

  try {
    const func = await getFunction(packageId, moduleName, functionName);

    // Check if function is entry point
    if (!func.is_entry) {
      result.errors.push('Function is not an entry function');
    }

    // Check visibility
    if (func.visibility !== 'PUBLIC') {
      result.errors.push(`Function visibility is ${func.visibility}, must be PUBLIC`);
    }

    // Check argument count
    if (args.length !== func.parameters.length) {
      result.errors.push(
        `Expected ${func.parameters.length} arguments, got ${args.length}`
      );
    }

    result.isValid = result.errors.length === 0;
    result.canCall = func.is_entry && func.visibility === 'PUBLIC';

    return result;

  } catch (error: any) {
    result.errors.push(`Function lookup failed: ${error.message}`);
    return result;
  }
}

// Usage
const validation = await validateFunctionCall(
  '0x2',
  'coin',
  'transfer',
  [coinObject, amount, recipient]
);

if (!validation.canCall) {
  console.error('Cannot call function:', validation.errors);
}

Generate Transaction Builder

TypeScript
async function generateTransactionBuilder(
  packageId: string,
  moduleName: string,
  functionName: string
): Promise<string> {
  const func = await getFunction(packageId, moduleName, functionName);

  const params = func.parameters
    .map((p: any, i: number) => `arg${i}: ${p}`)
    .join(', ');

  const typeParams = func.type_parameters?.length > 0
    ? `<${func.type_parameters.map((t: any) => t.toString()).join(', ')}>`
    : '';

  return `
async function call${func.name}${typeParams}(${params}) {
  const tx = new Transaction();

  tx.moveCall({
    target: '${packageId}::${moduleName}::${func.name}',
    arguments: [${func.parameters.map((_, i) => `arg${i}`).join(', ')}],
    typeArguments: [/* Add type arguments */]
  });

  return tx;
}
`;
}

// Usage
const builder = await generateTransactionBuilder('0x2', 'coin', 'transfer');
console.log(builder);

Function Documentation Generator

TypeScript
interface FunctionDocs {
  name: string;
  signature: string;
  description: string;
  parameters: Array<{
    name: string;
    type: string;
  }>;
  returns: string[];
  visibility: string;
  isEntry: boolean;
}

async function generateFunctionDocs(
  packageId: string,
  moduleName: string,
  functionName: string
): Promise<FunctionDocs> {
  const func = await getFunction(packageId, moduleName, functionName);

  return {
    name: func.name,
    signature: buildFunctionSignature(func),
    description: `${func.visibility} function in ${moduleName} module`,
    parameters: func.parameters.map((type: any, i: number) => ({
      name: `arg${i}`,
      type: type.toString()
    })),
    returns: func.return_ || [],
    visibility: func.visibility,
    isEntry: func.is_entry
  };
}

// Usage
const docs = await generateFunctionDocs('0x2', 'coin', 'transfer');

console.log(`# ${docs.name}\n`);
console.log(`**Signature:** \`${docs.signature}\`\n`);
console.log(`**Visibility:** ${docs.visibility}`);
console.log(`**Entry Function:** ${docs.isEntry}\n`);
console.log(`## Parameters\n`);
docs.parameters.forEach(param => {
  console.log(`- \`${param.name}\`: ${param.type}`);
});

Build Smart Contract Interface

TypeScript
interface ContractInterface {
  [functionName: string]: {
    signature: string;
    isCallable: boolean;
    parameterTypes: string[];
    returnTypes: string[];
  };
}

async function buildContractInterface(
  packageId: string,
  moduleName: string,
  functionNames: string[]
): Promise<ContractInterface> {
  const interface_: ContractInterface = {};

  await Promise.all(
    functionNames.map(async (funcName) => {
      try {
        const func = await getFunction(packageId, moduleName, funcName);

        interface_[funcName] = {
          signature: buildFunctionSignature(func),
          isCallable: func.is_entry && func.visibility === 'PUBLIC',
          parameterTypes: func.parameters,
          returnTypes: func.return_ || []
        };
      } catch (error) {
        console.warn(`Could not load function ${funcName}`);
      }
    })
  );

  return interface_;
}

// Usage
const contractInterface = await buildContractInterface(
  '0x2',
  'coin',
  ['transfer', 'split', 'join', 'zero']
);

console.log('Contract Interface:');
for (const [name, details] of Object.entries(contractInterface)) {
  console.log(`${name}: ${details.signature}`);
  console.log(`  Callable: ${details.isCallable}`);
}

Best Practices

Cache Function Metadata

TypeScript
class FunctionCache {
  private cache = new Map<string, { data: any; timestamp: number }>();
  private ttl = 3600000; // 1 hour

  async getFunction(
    packageId: string,
    moduleName: string,
    functionName: string
  ): Promise<any> {
    const key = `${packageId}::${moduleName}::${functionName}`;
    const cached = this.cache.get(key);

    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }

    const func = await getFunction(packageId, moduleName, functionName);

    this.cache.set(key, {
      data: func,
      timestamp: Date.now()
    });

    return func;
  }
}

Handle Missing Functions

TypeScript
async function getFunctionSafe(
  packageId: string,
  moduleName: string,
  functionName: string
): Promise<any | null> {
  try {
    return await getFunction(packageId, moduleName, functionName);
  } catch (error: any) {
    if (error.code === grpc.status.NOT_FOUND) {
      console.warn(`Function ${moduleName}::${functionName} not found in package ${packageId}`);
      return null;
    }

    throw error;
  }
}

Performance Characteristics

MetricValue
Typical Latency15-40ms
Response Size200-2000 bytes
Cache RecommendedYes (long TTL)
Rate Limit ImpactLow

Common Errors

Error CodeScenarioSolution
NOT_FOUNDFunction doesn't existVerify package, module, and function names
INVALID_ARGUMENTInvalid namesCheck naming format
UNAUTHENTICATEDMissing/invalid tokenVerify x-api-key header

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