suix_getOwnedObjects
Returns a paginated list of all objects owned by a specific address on the Sui network, with support for filtering by object type.
Overview​
The suix_getOwnedObjects
method is essential for querying all objects owned by an address. In Sui's object-centric model, everything is represented as objects - coins, NFTs, smart contracts, and custom data structures. This method allows you to discover and enumerate all objects belonging to a specific address, making it crucial for wallet implementations, portfolio trackers, and analytics tools.
Parameters​
Parameter | Type | Required | Description |
---|---|---|---|
owner | string | Yes | The Sui address to query (66-character hex string with 0x prefix) |
query | object | No | Query options for filtering and pagination |
cursor | string | No | Pagination cursor from previous response |
limit | number | No | Maximum number of objects to return (default: 50, max: 200) |
Query Object​
Field | Type | Description |
---|---|---|
MatchAll | array | Match all specified filters |
MatchAny | array | Match any of the specified filters |
MatchNone | array | Exclude objects matching these filters |
Filter Options​
Filter Type | Description | Example |
---|---|---|
StructType | Filter by Move struct type | "0x2::coin::Coin<0x2::sui::SUI>" |
AddressOwner | Filter by address owner | Address string |
ObjectOwner | Filter by object owner | Object ID string |
ObjectId | Filter by specific object ID | Object ID string |
Version | Filter by object version | Version number |
Returns​
Returns an object containing the paginated list of owned objects.
Field | Type | Description |
---|---|---|
data | array | Array of object information |
nextCursor | string | Cursor for next page (null if no more pages) |
hasNextPage | boolean | Whether more pages are available |
Object Information Structure​
Field | Type | Description |
---|---|---|
objectId | string | Unique identifier of the object |
version | string | Current version of the object |
digest | string | Object content digest |
type | string | Move type of the object |
owner | object | Ownership information |
previousTransaction | string | Previous transaction digest |
storageRebate | string | Storage rebate amount |
display | object | Display metadata (if available) |
content | object | Object's fields and values (if requested) |
Code Examples​
- cURL
- JavaScript
- Python
# Get all owned objects (basic query)
curl -X POST https://sui-mainnet.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_getOwnedObjects",
"params": [
"0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f"
],
"id": 1
}'
# Get only SUI coin objects
curl -X POST https://sui-mainnet.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_getOwnedObjects",
"params": [
"0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f",
{
"filter": {
"StructType": "0x2::coin::Coin<0x2::sui::SUI>"
}
},
null,
50
],
"id": 1
}'
# Get objects with content and display info
curl -X POST https://sui-mainnet.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_getOwnedObjects",
"params": [
"0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f",
{
"filter": null,
"options": {
"showType": true,
"showOwner": true,
"showPreviousTransaction": true,
"showDisplay": true,
"showContent": true,
"showBcs": false,
"showStorageRebate": true
}
},
null,
25
],
"id": 1
}'
import { SuiClient } from '@mysten/sui.js/client';
const client = new SuiClient({
url: 'https://sui-mainnet.dwellir.com/YOUR_API_KEY'
});
// Get all owned objects
async function getAllOwnedObjects(address) {
const result = await client.getOwnedObjects({
owner: address,
options: {
showType: true,
showOwner: true,
showContent: true,
showDisplay: true
}
});
console.log(`Found ${result.data.length} objects`);
return result;
}
// Get specific object type (e.g., SUI coins)
async function getSUICoins(address) {
const result = await client.getOwnedObjects({
owner: address,
filter: {
StructType: '0x2::coin::Coin<0x2::sui::SUI>'
},
options: {
showContent: true
}
});
const coins = result.data.map(obj => ({
objectId: obj.data?.objectId,
balance: obj.data?.content?.fields?.balance,
version: obj.data?.version
}));
return coins;
}
// Get all objects with pagination
async function getAllObjectsPaginated(address, maxPages = 10) {
let allObjects = [];
let cursor = null;
let pageCount = 0;
while (pageCount < maxPages) {
const result = await client.getOwnedObjects({
owner: address,
cursor: cursor,
limit: 50,
options: {
showType: true,
showContent: true
}
});
allObjects.push(...result.data);
console.log(`Page ${pageCount + 1}: ${result.data.length} objects`);
if (!result.hasNextPage) break;
cursor = result.nextCursor;
pageCount++;
}
return allObjects;
}
// Categorize owned objects by type
async function categorizeOwnedObjects(address) {
const allObjects = await getAllObjectsPaginated(address);
const categories = {
coins: [],
nfts: [],
packages: [],
other: []
};
allObjects.forEach(obj => {
const type = obj.data?.type || '';
if (type.includes('::coin::Coin<')) {
categories.coins.push({
objectId: obj.data.objectId,
coinType: type.match(/<(.+)>/)?.[1] || 'Unknown',
balance: obj.data.content?.fields?.balance || '0'
});
} else if (type.includes('::nft::') || obj.data?.display) {
categories.nfts.push({
objectId: obj.data.objectId,
type: type,
name: obj.data.display?.data?.name || 'Unknown NFT',
description: obj.data.display?.data?.description || '',
imageUrl: obj.data.display?.data?.image_url || ''
});
} else if (type.includes('::package::')) {
categories.packages.push({
objectId: obj.data.objectId,
type: type
});
} else {
categories.other.push({
objectId: obj.data.objectId,
type: type
});
}
});
return {
summary: {
totalObjects: allObjects.length,
coinObjects: categories.coins.length,
nftObjects: categories.nfts.length,
packageObjects: categories.packages.length,
otherObjects: categories.other.length
},
categories: categories
};
}
// Portfolio analysis
async function analyzePortfolio(address) {
const objects = await categorizeOwnedObjects(address);
// Analyze coin balances
const coinAnalysis = {};
let totalSUIBalance = 0;
objects.categories.coins.forEach(coin => {
const coinType = coin.coinType;
const balance = parseInt(coin.balance || '0');
if (!coinAnalysis[coinType]) {
coinAnalysis[coinType] = {
totalBalance: 0,
objectCount: 0,
objects: []
};
}
coinAnalysis[coinType].totalBalance += balance;
coinAnalysis[coinType].objectCount++;
coinAnalysis[coinType].objects.push(coin.objectId);
if (coinType === '0x2::sui::SUI') {
totalSUIBalance += balance;
}
});
// Format balances for display
const formattedBalances = Object.entries(coinAnalysis).map(([coinType, data]) => {
const isStandardCoin = coinType === '0x2::sui::SUI';
const decimals = isStandardCoin ? 9 : 6; // Default assumption
return {
coinType: coinType,
symbol: isStandardCoin ? 'SUI' : coinType.split('::').pop(),
totalBalance: data.totalBalance,
formattedBalance: (data.totalBalance / Math.pow(10, decimals)).toFixed(isStandardCoin ? 4 : 2),
objectCount: data.objectCount
};
});
return {
summary: objects.summary,
coinBalances: formattedBalances,
nftCollection: objects.categories.nfts,
totalSUIBalance: totalSUIBalance,
formattedSUIBalance: (totalSUIBalance / 1_000_000_000).toFixed(4)
};
}
// Monitor object changes
async function monitorObjectChanges(address, callback, intervalMs = 30000) {
let lastObjectCount = 0;
let knownObjects = new Set();
console.log(`Starting object monitoring for ${address}`);
const checkForChanges = async () => {
try {
const result = await client.getOwnedObjects({
owner: address,
options: { showType: true },
limit: 200
});
const currentObjects = new Set(
result.data.map(obj => obj.data?.objectId).filter(Boolean)
);
// Detect new objects
const newObjects = [...currentObjects].filter(id => !knownObjects.has(id));
// Detect removed objects
const removedObjects = [...knownObjects].filter(id => !currentObjects.has(id));
if (newObjects.length > 0 || removedObjects.length > 0) {
callback({
type: 'objects_changed',
newObjects: newObjects,
removedObjects: removedObjects,
totalObjects: currentObjects.size,
timestamp: new Date().toISOString()
});
}
knownObjects = currentObjects;
lastObjectCount = currentObjects.size;
} catch (error) {
console.error('Error monitoring objects:', error);
}
};
// Initial check
await checkForChanges();
// Set up interval monitoring
const intervalId = setInterval(checkForChanges, intervalMs);
return () => {
clearInterval(intervalId);
console.log('Object monitoring stopped');
};
}
// Usage examples
const address = '0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f';
// Basic query
const basicObjects = await getAllOwnedObjects(address);
console.log('Basic objects:', basicObjects.data.length);
// Get SUI coins
const suiCoins = await getSUICoins(address);
console.log('SUI coins:', suiCoins.length);
// Portfolio analysis
const portfolio = await analyzePortfolio(address);
console.log('Portfolio Analysis:', portfolio.summary);
console.log('Total SUI Balance:', portfolio.formattedSUIBalance, 'SUI');
// Monitor changes
const stopMonitoring = await monitorObjectChanges(address, (changes) => {
console.log('📦 Object changes detected:', changes);
});
// Stop monitoring after 10 minutes
setTimeout(stopMonitoring, 10 * 60 * 1000);
import requests
import json
from typing import List, Dict, Any, Optional, Set, Callable
from dataclasses import dataclass
from collections import defaultdict
import time
import asyncio
@dataclass
class ObjectFilter:
struct_type: Optional[str] = None
address_owner: Optional[str] = None
object_owner: Optional[str] = None
object_id: Optional[str] = None
version: Optional[int] = None
@dataclass
class QueryOptions:
show_type: bool = True
show_owner: bool = True
show_previous_transaction: bool = False
show_display: bool = True
show_content: bool = True
show_bcs: bool = False
show_storage_rebate: bool = False
class SuiOwnedObjectsClient:
def __init__(self, rpc_url: str):
self.rpc_url = rpc_url
def get_owned_objects(
self,
owner: str,
query_filter: Optional[ObjectFilter] = None,
options: Optional[QueryOptions] = None,
cursor: Optional[str] = None,
limit: int = 50
) -> Dict[str, Any]:
"""Get objects owned by an address"""
# Build filter
filter_dict = None
if query_filter:
if query_filter.struct_type:
filter_dict = {"StructType": query_filter.struct_type}
elif query_filter.address_owner:
filter_dict = {"AddressOwner": query_filter.address_owner}
elif query_filter.object_owner:
filter_dict = {"ObjectOwner": query_filter.object_owner}
elif query_filter.object_id:
filter_dict = {"ObjectId": query_filter.object_id}
elif query_filter.version:
filter_dict = {"Version": query_filter.version}
# Build options
options_dict = {}
if options:
options_dict = {
"showType": options.show_type,
"showOwner": options.show_owner,
"showPreviousTransaction": options.show_previous_transaction,
"showDisplay": options.show_display,
"showContent": options.show_content,
"showBcs": options.show_bcs,
"showStorageRebate": options.show_storage_rebate
}
# Build query object
query_obj = {}
if filter_dict:
query_obj["filter"] = filter_dict
if options_dict:
query_obj["options"] = options_dict
payload = {
"jsonrpc": "2.0",
"method": "suix_getOwnedObjects",
"params": [owner, query_obj, cursor, limit],
"id": 1
}
response = requests.post(
self.rpc_url,
headers={'Content-Type': 'application/json'},
data=json.dumps(payload)
)
result = response.json()
if 'error' in result:
raise Exception(f"RPC Error: {result['error']}")
return result['result']
def get_all_owned_objects_paginated(
self,
owner: str,
query_filter: Optional[ObjectFilter] = None,
options: Optional[QueryOptions] = None,
max_pages: int = 100
) -> List[Dict[str, Any]]:
"""Get all owned objects using pagination"""
all_objects = []
cursor = None
page = 0
while page < max_pages:
result = self.get_owned_objects(
owner=owner,
query_filter=query_filter,
options=options,
cursor=cursor,
limit=50
)
all_objects.extend(result['data'])
print(f"Page {page + 1}: {len(result['data'])} objects")
if not result['hasNextPage']:
break
cursor = result['nextCursor']
page += 1
print(f"Total objects retrieved: {len(all_objects)}")
return all_objects
def get_sui_coins(self, owner: str) -> List[Dict[str, Any]]:
"""Get all SUI coin objects owned by address"""
sui_filter = ObjectFilter(struct_type="0x2::coin::Coin<0x2::sui::SUI>")
options = QueryOptions(show_content=True, show_type=True)
objects = self.get_all_owned_objects_paginated(
owner=owner,
query_filter=sui_filter,
options=options
)
coins = []
for obj in objects:
if obj.get('data'):
coin_info = {
'object_id': obj['data']['objectId'],
'version': obj['data']['version'],
'balance': obj['data'].get('content', {}).get('fields', {}).get('balance', '0'),
'type': obj['data'].get('type', '')
}
coins.append(coin_info)
return coins
def categorize_owned_objects(self, owner: str) -> Dict[str, Any]:
"""Categorize all owned objects by type"""
options = QueryOptions(
show_type=True,
show_content=True,
show_display=True
)
all_objects = self.get_all_owned_objects_paginated(
owner=owner,
options=options
)
categories = {
'coins': [],
'nfts': [],
'packages': [],
'other': []
}
for obj in all_objects:
if not obj.get('data'):
continue
data = obj['data']
obj_type = data.get('type', '')
if '::coin::Coin<' in obj_type:
# Extract coin type
coin_type_match = obj_type.split('<')
coin_type = coin_type_match[1].rstrip('>') if len(coin_type_match) > 1 else 'Unknown'
coin_info = {
'object_id': data['objectId'],
'coin_type': coin_type,
'balance': data.get('content', {}).get('fields', {}).get('balance', '0'),
'version': data['version']
}
categories['coins'].append(coin_info)
elif '::nft::' in obj_type or data.get('display'):
display_data = data.get('display', {}).get('data', {})
nft_info = {
'object_id': data['objectId'],
'type': obj_type,
'name': display_data.get('name', 'Unknown NFT'),
'description': display_data.get('description', ''),
'image_url': display_data.get('image_url', ''),
'version': data['version']
}
categories['nfts'].append(nft_info)
elif '::package::' in obj_type:
package_info = {
'object_id': data['objectId'],
'type': obj_type,
'version': data['version']
}
categories['packages'].append(package_info)
else:
other_info = {
'object_id': data['objectId'],
'type': obj_type,
'version': data['version']
}
categories['other'].append(other_info)
summary = {
'total_objects': len(all_objects),
'coin_objects': len(categories['coins']),
'nft_objects': len(categories['nfts']),
'package_objects': len(categories['packages']),
'other_objects': len(categories['other'])
}
return {
'summary': summary,
'categories': categories
}
def analyze_portfolio(self, owner: str) -> Dict[str, Any]:
"""Comprehensive portfolio analysis"""
categorized = self.categorize_owned_objects(owner)
# Analyze coin balances
coin_analysis = defaultdict(lambda: {
'total_balance': 0,
'object_count': 0,
'objects': []
})
total_sui_balance = 0
for coin in categorized['categories']['coins']:
coin_type = coin['coin_type']
balance = int(coin['balance'])
coin_analysis[coin_type]['total_balance'] += balance
coin_analysis[coin_type]['object_count'] += 1
coin_analysis[coin_type]['objects'].append(coin['object_id'])
if coin_type == '0x2::sui::SUI':
total_sui_balance += balance
# Format balances for display
formatted_balances = []
for coin_type, data in coin_analysis.items():
is_sui = coin_type == '0x2::sui::SUI'
decimals = 9 if is_sui else 6 # Default assumption
symbol = 'SUI' if is_sui else coin_type.split('::')[-1]
formatted_balances.append({
'coin_type': coin_type,
'symbol': symbol,
'total_balance': data['total_balance'],
'formatted_balance': data['total_balance'] / (10 ** decimals),
'object_count': data['object_count']
})
return {
'summary': categorized['summary'],
'coin_balances': formatted_balances,
'nft_collection': categorized['categories']['nfts'],
'total_sui_balance': total_sui_balance,
'formatted_sui_balance': total_sui_balance / 1_000_000_000
}
def find_objects_by_type(
self,
owner: str,
object_type: str,
include_content: bool = True
) -> List[Dict[str, Any]]:
"""Find all objects of a specific type"""
type_filter = ObjectFilter(struct_type=object_type)
options = QueryOptions(
show_type=True,
show_content=include_content,
show_display=True
)
objects = self.get_all_owned_objects_paginated(
owner=owner,
query_filter=type_filter,
options=options
)
return [obj['data'] for obj in objects if obj.get('data')]
def get_object_history(
self,
owner: str,
object_type: Optional[str] = None,
days_back: int = 30
) -> Dict[str, Any]:
"""Track object ownership changes over time"""
query_filter = ObjectFilter(struct_type=object_type) if object_type else None
options = QueryOptions(
show_type=True,
show_previous_transaction=True,
show_content=True
)
current_objects = self.get_all_owned_objects_paginated(
owner=owner,
query_filter=query_filter,
options=options
)
# Group objects by type for analysis
type_analysis = defaultdict(lambda: {
'count': 0,
'objects': [],
'recent_transactions': set()
})
for obj in current_objects:
if not obj.get('data'):
continue
data = obj['data']
obj_type = data.get('type', 'Unknown')
type_analysis[obj_type]['count'] += 1
type_analysis[obj_type]['objects'].append({
'object_id': data['objectId'],
'version': data['version'],
'previous_transaction': data.get('previousTransaction')
})
if data.get('previousTransaction'):
type_analysis[obj_type]['recent_transactions'].add(
data['previousTransaction']
)
# Convert sets to lists for JSON serialization
for type_info in type_analysis.values():
type_info['recent_transactions'] = list(type_info['recent_transactions'])
return {
'owner': owner,
'total_objects': len(current_objects),
'type_breakdown': dict(type_analysis),
'analysis_timestamp': time.time()
}
def monitor_object_changes(
self,
owner: str,
callback: Callable,
interval_seconds: int = 60,
max_duration_minutes: int = 60
):
"""Monitor for object ownership changes"""
known_objects: Set[str] = set()
start_time = time.time()
max_duration_seconds = max_duration_minutes * 60
print(f"Starting object monitoring for {owner}")
# Initial state
try:
initial_result = self.get_owned_objects(
owner=owner,
options=QueryOptions(show_type=True),
limit=200
)
known_objects = {
obj['data']['objectId']
for obj in initial_result['data']
if obj.get('data')
}
print(f"Initial state: {len(known_objects)} objects")
except Exception as e:
print(f"Error in initial object fetch: {e}")
return
while (time.time() - start_time) < max_duration_seconds:
try:
time.sleep(interval_seconds)
current_result = self.get_owned_objects(
owner=owner,
options=QueryOptions(show_type=True),
limit=200
)
current_objects = {
obj['data']['objectId']
for obj in current_result['data']
if obj.get('data')
}
# Detect changes
new_objects = current_objects - known_objects
removed_objects = known_objects - current_objects
if new_objects or removed_objects:
changes = {
'timestamp': time.time(),
'new_objects': list(new_objects),
'removed_objects': list(removed_objects),
'total_objects': len(current_objects)
}
print(f"📦 Object changes detected: +{len(new_objects)}, -{len(removed_objects)}")
callback(changes)
known_objects = current_objects
except Exception as e:
print(f"Error in object monitoring: {e}")
print("Object monitoring completed")
# Usage examples
client = SuiOwnedObjectsClient('https://sui-mainnet.dwellir.com/YOUR_API_KEY')
# Example 1: Get all owned objects
address = '0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f'
basic_objects = client.get_owned_objects(address)
print(f"Found {len(basic_objects['data'])} objects")
# Example 2: Get SUI coins only
sui_coins = client.get_sui_coins(address)
total_sui = sum(int(coin['balance']) for coin in sui_coins)
print(f"SUI coins: {len(sui_coins)}, Total balance: {total_sui / 1_000_000_000:.4f} SUI")
# Example 3: Portfolio analysis
portfolio = client.analyze_portfolio(address)
print(f"\nPortfolio Summary:")
print(f"Total objects: {portfolio['summary']['total_objects']}")
print(f"Coin objects: {portfolio['summary']['coin_objects']}")
print(f"NFT objects: {portfolio['summary']['nft_objects']}")
print(f"Total SUI balance: {portfolio['formatted_sui_balance']:.4f} SUI")
# Example 4: Find specific object types
nft_objects = client.find_objects_by_type(
address,
"0x2::devnet_nft::DevNetNFT" # Example NFT type
)
print(f"Found {len(nft_objects)} NFT objects")
# Example 5: Monitor object changes
def on_object_change(changes):
print(f"Objects changed at {changes['timestamp']}")
print(f"New objects: {changes['new_objects']}")
print(f"Removed objects: {changes['removed_objects']}")
# Monitor for 5 minutes
client.monitor_object_changes(
address,
on_object_change,
interval_seconds=30,
max_duration_minutes=5
)
Response Example​
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"data": [
{
"data": {
"objectId": "0x5d3c87e88bc566e3f10c66e0275a366001ffa8b86142adc78c744de6afffeb34",
"version": "31823924",
"digest": "HpSeCiMLG53N9FcHDrRTxwGhc4RVJa1seZhXYJ7KFpJe",
"type": "0x2::coin::Coin<0x2::sui::SUI>",
"owner": {
"AddressOwner": "0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f"
},
"previousTransaction": "C2QKmxrYPNBJjNmLtZrzFt9tVfq7wo2JZBmc5nQKYFdt",
"storageRebate": "988000",
"content": {
"dataType": "moveObject",
"type": "0x2::coin::Coin<0x2::sui::SUI>",
"hasPublicTransfer": true,
"fields": {
"balance": "1000000000",
"id": {
"id": "0x5d3c87e88bc566e3f10c66e0275a366001ffa8b86142adc78c744de6afffeb34"
}
}
}
}
},
{
"data": {
"objectId": "0x7f8e9d1a2b3c4e5f6789abcdef0123456789abcdef0123456789abcdef012345",
"version": "15234567",
"digest": "9mNkLp3QrTyU8vWx2ZaB4CdE6fGh1JkL7MnOpQrSt2Uv",
"type": "0x2::devnet_nft::DevNetNFT",
"owner": {
"AddressOwner": "0xd77955e670601c2c2e6e8637e383695c166aac0a86b741c266bdfb23c2e3369f"
},
"previousTransaction": "8X9Y0Z1A2B3C4D5E6F789GHIJK123456789ABCDEF0123456789ABCDEF0123456",
"storageRebate": "1500000",
"display": {
"data": {
"name": "Sui Developer NFT #1234",
"description": "A unique NFT for Sui developers",
"image_url": "https://example.com/nft/1234.png",
"creator": "Sui Foundation"
},
"error": null
},
"content": {
"dataType": "moveObject",
"type": "0x2::devnet_nft::DevNetNFT",
"hasPublicTransfer": true,
"fields": {
"id": {
"id": "0x7f8e9d1a2b3c4e5f6789abcdef0123456789abcdef0123456789abcdef012345"
},
"name": "Sui Developer NFT #1234",
"description": "A unique NFT for Sui developers",
"url": "https://example.com/nft/1234.png"
}
}
}
}
],
"nextCursor": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"hasNextPage": true
}
}
Common Use Cases​
1. Wallet Asset Discovery​
async function buildWalletAssets(address) {
const portfolio = await analyzePortfolio(address);
return {
balances: portfolio.coinBalances.map(coin => ({
symbol: coin.symbol,
balance: coin.formattedBalance,
usdValue: 0, // Would need price feed integration
objectCount: coin.objectCount
})),
collectibles: portfolio.nftCollection.map(nft => ({
name: nft.name,
image: nft.imageUrl,
collection: nft.type.split('::')[0] // Extract package ID
})),
totalAssets: portfolio.summary.totalObjects
};
}
2. Object Type Analytics​
async function analyzeObjectTypes(addresses) {
const typeDistribution = {};
for (const address of addresses) {
const objects = await getAllObjectsPaginated(address);
objects.forEach(obj => {
const type = obj.data?.type || 'Unknown';
typeDistribution[type] = (typeDistribution[type] || 0) + 1;
});
}
return Object.entries(typeDistribution)
.sort(([,a], [,b]) => b - a)
.slice(0, 20); // Top 20 types
}
3. NFT Collection Management​
async function manageNFTCollection(address) {
const categorized = await categorizeOwnedObjects(address);
const nfts = categorized.categories.nfts;
// Group by collection (package)
const collections = {};
nfts.forEach(nft => {
const collection = nft.type.split('::')[0];
if (!collections[collection]) {
collections[collection] = [];
}
collections[collection].push(nft);
});
return Object.entries(collections).map(([packageId, nfts]) => ({
packageId: packageId,
name: nfts[0]?.type.split('::')[1] || 'Unknown Collection',
count: nfts.length,
items: nfts.map(nft => ({
objectId: nft.objectId,
name: nft.name,
image: nft.imageUrl
}))
}));
}
Best Practices​
- Use pagination for addresses with many objects to avoid timeouts
- Filter by type when you only need specific object categories
- Request minimal data by configuring options appropriately
- Cache results for frequently accessed data to improve performance
- Handle empty results gracefully for addresses with no objects
- Monitor changes for real-time applications using periodic polling
Error Handling​
async function safeGetOwnedObjects(address, options = {}) {
try {
const result = await client.getOwnedObjects({
owner: address,
...options
});
return {
success: true,
data: result
};
} catch (error) {
if (error.message.includes('Invalid address')) {
return {
success: false,
error: 'Invalid Sui address format'
};
}
return {
success: false,
error: 'Failed to fetch objects',
details: error.message
};
}
}
Related Methods​
- sui_getObject - Get detailed object information
- suix_getBalance - Query coin balances
- suix_getCoins - Get coin objects with balances
Need help? Contact our support team or check the Sui documentation.