ListOwnedObjects - Discover Address Assets
Query all objects owned by a Sui address via gRPC with pagination support. Essential for wallet interfaces, portfolio tracking, and asset discovery with Dwellir's infrastructure.
Discover All Assets Owned by an Address
The ListOwnedObjects method returns a paginated list of all objects owned by a specific Sui address. This is fundamental for wallet applications, portfolio dashboards, and any interface that needs to display a user's blockchain assets including NFTs, coins, and custom objects.
Overview
Every user on Sui owns a collection of objects—from SUI coins and custom tokens to NFTs and smart contract instances. The ListOwnedObjects method provides efficient enumeration of these assets with built-in pagination for handling large collections. Applications use this to build asset lists, calculate portfolio values, and enable user interactions with their blockchain holdings.
Method Signature
Service: sui.rpc.v2.StateService
Method: ListOwnedObjects
Type: Unary RPC with pagination
Use Cases
1. Wallet Asset Display
Build comprehensive wallet interfaces:
interface WalletAsset {
id: string;
type: string;
category: 'coin' | 'nft' | 'other';
displayName: string;
imageUrl?: string;
value?: string;
}
async function buildWalletView(owner: string): Promise<WalletAsset[]> {
const objects = await fetchAllOwnedObjects(owner);
return objects.map(obj => ({
id: obj.object_id,
type: obj.object_type,
category: categorizeObject(obj),
displayName: extractDisplayName(obj),
imageUrl: extractImage(obj),
value: extractValue(obj)
}));
}
function categorizeObject(obj: any): 'coin' | 'nft' | 'other' {
if (obj.object_type.includes('::coin::Coin')) return 'coin';
if (obj.has_public_transfer) return 'nft';
return 'other';
}2. NFT Gallery
Display user's NFT collection:
interface NFTDisplay {
id: string;
name: string;
image: string;
collection: string;
attributes: Record<string, any>;
}
async function loadNFTGallery(owner: string): Promise<NFTDisplay[]> {
const allObjects = await fetchAllOwnedObjects(owner);
const nfts = allObjects.filter(obj =>
obj.has_public_transfer &&
!obj.object_type.includes('::coin::')
);
return nfts.map(nft => ({
id: nft.object_id,
name: nft.contents?.fields?.name || 'Unnamed',
image: nft.contents?.fields?.url || '',
collection: extractCollection(nft.object_type),
attributes: nft.contents?.fields || {}
}));
}
function extractCollection(objectType: string): string {
const parts = objectType.split('::');
return parts[parts.length - 1];
}3. Portfolio Value Calculation
Calculate total portfolio value:
async function calculatePortfolioValue(owner: string): Promise<number> {
const objects = await fetchAllOwnedObjects(owner);
const coins = objects.filter(obj =>
obj.object_type.includes('::coin::Coin')
);
let totalValue = 0;
for (const coin of coins) {
const coinType = extractCoinType(coin.object_type);
const balance = await getBalance(owner, coinType);
const price = await getCoinPrice(coinType);
totalValue += (parseInt(balance) / 1e9) * price;
}
return totalValue;
}4. Asset Transfer Preparation
Prepare objects for batch transfer:
async function prepareTransferables(owner: string): Promise<string[]> {
const objects = await fetchAllOwnedObjects(owner);
return objects
.filter(obj => obj.has_public_transfer)
.map(obj => obj.object_id);
}Pagination Best Practices
Efficient Pagination
Handle large collections efficiently:
async function* paginatedObjectStream(
owner: string,
pageSize: number = 50
): AsyncGenerator<any[], void, unknown> {
let pageToken: string | undefined = undefined;
do {
const { objects, nextPageToken } = await listOwnedObjects(
owner,
pageSize,
pageToken
);
yield objects;
pageToken = nextPageToken;
} while (pageToken);
}
// Usage
for await (const objectsPage of paginatedObjectStream(userAddress)) {
console.log(`Processing ${objectsPage.length} objects...`);
// Process page
}Progressive Loading
Load assets progressively for better UX:
async function loadAssetsProgressively(
owner: string,
onPageLoaded: (objects: any[], totalSoFar: number) => void
): Promise<any[]> {
const allObjects: any[] = [];
let pageToken: string | undefined = undefined;
do {
const { objects, nextPageToken } = await listOwnedObjects(
owner,
50,
pageToken
);
allObjects.push(...objects);
onPageLoaded(objects, allObjects.length);
pageToken = nextPageToken;
} while (pageToken);
return allObjects;
}
// Usage
await loadAssetsProgressively(userAddress, (page, total) => {
console.log(`Loaded ${page.length} more. Total: ${total}`);
updateUI(page); // Update UI incrementally
});Performance Optimization
Caching Strategy
Cache object lists with TTL:
interface CachedObjectList {
objects: any[];
timestamp: number;
owner: string;
}
const cache = new Map<string, CachedObjectList>();
const CACHE_TTL = 30000; // 30 seconds
async function getCachedOwnedObjects(owner: string): Promise<any[]> {
const cached = cache.get(owner);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
console.log('✓ Using cached data');
return cached.objects;
}
const objects = await fetchAllOwnedObjects(owner);
cache.set(owner, {
objects,
timestamp: Date.now(),
owner
});
return objects;
}Related Methods
- GetObject - Get detailed object information
- BatchGetObjects - Fetch multiple objects
Need help with asset enumeration? Contact support@dwellir.com or check the gRPC overview.
ListDynamicFields
Retrieve dynamic fields attached to Sui objects via gRPC with pagination support. Essential for exploring extensible objects and collections with Dwellir.
SimulateTransaction
Simulate Sui transactions before execution to preview effects, gas costs, and potential errors via gRPC. Essential for safe transaction building with Dwellir.