Docs

suix_getDynamicFields - Query Dynamic Ob...

Query dynamic object fields on Sui blockchain. Access dynamic field data and nested object structures with Dwellir's high-performance Sui RPC infrastructure.

Returns the list of dynamic field objects owned by an object on the Sui network.

Overview

The suix_getDynamicFields method allows you to query dynamic fields attached to any Sui object. Dynamic fields provide a way to add heterogeneous data to objects after creation, enabling flexible data structures and extensible object designs. This method is essential for exploring complex object hierarchies and understanding object relationships in Sui applications.

Code Examples

Practical Examples

Dynamic Field Manager

JavaScript
class DynamicFieldManager {
  constructor(client) {
    this.client = client;
    this.fieldCache = new Map();
  }
  
  async getFieldsStructure(parentId, useCache = true) {
    const cacheKey = `fields_${parentId}`;
    
    if (useCache && this.fieldCache.has(cacheKey)) {
      return this.fieldCache.get(cacheKey);
    }
    
    const fields = await this.getAllDynamicFields(parentId);
    
    const structure = {
      parentId: parentId,
      totalFields: fields.length,
      fieldsByType: this.groupFieldsByType(fields),
      fieldsByName: this.groupFieldsByName(fields),
      metadata: {
        lastUpdated: Date.now(),
        versions: fields.map(f => parseInt(f.version))
      }
    };
    
    if (useCache) {
      this.fieldCache.set(cacheKey, structure);
    }
    
    return structure;
  }
  
  groupFieldsByType(fields) {
    return fields.reduce((acc, field) => {
      const type = field.objectType;
      if (!acc[type]) {
        acc[type] = [];
      }
      acc[type].push(field);
      return acc;
    }, {});
  }
  
  groupFieldsByName(fields) {
    return fields.reduce((acc, field) => {
      const nameKey = this.getFieldNameKey(field.name);
      acc[nameKey] = field;
      return acc;
    }, {});
  }
  
  getFieldNameKey(name) {
    if (typeof name === 'string') return name;
    if (name && name.value) return name.value.toString();
    return JSON.stringify(name);
  }
  
  async getAllDynamicFields(parentId) {
    let allFields = [];
    let cursor = null;
    let hasNextPage = true;
    
    while (hasNextPage) {
      const result = await this.client.getDynamicFields({
        parentId: parentId,
        cursor: cursor,
        limit: 50
      });
      
      allFields = allFields.concat(result.data);
      cursor = result.nextCursor;
      hasNextPage = result.hasNextPage;
    }
    
    return allFields;
  }
}

Field Value Resolver

JavaScript
class FieldValueResolver {
  constructor(client) {
    this.client = client;
    this.valueCache = new Map();
  }
  
  async resolveFieldValues(parentId, fieldNames = []) {
    const fields = await this.client.getDynamicFields({ parentId });
    const resolved = {};
    
    for (const field of fields.data) {
      const nameKey = this.getFieldNameKey(field.name);
      
      // If specific fields requested, filter
      if (fieldNames.length > 0 && !fieldNames.includes(nameKey)) {
        continue;
      }
      
      try {
        const value = await this.getFieldValue(field.objectId);
        resolved[nameKey] = {
          field: field,
          value: value,
          resolved: true
        };
      } catch (error) {
        resolved[nameKey] = {
          field: field,
          error: error.message,
          resolved: false
        };
      }
    }
    
    return resolved;
  }
  
  async getFieldValue(fieldObjectId, useCache = true) {
    if (useCache && this.valueCache.has(fieldObjectId)) {
      return this.valueCache.get(fieldObjectId);
    }
    
    const fieldObject = await this.client.getObject({
      id: fieldObjectId,
      options: {
        showType: true,
        showContent: true,
        showBcs: true
      }
    });
    
    if (fieldObject && fieldObject.data) {
      if (useCache) {
        this.valueCache.set(fieldObjectId, fieldObject.data);
      }
      return fieldObject.data;
    }
    
    return null;
  }
  
  getFieldNameKey(name) {
    if (typeof name === 'string') return name;
    if (name && name.value !== undefined) return name.value.toString();
    return JSON.stringify(name);
  }
}

Dynamic Object Inspector

JavaScript
class DynamicObjectInspector {
  constructor(client) {
    this.client = client;
  }
  
  async inspectObject(objectId, options = {}) {
    const {
      includeFieldValues = false,
      maxFieldsToInspect = 20,
      includeTypeAnalysis = true
    } = options;
    
    try {
      // Get object info
      const objectInfo = await this.client.getObject({
        id: objectId,
        options: { showType: true, showContent: true }
      });
      
      // Get dynamic fields
      const fieldsResult = await this.client.getDynamicFields({
        parentId: objectId,
        limit: maxFieldsToInspect
      });
      
      const inspection = {
        objectId: objectId,
        objectType: objectInfo.data?.type,
        objectVersion: objectInfo.data?.version,
        dynamicFieldsCount: fieldsResult.data.length,
        hasMoreFields: fieldsResult.hasNextPage,
        fields: fieldsResult.data
      };
      
      if (includeTypeAnalysis) {
        inspection.typeAnalysis = this.analyzeFieldTypes(fieldsResult.data);
      }
      
      if (includeFieldValues) {
        inspection.fieldValues = {};
        
        for (const field of fieldsResult.data.slice(0, 10)) { // Limit to first 10
          try {
            const value = await this.client.getObject({
              id: field.objectId,
              options: { showContent: true }
            });
            
            const nameKey = this.getFieldNameKey(field.name);
            inspection.fieldValues[nameKey] = value.data;
          } catch (error) {
            console.warn(`Failed to get value for field ${field.objectId}:`, error);
          }
        }
      }
      
      return inspection;
      
    } catch (error) {
      return {
        objectId: objectId,
        error: error.message,
        timestamp: Date.now()
      };
    }
  }
  
  analyzeFieldTypes(fields) {
    const typeCount = {};
    const nameTypes = {};
    
    fields.forEach(field => {
      // Count object types
      const objType = field.objectType;
      typeCount[objType] = (typeCount[objType] || 0) + 1;
      
      // Analyze name types
      const nameType = typeof field.name === 'object' ? 
        field.name.type || 'object' : typeof field.name;
      nameTypes[nameType] = (nameTypes[nameType] || 0) + 1;
    });
    
    return {
      objectTypes: typeCount,
      nameTypes: nameTypes,
      totalFields: fields.length,
      uniqueTypes: Object.keys(typeCount).length
    };
  }
  
  getFieldNameKey(name) {
    if (typeof name === 'string') return name;
    if (name && name.value !== undefined) return name.value.toString();
    return JSON.stringify(name);
  }
  
  async compareObjects(objectIds) {
    const comparisons = [];
    
    for (const objectId of objectIds) {
      const inspection = await this.inspectObject(objectId, {
        includeTypeAnalysis: true,
        includeFieldValues: false
      });
      comparisons.push(inspection);
    }
    
    return {
      objects: comparisons,
      comparison: {
        totalObjects: comparisons.length,
        averageFieldsPerObject: comparisons.reduce(
          (sum, obj) => sum + (obj.dynamicFieldsCount || 0), 0
        ) / comparisons.length,
        commonTypes: this.findCommonTypes(comparisons),
        uniquePatterns: this.findUniquePatterns(comparisons)
      }
    };
  }
  
  findCommonTypes(comparisons) {
    const allTypes = new Set();
    comparisons.forEach(comp => {
      if (comp.typeAnalysis) {
        Object.keys(comp.typeAnalysis.objectTypes).forEach(type => 
          allTypes.add(type)
        );
      }
    });
    
    const commonTypes = {};
    allTypes.forEach(type => {
      const count = comparisons.filter(comp => 
        comp.typeAnalysis?.objectTypes[type] > 0
      ).length;
      
      if (count > 1) {
        commonTypes[type] = count;
      }
    });
    
    return commonTypes;
  }
  
  findUniquePatterns(comparisons) {
    const patterns = [];
    
    comparisons.forEach(comp => {
      if (comp.typeAnalysis) {
        const uniqueTypes = Object.keys(comp.typeAnalysis.objectTypes).filter(
          type => {
            const appearsInOthers = comparisons.some(other => 
              other !== comp && other.typeAnalysis?.objectTypes[type] > 0
            );
            return !appearsInOthers;
          }
        );
        
        if (uniqueTypes.length > 0) {
          patterns.push({
            objectId: comp.objectId,
            uniqueTypes: uniqueTypes
          });
        }
      }
    });
    
    return patterns;
  }
}

Best Practices

  1. Use Pagination: Always handle pagination for objects with many dynamic fields
  2. Cache Results: Cache field information when exploring object hierarchies
  3. Handle Large Objects: Be mindful of objects with hundreds of dynamic fields
  4. Validate Field Names: Handle different field name formats (strings, objects, numbers)
  5. Implement Retries: Network requests can fail, implement retry logic
  6. Limit Depth: When exploring recursively, set reasonable depth limits

Need help? Contact our support team or check the Sui documentation.