Skip to main content

GetFunction

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.

Method Signature#

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

Parameters#

ParameterTypeRequiredDescription
package_idstringYesPackage object ID
module_namestringYesModule name within package
function_namestringYesFunction name within module

Response Structure#

message MoveFunction {
string name = 1;
MoveVisibility visibility = 2;
bool is_entry = 3;
repeated MoveType type_parameters = 4;
repeated MoveType parameters = 5;
repeated MoveType return_ = 6;
}

enum MoveVisibility {
PRIVATE = 0;
PUBLIC = 1;
FRIEND = 2;
}

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 getFunction(
packageId: string,
moduleName: string,
functionName: string
): Promise<any> {
return new Promise((resolve, reject) => {
const request = {
package_id: packageId,
module_name: moduleName,
function_name: functionName
};

client.GetFunction(request, metadata, (error: any, response: any) => {
if (error) {
console.error('GetFunction error:', error.message);
reject(error);
return;
}

resolve(response);
});
});
}

// Usage - Query coin::transfer function
const transferFunc = await getFunction('0x2', 'coin', 'transfer');

console.log('Function:', transferFunc.name);
console.log('Visibility:', transferFunc.visibility);
console.log('Is Entry:', transferFunc.is_entry);
console.log('Parameters:', transferFunc.parameters.length);
console.log('Returns:', transferFunc.return_.length);

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#

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.