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
MoveCalltransaction 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
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
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
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
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
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
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
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
| Metric | Value |
|---|---|
| Typical Latency | 15-40ms |
| Response Size | 200-2000 bytes |
| Cache Recommended | Yes (long TTL) |
| Rate Limit Impact | Low |
Common Errors
| Error Code | Scenario | Solution |
|---|---|---|
NOT_FOUND | Function doesn't exist | Verify package, module, and function names |
INVALID_ARGUMENT | Invalid names | Check naming format |
UNAUTHENTICATED | Missing/invalid token | Verify x-api-key header |
Related Methods
- GetPackage - Query entire package
- GetDatatype - Query struct definitions
Need help? Contact support@dwellir.com or check the gRPC overview.
GetDatatype
Retrieve Move struct and datatype definitions via gRPC including fields and type parameters. Essential for understanding smart contract data structures with Dwellir.
GetPackage
Retrieve comprehensive Move package information via gRPC including modules, functions, and datatypes. Essential for smart contract exploration with Dwellir.