Docs

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:

TypeScript
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';
}

Display user's NFT collection:

TypeScript
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:

TypeScript
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:

TypeScript
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:

TypeScript
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:

TypeScript
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:

TypeScript
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;
}

Need help with asset enumeration? Contact support@dwellir.com or check the gRPC overview.