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#
| Parameter | Type | Required | Description |
|---|---|---|---|
package_id | string | Yes | Package object ID |
module_name | string | Yes | Module name within package |
function_name | string | Yes | Function 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#
- TypeScript
- Python
- Go
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);
import grpc
import package_service_pb2
import package_service_pb2_grpc
ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com'
API_TOKEN = 'your_api_token_here'
def get_function(package_id: str, module_name: str, function_name: str):
credentials = grpc.ssl_channel_credentials()
channel = grpc.secure_channel(ENDPOINT, credentials)
client = package_service_pb2_grpc.MovePackageServiceStub(channel)
request = package_service_pb2.GetFunctionRequest(
package_id=package_id,
module_name=module_name,
function_name=function_name
)
metadata = [('x-api-key', API_TOKEN)]
response = client.GetFunction(request, metadata=metadata)
print(f'Function: {response.name}')
print(f'Visibility: {response.visibility}')
print(f'Is Entry: {response.is_entry}')
print(f'Parameters: {len(response.parameters)}')
channel.close()
return response
# Usage
func = get_function('0x2', 'coin', 'transfer')
package main
import (
"context"
"fmt"
"log"
"time"
"sui-grpc-client/config"
pb "sui-grpc-client/sui/rpc/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)
func main() {
// Load configuration from .env file
cfg, err := config.Load()
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// Create TLS credentials
creds := credentials.NewClientTLSFromCert(nil, "")
// Connect to Dwellir
conn, err := grpc.NewClient(
cfg.Endpoint,
grpc.WithTransportCredentials(creds),
)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()
// Create move package service client
client := pb.NewMovePackageServiceClient(conn)
// Add authentication
ctx := metadata.AppendToOutgoingContext(
context.Background(),
"x-api-key", cfg.APIKey,
)
// Set timeout
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
// Example: Get the transfer function from the Sui Framework (0x2::transfer::transfer)
packageId := "0x0000000000000000000000000000000000000000000000000000000000000002"
moduleName := "transfer"
functionName := "transfer"
request := &pb.GetFunctionRequest{
PackageId: &packageId,
ModuleName: &moduleName,
Name: &functionName,
}
response, err := client.GetFunction(ctx, request)
if err != nil {
log.Fatalf("Failed to get function: %v", err)
}
function := response.GetFunction()
if function == nil {
log.Fatal("No function data returned")
}
// Display function information
fmt.Println("Function Information:")
fmt.Println("=====================")
fmt.Printf("Name: %s\n", function.GetName())
// Display visibility
visibility := function.GetVisibility()
switch visibility {
case pb.FunctionDescriptor_PUBLIC:
fmt.Printf("Visibility: PUBLIC\n")
case pb.FunctionDescriptor_PRIVATE:
fmt.Printf("Visibility: PRIVATE\n")
case pb.FunctionDescriptor_FRIEND:
fmt.Printf("Visibility: FRIEND\n")
default:
fmt.Printf("Visibility: UNKNOWN\n")
}
// Display entry function status
fmt.Printf("Is Entry: %v\n", function.GetIsEntry())
// Display type parameters
typeParams := function.GetTypeParameters()
if len(typeParams) > 0 {
fmt.Printf("\nType Parameters: %d\n", len(typeParams))
for i, param := range typeParams {
fmt.Printf(" Parameter %d:\n", i+1)
if len(param.GetConstraints()) > 0 {
fmt.Printf(" Constraints: ")
for j, constraint := range param.GetConstraints() {
if j > 0 {
fmt.Printf(", ")
}
switch constraint {
case pb.Ability_COPY:
fmt.Printf("COPY")
case pb.Ability_DROP:
fmt.Printf("DROP")
case pb.Ability_STORE:
fmt.Printf("STORE")
case pb.Ability_KEY:
fmt.Printf("KEY")
}
}
fmt.Println()
}
}
}
// Display parameters
parameters := function.GetParameters()
if len(parameters) > 0 {
fmt.Printf("\nParameters: %d\n", len(parameters))
for i, param := range parameters {
fmt.Printf(" %d. ", i+1)
// Display reference type
ref := param.GetReference()
switch ref {
case pb.OpenSignature_IMMUTABLE:
fmt.Printf("&")
case pb.OpenSignature_MUTABLE:
fmt.Printf("&mut ")
}
// Display parameter type
if body := param.GetBody(); body != nil {
displayType(body)
}
fmt.Println()
}
}
// Display return types
returns := function.GetReturns()
if len(returns) > 0 {
fmt.Printf("\nReturn Types: %d\n", len(returns))
for i, ret := range returns {
fmt.Printf(" %d. ", i+1)
if body := ret.GetBody(); body != nil {
displayType(body)
}
fmt.Println()
}
}
}
func displayType(body *pb.OpenSignatureBody) {
t := body.GetType()
switch t {
case pb.OpenSignatureBody_ADDRESS:
fmt.Printf("address")
case pb.OpenSignatureBody_BOOL:
fmt.Printf("bool")
case pb.OpenSignatureBody_U8:
fmt.Printf("u8")
case pb.OpenSignatureBody_U16:
fmt.Printf("u16")
case pb.OpenSignatureBody_U32:
fmt.Printf("u32")
case pb.OpenSignatureBody_U64:
fmt.Printf("u64")
case pb.OpenSignatureBody_U128:
fmt.Printf("u128")
case pb.OpenSignatureBody_U256:
fmt.Printf("u256")
case pb.OpenSignatureBody_VECTOR:
fmt.Printf("vector<")
typeParams := body.GetTypeParameterInstantiation()
if len(typeParams) > 0 {
displayType(typeParams[0])
}
fmt.Printf(">")
case pb.OpenSignatureBody_DATATYPE:
fmt.Printf("%s", body.GetTypeName())
typeParams := body.GetTypeParameterInstantiation()
if len(typeParams) > 0 {
fmt.Printf("<")
for i, tp := range typeParams {
if i > 0 {
fmt.Printf(", ")
}
displayType(tp)
}
fmt.Printf(">")
}
case pb.OpenSignatureBody_TYPE_PARAMETER:
fmt.Printf("T%d", body.GetTypeParameter())
default:
fmt.Printf("unknown")
}
}
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.