Skip to main content
Learn how to efficiently query objects, transactions, events, and other on-chain data.

Querying Objects

Get owned objects

use sui_sdk::SuiClientBuilder;
use sui_sdk::rpc_types::SuiObjectDataOptions;

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    let sui = SuiClientBuilder::default().build_testnet().await?;
    let address = /* your address */;

    let objects = sui
        .read_api()
        .get_owned_objects(
            address,
            None,      // query filter
            None,      // cursor for pagination
            Some(50),  // limit
        )
        .await?;

    for obj in objects.data {
        println!("Object: {:?}", obj);
    }

    Ok(())
}

Get specific object

let object_id: ObjectID = "0x...".parse()?;

let object = sui
    .read_api()
    .get_object_with_options(
        object_id,
        SuiObjectDataOptions {
            show_type: true,
            show_owner: true,
            show_content: true,
            show_display: true,
            show_bcs: true,
            show_storage_rebate: true,
            show_previous_transaction: true,
        },
    )
    .await?;

println!("Object: {:?}", object);

Querying Coins

Get coin balances

let balance = sui
    .coin_read_api()
    .get_balance(address, None) // None = SUI
    .await?;

println!("Balance: {}", balance.total_balance);

// Get all coin types
let all_balances = sui
    .coin_read_api()
    .get_all_balances(address)
    .await?;

for bal in all_balances {
    println!("{}: {}", bal.coin_type, bal.total_balance);
}

Get individual coins

let coins = sui
    .coin_read_api()
    .get_coins(address, None, None, None)
    .await?;

for coin in coins.data {
    println!("Coin {} = {}", coin.coin_object_id, coin.balance);
}

Querying Transactions

Get transaction details

use sui_sdk::rpc_types::SuiTransactionBlockResponseOptions;

let tx = sui
    .read_api()
    .get_transaction_with_options(
        digest,
        SuiTransactionBlockResponseOptions {
            show_input: true,
            show_effects: true,
            show_events: true,
            show_object_changes: true,
            show_balance_changes: true,
            show_raw_input: false,
            show_raw_effects: false,
        },
    )
    .await?;

println!("Transaction: {:?}", tx);

Query transactions

// Get transactions for an address
const txs = await client.queryTransactionBlocks({
  filter: {
    FromAddress: address,
  },
  options: {
    showEffects: true,
  },
  limit: 50,
});

// Get transactions that changed an object
const objTxs = await client.queryTransactionBlocks({
  filter: {
    ChangedObject: objectId,
  },
});

Querying Events

Query by event type

use sui_sdk::rpc_types::EventFilter;

let events = sui
    .event_api()
    .query_events(
        EventFilter::MoveEventType(
            "0x2::coin::Deposit".parse()?
        ),
        None,     // cursor
        Some(50), // limit
        false,    // descending
    )
    .await?;

for event in events.data {
    println!("Event: {:?}", event);
}

Query by sender

let events = sui
    .event_api()
    .query_events(
        EventFilter::Sender(address),
        None,
        Some(100),
        false,
    )
    .await?;

Dynamic Fields

Get dynamic fields

let parent_id: ObjectID = "0x...".parse()?;

let fields = sui
    .read_api()
    .get_dynamic_fields(parent_id, None, None)
    .await?;

for field in fields.data {
    println!("Field: {:?}", field);
    
    // Get field value
    let field_obj = sui
        .read_api()
        .get_dynamic_field_object(parent_id, field.name)
        .await?;
    println!("Value: {:?}", field_obj);
}

Pagination

Paginate through objects

let mut cursor = None;
let mut all_objects = Vec::new();

loop {
    let response = sui
        .read_api()
        .get_owned_objects(address, None, cursor, Some(50))
        .await?;

    all_objects.extend(response.data);

    if !response.has_next_page {
        break;
    }
    cursor = response.next_cursor;
}

println!("Total objects: {}", all_objects.len());

Filtering Objects

Filter by type

const objects = await client.getOwnedObjects({
  owner: address,
  filter: {
    StructType: '0xPACKAGE::module::TypeName',
  },
});

Filter by package

const objects = await client.getOwnedObjects({
  owner: address,
  filter: {
    Package: packageId,
  },
});

Checkpoint Queries

Get latest checkpoint

let latest = sui
    .read_api()
    .get_latest_checkpoint_sequence_number()
    .await?;

println!("Latest checkpoint: {}", latest);

Get checkpoint details

let checkpoint = sui
    .read_api()
    .get_checkpoint(checkpoint_id)
    .await?;

println!("Checkpoint: {:?}", checkpoint);

Protocol Information

Get protocol config

let config = sui
    .read_api()
    .get_protocol_config(None)
    .await?;

println!("Max tx gas: {}", config.max_tx_gas);
println!("Protocol version: {}", config.protocol_version);

Get chain identifier

let chain_id = sui
    .read_api()
    .get_chain_identifier()
    .await?;

println!("Chain ID: {}", chain_id);

Best Practices

1. Use pagination for large datasets

// Good: Paginate
let cursor = null;
while (true) {
  const page = await client.getOwnedObjects({
    owner: address,
    cursor,
    limit: 50,
  });
  // Process page
  if (!page.hasNextPage) break;
  cursor = page.nextCursor;
}

2. Request only needed data

// Good: Only request what you need
const objects = await client.getOwnedObjects({
  owner: address,
  options: {
    showType: true,  // Only type, not full content
  },
});

3. Cache expensive queries

const cache = new Map();

async function getCachedBalance(address: string) {
  if (cache.has(address)) {
    const { balance, timestamp } = cache.get(address);
    if (Date.now() - timestamp < 10000) { // 10s cache
      return balance;
    }
  }

  const balance = await client.getBalance({ owner: address });
  cache.set(address, { balance, timestamp: Date.now() });
  return balance;
}

4. Handle errors gracefully

async function safeGetObject(objectId: string) {
  try {
    return await client.getObject({ id: objectId });
  } catch (error) {
    console.error(`Failed to fetch object ${objectId}:`, error);
    return null;
  }
}

Next Steps

Build docs developers (and LLMs) love